ircu2.10.12 pk910 fork WGN4
authorpk910 <philipp@zoelle1.de>
Tue, 28 Jun 2011 13:17:43 +0000 (15:17 +0200)
committerpk910 <philipp@zoelle1.de>
Tue, 28 Jun 2011 13:17:43 +0000 (15:17 +0200)
351 files changed:
.indent.pro [new file with mode: 0644]
ChangeLog [new file with mode: 0644]
ChangeLog.11 [new file with mode: 0644]
Doxyfile [new file with mode: 0644]
INSTALL [new file with mode: 0644]
INSTALL_FR [new file with mode: 0644]
LICENSE [new file with mode: 0644]
Makefile.in [new file with mode: 0644]
README [new file with mode: 0644]
RELEASE.NOTES [new file with mode: 0644]
acinclude.m4 [new file with mode: 0644]
aclocal.m4 [new file with mode: 0644]
autom4te.cache/output.0 [new file with mode: 0644]
autom4te.cache/output.1 [new file with mode: 0644]
autom4te.cache/requests [new file with mode: 0644]
autom4te.cache/traces.0 [new file with mode: 0644]
autom4te.cache/traces.1 [new file with mode: 0644]
clean [new file with mode: 0644]
config.guess [new file with mode: 0644]
config.h.in [new file with mode: 0644]
config.sub [new file with mode: 0644]
configure [new file with mode: 0644]
configure.in [new file with mode: 0644]
doc/Authors [new file with mode: 0644]
doc/Makefile [new file with mode: 0644]
doc/Makefile.in [new file with mode: 0644]
doc/api/api.txt [new file with mode: 0644]
doc/api/events.txt [new file with mode: 0644]
doc/api/features.txt [new file with mode: 0644]
doc/api/gline.txt [new file with mode: 0644]
doc/api/ircd_snprintf.txt [new file with mode: 0644]
doc/api/joinbuf.txt [new file with mode: 0644]
doc/api/jupe.txt [new file with mode: 0644]
doc/api/log.txt [new file with mode: 0644]
doc/api/modebuf.txt [new file with mode: 0644]
doc/api/motd.txt [new file with mode: 0644]
doc/api/msgq.txt [new file with mode: 0644]
doc/api/privileges.txt [new file with mode: 0644]
doc/api/send.txt [new file with mode: 0644]
doc/debug_memleak_gc.patch [new file with mode: 0644]
doc/example.conf [new file with mode: 0644]
doc/fda.txt [new file with mode: 0644]
doc/features.txt [new file with mode: 0644]
doc/freebsd.txt [new file with mode: 0644]
doc/history/2.4.notes [new file with mode: 0644]
doc/history/2.7-New [new file with mode: 0644]
doc/history/ChangeLog.07 [new file with mode: 0644]
doc/history/ChangeLog.10 [new file with mode: 0644]
doc/history/ChangeLog.11 [new file with mode: 0644]
doc/history/ChangeLog.12 [new file with mode: 0644]
doc/history/Manual [new file with mode: 0644]
doc/history/README-2.6 [new file with mode: 0644]
doc/history/README.patches [new file with mode: 0644]
doc/history/history.pre24 [new file with mode: 0644]
doc/history/overview.u2.9 [new file with mode: 0644]
doc/irc.1 [new file with mode: 0644]
doc/ircd.8 [new file with mode: 0644]
doc/iso-time.html [new file with mode: 0644]
doc/linux-poll.patch [new file with mode: 0644]
doc/p10.html [new file with mode: 0644]
doc/readme.asll [new file with mode: 0644]
doc/readme.chroot [new file with mode: 0644]
doc/readme.crules [new file with mode: 0644]
doc/readme.cvs [new file with mode: 0644]
doc/readme.features [new file with mode: 0644]
doc/readme.gline [new file with mode: 0644]
doc/readme.iauth [new file with mode: 0644]
doc/readme.indent [new file with mode: 0644]
doc/readme.jupe [new file with mode: 0644]
doc/readme.log [new file with mode: 0644]
doc/readme.who [new file with mode: 0644]
doc/readme.www [new file with mode: 0644]
doc/rfc1413.txt [new file with mode: 0644]
doc/rfc1459.unet [new file with mode: 0644]
doc/snomask.html [new file with mode: 0644]
doc/strings.txt [new file with mode: 0644]
include/IPcheck.h [new file with mode: 0644]
include/capab.h [new file with mode: 0644]
include/channel.h [new file with mode: 0644]
include/class.h [new file with mode: 0644]
include/client.h [new file with mode: 0644]
include/crule.h [new file with mode: 0644]
include/dbuf.h [new file with mode: 0644]
include/destruct_event.h [new file with mode: 0644]
include/fileio.h [new file with mode: 0644]
include/gline.h [new file with mode: 0644]
include/handlers.h [new file with mode: 0644]
include/hash.h [new file with mode: 0644]
include/ircd.h [new file with mode: 0644]
include/ircd_alloc.h [new file with mode: 0644]
include/ircd_chattr.h [new file with mode: 0644]
include/ircd_crypt.h [new file with mode: 0644]
include/ircd_crypt_native.h [new file with mode: 0644]
include/ircd_crypt_plain.h [new file with mode: 0644]
include/ircd_crypt_smd5.h [new file with mode: 0644]
include/ircd_defs.h [new file with mode: 0644]
include/ircd_events.h [new file with mode: 0644]
include/ircd_features.h [new file with mode: 0644]
include/ircd_handler.h [new file with mode: 0644]
include/ircd_log.h [new file with mode: 0644]
include/ircd_md5.h [new file with mode: 0644]
include/ircd_osdep.h [new file with mode: 0644]
include/ircd_relay.h [new file with mode: 0644]
include/ircd_reply.h [new file with mode: 0644]
include/ircd_reslib.h [new file with mode: 0644]
include/ircd_signal.h [new file with mode: 0644]
include/ircd_snprintf.h [new file with mode: 0644]
include/ircd_string.h [new file with mode: 0644]
include/jupe.h [new file with mode: 0644]
include/list.h [new file with mode: 0644]
include/listener.h [new file with mode: 0644]
include/match.h [new file with mode: 0644]
include/memdebug.h [new file with mode: 0644]
include/motd.h [new file with mode: 0644]
include/msg.h [new file with mode: 0644]
include/msgq.h [new file with mode: 0644]
include/numeric.h [new file with mode: 0644]
include/numnicks.h [new file with mode: 0644]
include/opercmds.h [new file with mode: 0644]
include/packet.h [new file with mode: 0644]
include/parse.h [new file with mode: 0644]
include/patchlevel.h [new file with mode: 0644]
include/patchlist.h [new file with mode: 0644]
include/querycmds.h [new file with mode: 0644]
include/random.h [new file with mode: 0644]
include/res.h [new file with mode: 0644]
include/s_auth.h [new file with mode: 0644]
include/s_bsd.h [new file with mode: 0644]
include/s_conf.h [new file with mode: 0644]
include/s_debug.h [new file with mode: 0644]
include/s_misc.h [new file with mode: 0644]
include/s_numeric.h [new file with mode: 0644]
include/s_serv.h [new file with mode: 0644]
include/s_stats.h [new file with mode: 0644]
include/s_user.h [new file with mode: 0644]
include/send.h [new file with mode: 0644]
include/ssl.h [new file with mode: 0644]
include/struct.h [new file with mode: 0644]
include/supported.h [new file with mode: 0644]
include/sys.h [new file with mode: 0644]
include/umkpasswd.h [new file with mode: 0644]
include/uping.h [new file with mode: 0644]
include/userload.h [new file with mode: 0644]
include/version.h [new file with mode: 0644]
include/whocmds.h [new file with mode: 0644]
include/whowas.h [new file with mode: 0644]
install-sh [new file with mode: 0644]
ircd-patch [new file with mode: 0644]
ircd/IPcheck.c [new file with mode: 0644]
ircd/Makefile.in [new file with mode: 0644]
ircd/channel.c [new file with mode: 0644]
ircd/chattr.tab.c [new file with mode: 0644]
ircd/class.c [new file with mode: 0644]
ircd/client.c [new file with mode: 0644]
ircd/convert-conf.c [new file with mode: 0644]
ircd/crule.c [new file with mode: 0644]
ircd/dbuf.c [new file with mode: 0644]
ircd/destruct_event.c [new file with mode: 0644]
ircd/engine_devpoll.c [new file with mode: 0644]
ircd/engine_epoll.c [new file with mode: 0644]
ircd/engine_kqueue.c [new file with mode: 0644]
ircd/engine_poll.c [new file with mode: 0644]
ircd/engine_select.c [new file with mode: 0644]
ircd/fileio.c [new file with mode: 0644]
ircd/gline.c [new file with mode: 0644]
ircd/hash.c [new file with mode: 0644]
ircd/ircd.c [new file with mode: 0644]
ircd/ircd_alloc.c [new file with mode: 0644]
ircd/ircd_crypt.c [new file with mode: 0644]
ircd/ircd_crypt_native.c [new file with mode: 0644]
ircd/ircd_crypt_plain.c [new file with mode: 0644]
ircd/ircd_crypt_smd5.c [new file with mode: 0644]
ircd/ircd_events.c [new file with mode: 0644]
ircd/ircd_features.c [new file with mode: 0644]
ircd/ircd_lexer.l [new file with mode: 0644]
ircd/ircd_log.c [new file with mode: 0644]
ircd/ircd_md5.c [new file with mode: 0644]
ircd/ircd_parser.y [new file with mode: 0644]
ircd/ircd_relay.c [new file with mode: 0644]
ircd/ircd_reply.c [new file with mode: 0644]
ircd/ircd_res.c [new file with mode: 0644]
ircd/ircd_reslib.c [new file with mode: 0644]
ircd/ircd_signal.c [new file with mode: 0644]
ircd/ircd_snprintf.c [new file with mode: 0644]
ircd/ircd_string.c [new file with mode: 0644]
ircd/jupe.c [new file with mode: 0644]
ircd/lex.yy.c [new file with mode: 0644]
ircd/list.c [new file with mode: 0644]
ircd/listener.c [new file with mode: 0644]
ircd/m_account.c [new file with mode: 0644]
ircd/m_admin.c [new file with mode: 0644]
ircd/m_asll.c [new file with mode: 0644]
ircd/m_away.c [new file with mode: 0644]
ircd/m_burst.c [new file with mode: 0644]
ircd/m_cap.c [new file with mode: 0644]
ircd/m_check.c [new file with mode: 0644]
ircd/m_clearmode.c [new file with mode: 0644]
ircd/m_close.c [new file with mode: 0644]
ircd/m_connect.c [new file with mode: 0644]
ircd/m_cprivmsg.c [new file with mode: 0644]
ircd/m_create.c [new file with mode: 0644]
ircd/m_defaults.c [new file with mode: 0644]
ircd/m_destruct.c [new file with mode: 0644]
ircd/m_desynch.c [new file with mode: 0644]
ircd/m_die.c [new file with mode: 0644]
ircd/m_endburst.c [new file with mode: 0644]
ircd/m_error.c [new file with mode: 0644]
ircd/m_fakehost.c [new file with mode: 0644]
ircd/m_get.c [new file with mode: 0644]
ircd/m_gline.c [new file with mode: 0644]
ircd/m_help.c [new file with mode: 0644]
ircd/m_hidehost.c [new file with mode: 0644]
ircd/m_info.c [new file with mode: 0644]
ircd/m_invite.c [new file with mode: 0644]
ircd/m_ison.c [new file with mode: 0644]
ircd/m_join.c [new file with mode: 0644]
ircd/m_jupe.c [new file with mode: 0644]
ircd/m_kick.c [new file with mode: 0644]
ircd/m_kill.c [new file with mode: 0644]
ircd/m_links.c [new file with mode: 0644]
ircd/m_list.c [new file with mode: 0644]
ircd/m_lusers.c [new file with mode: 0644]
ircd/m_map.c [new file with mode: 0644]
ircd/m_mode.c [new file with mode: 0644]
ircd/m_motd.c [new file with mode: 0644]
ircd/m_names.c [new file with mode: 0644]
ircd/m_nick.c [new file with mode: 0644]
ircd/m_notice.c [new file with mode: 0644]
ircd/m_oper.c [new file with mode: 0644]
ircd/m_opmode.c [new file with mode: 0644]
ircd/m_part.c [new file with mode: 0644]
ircd/m_pass.c [new file with mode: 0644]
ircd/m_ping.c [new file with mode: 0644]
ircd/m_pong.c [new file with mode: 0644]
ircd/m_privmsg.c [new file with mode: 0644]
ircd/m_privs.c [new file with mode: 0644]
ircd/m_proto.c [new file with mode: 0644]
ircd/m_pseudo.c [new file with mode: 0644]
ircd/m_quit.c [new file with mode: 0644]
ircd/m_rehash.c [new file with mode: 0644]
ircd/m_relay.c [new file with mode: 0644]
ircd/m_reset.c [new file with mode: 0644]
ircd/m_restart.c [new file with mode: 0644]
ircd/m_rping.c [new file with mode: 0644]
ircd/m_rpong.c [new file with mode: 0644]
ircd/m_server.c [new file with mode: 0644]
ircd/m_set.c [new file with mode: 0644]
ircd/m_settime.c [new file with mode: 0644]
ircd/m_silence.c [new file with mode: 0644]
ircd/m_squit.c [new file with mode: 0644]
ircd/m_stats.c [new file with mode: 0644]
ircd/m_svsjoin.c [new file with mode: 0644]
ircd/m_svsmode.c [new file with mode: 0644]
ircd/m_svsnick.c [new file with mode: 0644]
ircd/m_time.c [new file with mode: 0644]
ircd/m_tmpl.c [new file with mode: 0644]
ircd/m_topic.c [new file with mode: 0644]
ircd/m_trace.c [new file with mode: 0644]
ircd/m_uping.c [new file with mode: 0644]
ircd/m_user.c [new file with mode: 0644]
ircd/m_userhost.c [new file with mode: 0644]
ircd/m_userip.c [new file with mode: 0644]
ircd/m_version.c [new file with mode: 0644]
ircd/m_wallchops.c [new file with mode: 0644]
ircd/m_wallops.c [new file with mode: 0644]
ircd/m_wallusers.c [new file with mode: 0644]
ircd/m_wallvoices.c [new file with mode: 0644]
ircd/m_webirc.c [new file with mode: 0644]
ircd/m_who.c [new file with mode: 0644]
ircd/m_whois.c [new file with mode: 0644]
ircd/m_whowas.c [new file with mode: 0644]
ircd/match.c [new file with mode: 0644]
ircd/memdebug.c [new file with mode: 0644]
ircd/motd.c [new file with mode: 0644]
ircd/msgq.c [new file with mode: 0644]
ircd/numnicks.c [new file with mode: 0644]
ircd/opercmds.c [new file with mode: 0644]
ircd/os_generic.c [new file with mode: 0644]
ircd/packet.c [new file with mode: 0644]
ircd/parse.c [new file with mode: 0644]
ircd/querycmds.c [new file with mode: 0644]
ircd/random.c [new file with mode: 0644]
ircd/s_auth.c [new file with mode: 0644]
ircd/s_bsd.c [new file with mode: 0644]
ircd/s_conf.c [new file with mode: 0644]
ircd/s_debug.c [new file with mode: 0644]
ircd/s_err.c [new file with mode: 0644]
ircd/s_misc.c [new file with mode: 0644]
ircd/s_numeric.c [new file with mode: 0644]
ircd/s_serv.c [new file with mode: 0644]
ircd/s_stats.c [new file with mode: 0644]
ircd/s_user.c [new file with mode: 0644]
ircd/send.c [new file with mode: 0644]
ircd/ssl.c [new file with mode: 0644]
ircd/table_gen.c [new file with mode: 0644]
ircd/test/Makefile [new file with mode: 0644]
ircd/test/Makefile.in [new file with mode: 0644]
ircd/test/channel-1.cmd [new file with mode: 0644]
ircd/test/client-1.cmd [new file with mode: 0644]
ircd/test/commands-1.cmd [new file with mode: 0644]
ircd/test/die.cmd [new file with mode: 0644]
ircd/test/feature-1.cmd [new file with mode: 0644]
ircd/test/gline-1.cmd [new file with mode: 0644]
ircd/test/ircd-t1-2.conf [new file with mode: 0644]
ircd/test/ircd-t1.conf [new file with mode: 0644]
ircd/test/ircd-t2.conf [new file with mode: 0644]
ircd/test/ircd_chattr.0.dat [new file with mode: 0644]
ircd/test/ircd_chattr_t.c [new file with mode: 0644]
ircd/test/ircd_in_addr_t.c [new file with mode: 0644]
ircd/test/ircd_match_t.c [new file with mode: 0644]
ircd/test/ircd_string_t.c [new file with mode: 0644]
ircd/test/jupe-1.cmd [new file with mode: 0644]
ircd/test/kill-block-1.cmd [new file with mode: 0644]
ircd/test/run-tests.sh [new file with mode: 0644]
ircd/test/stats-1.cmd [new file with mode: 0644]
ircd/test/test-driver.pl [new file with mode: 0644]
ircd/test/test_stub.c [new file with mode: 0644]
ircd/umkpasswd.c [new file with mode: 0644]
ircd/uping.c [new file with mode: 0644]
ircd/userload.c [new file with mode: 0644]
ircd/version.c [new file with mode: 0644]
ircd/version.c.SH [new file with mode: 0644]
ircd/whocmds.c [new file with mode: 0644]
ircd/whowas.c [new file with mode: 0644]
ircd/y.tab.c [new file with mode: 0644]
ircd/y.tab.h [new file with mode: 0644]
patches/diffs/lazy.diff [new file with mode: 0644]
patches/diffs/login-on-connect.diff [new file with mode: 0644]
patches/diffs/sline.diff [new file with mode: 0644]
stamp-h.in [new file with mode: 0644]
tests/bug-1640796.cmd [new file with mode: 0644]
tests/bug-1674539.cmd [new file with mode: 0644]
tests/ircd-2.conf [new file with mode: 0644]
tests/ircd-3.conf [new file with mode: 0644]
tests/ircd.conf [new file with mode: 0644]
tests/readme.txt [new file with mode: 0644]
tests/test-driver.pl [new file with mode: 0644]
tools/Bounce/Bounce.cpp [new file with mode: 0644]
tools/Bounce/Bounce.h [new file with mode: 0644]
tools/Bounce/bounce.conf [new file with mode: 0644]
tools/Bounce/build [new file with mode: 0644]
tools/autodoc.py [new file with mode: 0644]
tools/hashtoy [new file with mode: 0644]
tools/iauth-test [new file with mode: 0644]
tools/linesync/linesync.conf [new file with mode: 0644]
tools/linesync/linesync.sh [new file with mode: 0644]
tools/mkchroot [new file with mode: 0644]
tools/ringlog.c [new file with mode: 0644]
tools/ringlog.pl [new file with mode: 0644]
tools/untabify [new file with mode: 0644]
tools/wrapper.c [new file with mode: 0644]

diff --git a/.indent.pro b/.indent.pro
new file mode 100644 (file)
index 0000000..84ea6ad
--- /dev/null
@@ -0,0 +1,50 @@
+--leave-preprocessor-space
+--dont-break-procedure-type
+--no-space-after-function-call-names
+--brace-indent0
+--indent-level2
+--dont-line-up-parentheses
+--continuation-indentation4
+--case-indentation2
+--no-space-after-casts
+--blank-lines-after-procedures
+--no-blank-lines-after-declarations
+--braces-on-struct-decl-line
+--paren-indentation0
+--case-brace-indentation0
+--line-length80
+--declaration-indentation4
+-T size_t
+-T aClass
+-T aClient
+-T aServer
+-T anUser
+-T aChannel
+-T Mode
+-T aConfItem
+-T aMessage
+-T aMessageTree
+-T aGline
+-T aListingArgs
+-T snomask_t
+-T n_short
+-T n_long
+-T n_time
+-T u_char
+-T u_short
+-T u_long
+-T u_int
+-T dbuf
+-T dbufbuf
+-T aHashEntry
+-T Link
+-T Dlink
+-T VOIDSIG
+-T aHostent
+-T ResRQ
+-T aCache
+-T CacheTable
+-T cainfo
+-T reinfo
+-T RETSIGTYPE
+-T OPT_TYPE
diff --git a/ChangeLog b/ChangeLog
new file mode 100644 (file)
index 0000000..49c5f51
--- /dev/null
+++ b/ChangeLog
@@ -0,0 +1,10675 @@
+2007-03-09  Michael Poole <mdpoole@troilus.org>
+
+       * include/patchlevel.h (PATCHLEVEL): Bump for u2.10.12.10 release.
+
+2007-03-05  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/m_privs.c (ms_privs): Use the correct source when
+       forwarding the PRIVS request.
+
+       * tests/bug-1674539.cmd: New file to test for this.
+
+       * tests/test-driver.pl: Recognize "oper" command from scripts.
+
+2007-03-05  Michael Poole <mdpoole@troilus.org>
+
+       * tests/ircd.conf: Make into a hub.
+
+       * tests/ircd-2.conf: New file, for a second server.
+
+       * tests/ircd-3.conf: Configuration for a third server.
+
+2007-03-04  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/whocmds.c (count_users): Fix length of ipbuf.  (Spotted by
+       paulr.)
+
+2007-02-28  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/os_generic.c (sockaddr_from_irc): Zero out socket address
+       before setting family, and regardless of whether we have an
+       irc_sockaddr template.
+
+2007-02-25  Michael Poole <mdpoole@troilus.org>
+
+       * doc/example.conf: Document new options for General block.
+       
+       * include/res.h (clear_nameservers): Declare new function.
+       (add_nameserver): Declare previously static function.
+
+       * include/s_bsd.h (VirtualHost_dns_v4): Declare.
+       (VirtualHost_dns_v6): Likewise.
+
+       * ircd/ircd_lexer.l (DNS): Recognize new token.
+
+       * ircd/ircd_parser.y (DNS): Declare new token.
+       (generalitem): Allow new items for dns vhost(s) and dns servers.
+       (generaldnsvhost): New production.
+       (generaldnsserver): New production.
+
+       * ircd/ircd_res.c (VirtualHost_dns_v4): New variable.
+       (VirtualHost_dns_v6): Likewise.
+       (clear_nameservers): New function.
+       (restart_resolver): Scan specified servers so we only try to open
+       DNS client sockets that we need.
+
+       * ircd/ircd_reslib.c (irc_nscount): Remove redundant initializer.
+       (irc_res_init): Only read the resolver config file if there are no
+       nameservers provided.
+       (add_nameserver): Make non-static.  Remove off-by-one check
+       against IRCD_MAXNS.
+
+       * ircd/s_conf.c (read_configuration_file): Clear nameserver list
+       before reading the config file.
+
+2007-01-27  Jeannot Langlois <jeannot12@linuxmail.org>
+
+       * doc/example.conf (Features): Illustrate URLREG feature.
+
+       * doc/readme.features (URLREG): Define new feature.
+
+       * include/ircd_features.h (Feature): Add FEAT_URLREG.
+
+       * ircd/ircd_features.c (features): Set the default value.
+
+       * ircd/m_join.c (m_join): For ERR_NEEDREGGEDNICK, include the
+       URLREG value as a format argument.
+
+       * ircd/s_err.c (replyTable): Update ERR_NEEDREGGEDNICK
+       appropriately.
+
+2007-02-03  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/ircd_reply.c (protocol_violation): Avoid reusing the
+       va_list in vd.
+
+       * ircd/send.c (sendcmdto_channel_butone): Warn against using %v in
+       the pattern -- that will cause incorrect behavior.
+       (sendwallto_group_butone): Likewise.
+       (sendcmdto_match_butone): Likewise.
+
+2007-01-22  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/channel.c (find_delayed_joins): New function.
+       (modebuf_flush): Handle +D-D and related cases.
+       (mode_parse_mode): It is too early to handle +D here, so don't.
+       (CheckDelayedJoins): Use find_delayed_joins().
+
+2007-01-22  Michael Poole <mdpoole@troilus.org>
+
+       * tests: New subdirectory for test framework.
+
+       * tests/ircd.conf: Helper file for testing.
+
+       * tests/readme.txt: Simple documentation of test framework.
+
+       * tests/test-driver.pl: Testing script interpreter.
+
+2007-01-22  Michael Poole <mdpoole@troilus.org>
+
+       * doc/example.conf: Fix potentially confusing comment about ip
+       mask syntax.
+
+2007-01-22  Michael Poole <mdpoole@troilus.org>
+
+       * INSTALL: Mention source directory naming; update the reference
+       to the config file converter (hah); update CVS directions.
+
+2007-01-22  Michael Poole <mdpoole@troilus.org>
+
+       * include/supported.h: Move parameters from FEATURES1 to FEATURES2
+       so that neither ISUPPORT line has more than 15 parameters.  (Some
+       clients are picky about this.)
+
+2007-01-21  Michael Poole <mdpoole@troilus.org>
+
+       * include/patchlevel.h (PATCHLEVEL): Bump for pre10 development.
+
+2007-01-20  Michael Poole <mdpoole@troilus.org>
+
+       * include/patchlevel.h (PATCHLEVEL): Bump for 2.10.12.09 release.
+
+2007-01-15  Michael Poole <mdpoole@troilus.org>
+
+       * doc/readme.iauth (U): Document extended fields.
+
+       * include/s_auth.h (auth_set_user): Declare new parameters.
+
+       * ircd/m_user.c (m_user): Pass new parameters.
+
+       * ircd/s_auth.c (auth_set_user): Accept new parameters.  When
+       using Undernet extensions, forward them to the iauth process.
+
+2007-01-14  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/os_generic.c (os_recv_nonb): Set errno to zero when
+       returning IO_FAILURE due to a closed connection.
+
+2006-12-31  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/m_mode.c (ms_mode): Bounce modes from deopped members.
+
+2006-12-30  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/ircd_string.c (ircd_strncpy): Make sure the output buffer
+       is terminated.  We don't rely on the arguable strncpy semantics.
+
+2006-12-30  Michael Poole <mdpoole@troilus.org>
+
+       * include/struct.h (struct Server): Add asll_last field.
+
+       * ircd/ircd.c (check_pings): Add check for asll_last.  When a
+       server doesn't ping, use an old-style ping rather than AsLL ping.
+
+       * ircd/m_pong.c (ms_pong): Use ClearPingSent() rather than
+       ClrFlag().  Set asll_last to current time.
+       (mr_pong): Use ClearPingSent() rather than ClrFlag().
+       (m_pong): Likewise.
+
+       * ircd/s_bsd.c (completed_connection): Likewise.
+       (read_packet): Likewise.  Update cli_lasttime for servers in
+       addition to clients.
+
+2006-01-13  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/m_burst.c (ms_burst): Properly handle member mode :ov.
+
+2006-01-13  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/m_create.c (ms_create): Add channel name to the protocol
+       violation notice for a redundant CREATE.
+
+2006-01-13  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/s_user.c (set_nick_name): Use user's account name rather
+       than the account parameter, in case the parameter contains a colon
+       (i.e. "account:1234" format).
+
+2006-01-13  Michael Poole <mdpoole@troilus.org>
+
+       * doc/readme.who: Document 'd' user-matching flag.
+
+2006-12-18  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/m_jupe.c (mo_jupe): Fix which privilege is tested.
+
+2006-12-07  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/listener.c (show_ports): Update to show '4' and/or '6' as
+       flags in response, with a '-' suffix if either one fails to open.
+
+2006-12-07  Michael Poole <mdpoole@troilus.org>
+
+       * doc/example.conf (Port): Document the method to select IPv4 or
+       IPv6 restriction for a port.
+
+       * include/listener.h (LISTEN_IPV4): New listener flag.
+       (LISTEN_IPV6): New listener flag.
+       (struct Listener): Split 'fd' and 'socket' fields into two each.
+
+       * ircd/ircd_lexer.l (gb): Move to be alphabetical.
+       (gigabytes): Likewise.
+       (ipv4): New token.
+       (ipv6): Likewise.
+       Adapted word matcher to handle digits in the non-leading character.
+
+       * ircd/ircd_parser.y (USE_IPV4): New macro.
+       (USE_IPV6): Likewise.
+       (TOK_IPV4): New token.
+       (TOK_IPV6): Likewise.
+       (address_family): New non-terminal rule.
+       (portblock): Default to listening on both IPv4 and IPv6.
+       (portnumber): Add address_family element and use it.
+       (portvhost): Likewise.
+
+       * ircd/listener.c (make_listener): Adjust for newly split fields
+       in struct Listener.
+       (inetport): Likewise.  Adjust return value as well.
+       (add_listener): Update to handle both IPv4 and IPV6 support.
+       (close_listener): Likewise.
+       (accept_connection): Because each listener has two sockets, it is
+       no longer safe to free the listener when one is destroyed -- so
+       don't.  Also accept() on the file descriptor from the incoming
+       event rather than on a fixed fd.
+
+       * ircd/os_generic.c (os_socket): For platforms with IPV6_V6ONLY,
+       enable it for AF_INET6 sockets rather than disabling it for
+       unspecified sockets.
+
+2006-12-06  Michael Poole <mdpoole@troilus.org>
+
+       * include/listener.h (enum ListenerFlag): New enum.
+       (struct Listener): Convert "active", "hidden" and "server" to a
+       flagset.
+       (add_listener): Convert "is_server" and "is_hidden" arguments to
+       use the same flagset structure.
+
+       * ircd/ircd_parser.y (listen_flags): New variable.
+       (general_vhost): Consolidate references to $3 to use a variable.
+       (portblock): Use listen_flags instead of tconn and tping.
+       (portserver): Likewise.
+       (porthidden): Likewise.
+
+       * ircd/listener.c (show_ports): Use new field in Listener.
+       (set_listener_options): New function.
+       (inetport): Use it.
+       (add_listener): Use new field in Listener.  When reusing an extant
+       listener, call set_listener_options() so the options are updated.
+       (mark_listeners_closing): Use new field in Listener.
+       (close_listeners): Use new helper macro to check activeness.
+       (release_listener): Likewise.
+       (accept_connection): Likewise.
+
+       * ircd/s_bsd.c (report_error): Use the standard snotice rate
+       limiting here.
+       (add_connection): Use new helper macro to check serverness.
+
+2006-11-04  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/m_nick.c (m_nick): If we get NICK on a server port, tell
+       the client to go away.
+
+2006-11-04  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/version.c.SH: Skip version.c.
+
+2006-11-04  Michael Poole <mdpoole@troilus.org>
+
+       * doc/readme.who: Document new 'o' field flag.
+
+       * include/whocmds.h (WHO_FIELD_OPL): New flag.
+
+       * ircd/channel.c (send_channel_modes): Rename feat_oplevels to
+       send_oplevels and determine it automatically.
+       (modebuf_flush_int): Pass along oplevel if it's less than
+       MAXOPLEVEL.
+       (mode_process_clients): Allow oplevels to be inherited for -A
+       channels.  Inherit the opper's oplevel if >= MAXOPLEVEL.
+
+       * ircd/m_who.c (m_who): Recognize 'o' flag as WHO_FIELD_OPL.
+
+       * ircd/whocmds.c (do_who): Send oplevel for WHO_FIELD_OPL, but
+       only show up to the requester's own oplevel.
+
+2006-10-21  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/convert-conf.c (finish_connects): Fix error display for
+       missing C: lines when an H: line is present.
+
+2006-08-02  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/ircd_parser.y (connectblock): Check for too-long password.
+       (operblock): Comment why we don't check password length.  Move
+       PRIV_PROPAGATE test earlier (so a buggy edit, rehash, /oper will
+       not crash).
+       (clientblock): Check for too-long password.
+
+2006-08-02  Michael Poole <mdpoole@troilus.org>
+
+       * include/channel.h (struct Ban): Fix typo in doxygen comment.
+
+2006-07-09  Michael Poole <mdpoole@troilus.org>
+
+       * include/patchlevel.h (PATCHLEVEL): Bump for pre09.
+
+2006-07-09  Michael Poole <mdpoole@troilus.org>
+
+       * include/patchlevel.h (PATCHLEVEL): Bump for 2.10.12.08 release.
+
+2006-07-05  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/s_auth.c (auth_freelist): New static variable.
+       (check_auth_finished): Move call to destroy_auth_request().
+       (destroy_auth_request): Prepend auth request to freelist.
+       (start_auth): Use struct from auth freelist if possible.
+
+2006-06-30  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/ircd_parser.y (iauth*): Avoid leaking program name string.
+
+2006-06-30  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/s_auth.c (check_auth_finished): Free auth structure when
+       done with it.
+       (sendto_iauth): Free message buffer when done with it.
+
+2006-06-26  Michael Poole <mdpoole@troilus.org>
+
+       * include/patchlevel.h (PATCHLEVEL): Bump for pre08.
+
+2006-06-26  Michael Poole <mdpoole@troilus.org>
+
+       * include/patchlevel.h (PATCHEVEL): Bump for release.
+
+2006-06-17  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/m_pass.c (mr_pass): Only back 'len' up when it's safe.
+
+2006-06-08  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/m_whois.c (do_whois): Prefix '*' to names of secret (local)
+       channels for locops as well as global opers.
+
+2006-06-08  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/m_gline.c (ms_gline): Use final argument as G-line reason.
+
+2006-06-08  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/gline.c (gline_stats): Show activation state in /stats g.
+
+       * ircd/s_err.c (RPL_STATSGLINE): Update format string to match.
+
+2006-06-07  Michael Poole <mdpoole@troilus.org>
+
+       * doc/example.conf: Document the list_chan privilege.
+
+       * ircd/ircd_lexer.l: Recognize the token.
+
+       * ircd/ircd_parser.y: Treat it appropriately.
+
+2006-06-07  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/s_auth.c (auth_ping_timeout): If the client never had an
+       auth request, kill them on ping timeout.
+
+2006-06-05  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/s_auth.c (auth_timeout_callback): Clear AR_DNS_PENDING when
+       destroying the lookup and reporting DNS failure.
+
+2006-05-28  Michael Poole <mdpoole@troilus.org>
+
+       * doc/readme.features (MAXBANS): Update default value.
+       (NICKLEN): Likewise.
+       (HIS_STATS_*): Sort alphabetically.
+
+       * ircd/m_stats.c (m_stats): Describe the intention so that there
+       are not further questions about local opers and remote /stats.
+       Fix places that use cptr instead of sptr.
+
+2006-05-24  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/s_auth.c (auth_dns_callback): Be more careful about
+       handling failed DNS lookups.  Use a more standard function to
+       disconnect clients for IP mismatches.
+       (start_auth): Use a more standard function to disconnect clients
+       for peer or local socket address lookup failures.
+
+2006-05-17  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/s_auth.c (auth_ping_timeout): Fix off-by-one error.
+
+2006-05-17  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/Makefile.in (install-*): Install convert-conf.  Install
+       umkpasswd when ${BINDIR}/ircd is not a symlink.
+
+2006-05-15  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/s_auth.c (check_auth_finished): Only check passwords on
+       user ports.
+
+2006-05-14  Michael Poole <mdpoole@troilus.org>
+
+       * doc/example.conf (Connect): Mention the vhost option.
+
+2006-05-08  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/m_pong.c (mr_pong): Move cli_lasttime update from here...
+
+       * ircd/s_auth.c (auth_set_pong): ... to here.
+
+2006-05-07  Michael Poole <mdpoole@troilus.org>
+
+       * include/s_auth.h (auth_ping_timeout): Declare new function.
+
+       * ircd/ircd.c (check_pings): Move auth timeout logic into that new
+       function.
+
+       * ircd/s_auth.c (HeaderMessages): Insert new message.
+       (auth_ping_timeout): Define new function.
+       (auth_timeout_callback): Remove "hurry" notification from here.
+
+2006-05-07  Michael Poole <mdpoole@troilus.org>
+
+       * include/s_auth.h (destroy_auth_request): Remove second argument.
+
+       * ircd/list.c (free_client): Update to match.
+
+       * ircd/s_auth.c (check_auth_finished): Remove second argument and
+       update call to destroy_auth_request().
+       (send_auth_query): Update call to destroy_auth_request().
+       (destroy_auth_request): Remove second argument.
+       (auth_timeout_callback): Send timeout failure messages here
+       instead.  Update call to check_auth_finished().
+       (auth_dns_callback): Update call to check_auth_finished().
+       (start_auth): Likewise.
+       (auth_set_pong): Likewise.
+       (auth_set_user): Likewise.
+       (auth_set_nick): Likewise.
+       (auth_cap_done): Likewise.
+       (iauth_parse): Likewise.
+
+2006-05-06  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/s_auth.c (AuthRequestFlag): Add AR_PASSWORD_CHECKED.
+       (check_auth_finished): Move password check out of iauth-only part
+       and use AR_PASSWORD_CHECKED to make sure we only check it once.
+
+2006-04-28  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/s_auth.c (AuthRequest): Clarify comment on 'timeout' field.
+       (check_auth_finished): Fix timeout update.
+       (destroy_auth_request): Only delete timer if it is active.
+       (auth_timeout_callback): Do not disconnect client on timeout, so
+       that the user can finish sending NICK/USER or doing iauth.
+
+2006-04-28  Michael Poole <mdpoole@troilus.org>
+
+       * doc/example.conf (Admin): Fix documentation of which line can be
+       listed twice.
+
+       * ircd/ircd_parser.y (adminblock): Allow admin information to be
+       changed via /rehash.
+
+2006-04-06  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/s_auth.c (start_auth): Add client to list after getting
+       endpoint names (which can apparently fail for some reason).
+
+2006-04-06  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/ircd_snprintf.c: Use SIZEOF_LONG_LONG (which is 0 for
+       unknown types) instead of the never-defined HAVE_LONG_LONG.
+
+2006-04-06  Michael Poole <mdpoole@troilus.org>
+
+       * doc/example.conf (IAuth): Update to reflect new syntax.
+
+       * doc/readme.who: Fix typo in metasyntactic variable name.
+
+2006-04-04  Michael Poole <mdpoole@troilus.org>
+
+       * include/patchlevel.h: Update for pre07.
+
+2006-04-04  Michael Poole <mdpoole@troilus.org>
+
+       * include/patchlevel.h: Update for u2.10.12.06 release.
+
+2006-04-03  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/channel.c (bmatch): If ipmask_check() indicates old_ban is
+       a CIDR-wise superset of new_ban, check whether new_ban is a
+       text-wise superset of old_ban.
+
+2006-03-31  Michael Poole <mdpoole@troilus.org>
+
+       * tools/iauth-test (send_server_notice): Use a colon prefix before
+       the message.
+       (%handlers): Likewise.
+
+2006-03-24  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/ircd_signal.c (alloc_crec): Zero-fill returned
+       ChildRecord structs.
+
+       * ircd/jupe.c (make_jupe): Zero-fill newly allocated jupes.
+
+       * ircd/list.c (make_link): Zero-fill returned SLink structs.
+
+       * ircd/whowas.c (whowas_init): Delete function.
+       (whowas_alloc): Rewrite to follow the more common pattern and to
+       zero-fill returned Whowas structs.
+
+2006-03-23  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/s_auth.c: rewrite iauth_read(), spliting out the parsing
+       into iauth_parse(); change parsing to separate parameters and deal
+       with the ':' sentinel; send sentinel in multi-word parameters; fix
+       iauth_cmd_config() and iauth_cmd_stats() to clear the 'next'
+       pointer in the SLink structure; fix buffering in
+       iauth_read_stderr(); remove carriage returns from STDERR contents
+       as well
+
+       * doc/readme.iauth: fix a minor typo in comments for 'd' and 'N'
+       server messages
+
+2006-03-18  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/convert-conf.c (finish_features): Do not emit a feature
+       setting that has no values.
+
+2006-03-18  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/channel.c (mode_parse_key): Outside of burst, allow
+       overwriting of keys by a service when a key is already set.
+       (mode_parse_upass): Likewise.  Instead, ignore new Upass during
+       burst if it is lexicographically greater than the current one.
+       (mode_parse_apas): Likewise for Apass, but only allow overwiting
+       an existing Apass in a BURST.
+
+2006-03-18  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/channel.c (modebuf_flush_int): Fix typo about changing
+       oplevels.  Send correct channel TS for modes to other servers.
+       (mode_parse): Accept timestamps on modes from users on other
+       servers.  If the received timestamp is too large, handle that.
+
+       * ircd/m_create.c (ms_create): Mention the CREATE-during-burst
+       case and handle it.
+
+       * ircd/m_mode.c (ms_mode): Put back HACK(3) when oplevels are off.
+
+2006-03-14  Wouter Coekarts <wouter@coekaerts.be>
+
+       * ircd/s_err.c (RPL_STATSILINE): Add two %s to the first field.
+
+       * ircd/s_stats.c (stats_configured_links): Use the new %s's to
+       show username masks for I: lines that have them.
+       (stats_access): Likewise.
+
+2006-03-13  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/msgq.c (msgq_vmake): Try to clear msgbuf freelist after
+       killing clients, so that that case does not lead immediately to a
+       server panic.
+       (msgq_count_memory): Report total buffer text used as a way to
+       determine whether the BUFFERPOOL value is marginal.
+
+2006-03-02  Michael Poole <mdpoole@troilus.org>
+
+       * include/ircd_osdep.h (os_socket): New parameter.
+
+       * include/res.h (irc_in_addr_unspec): New macro.
+
+       * ircd/ircd_res.c (restart_resolver): Set family appropriately.
+
+       * ircd/listener.c (inetport): Let os_ library pick socket family.
+
+       * ircd/os_generic.c: Do not #define _XOPEN_SOURCE on FreeBSD 5+.
+       (sockaddr_from_irc): New parameter.
+       (os_sendto_nonb): Use new parameter to sockaddr_from_irc().
+       (os_socket): New parameter.  Try to turn off IPV6_V6ONLY on
+       sockets that listen on unspecified addresses.
+       (os_connect_nonb): Use new parameter to sockaddr_from_irc().
+
+       * ircd/s_auth.c (start_auth_query): Let os_ library pick socket
+       family.
+
+       * ircd/s_bsd.c (connect_inet): If we pick the IPv4 vhost, specify
+       family for os_socket() as AF_INET.
+
+       * ircd/uping.c (uping_init): Set socket family appropriately.
+       (uping_server): Likewise.
+       (uping_end): Fix format strings (the ms_* fields are int, not
+       long, and this causes bad results on LP64 machines).
+
+2006-02-22  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/m_silence.c (apply_silence): Refuse to apply silences for
+       local users that are broader than an IPv4 /16 or an IPv6 /32,
+       unless they match every host indiscriminately.
+
+2006-02-22  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/s_auth.c (check_auth_finished): Give non-iauth clients
+       connection classes, too.
+       (auth_close_unused): Remove redundant check for iauth != NULL.
+       (report_iauth_conf): Check iauth != NULL before deref'ing it.
+       (report_iauth_stats): Likewise.
+
+2006-02-22  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/s_auth.c: fix macros to not dereference a NULL pointer when
+       iauth is not connected
+
+2006-02-17  Alex Badea <vamposdecampos@gmail.com>
+
+       * ircd/s_auth.c (auth_set_username): Check if the last
+       character of the username is alphanumeric, instead of the
+       '\0' terminator.
+       
+       * ircd/m_pong.c (mr_pong): Parse cookie with strtoul(),
+       since atol() causes signedness problems.
+
+2006-02-15  Michael Poole <mdpoole@troilus.org>
+
+       * include/res.h (NXDOMAIN): Define.
+
+       * ircd/ircd_res.c (res_readreply): Treat NXDOMAIN just like
+       SERVFAIL.  Patch courtesy of Dianora.
+
+       * tools/iauth-test (Carp): This doesn't actually use Carp.
+
+2006-02-15  Michael Poole <mdpoole@troilus.org>
+
+       * doc/example.conf: Include new HIS_STATS_IAUTH feature.
+
+       * doc/readme.features: Document the feature.
+
+       * doc/readme.iauth: Rewrite to reflect the new progressive iauth
+       protocol, based on IRCnet's iauth.
+
+       * doc/snomask.html: Document SNO_AUTH server notice flag.
+
+       * include/client.h (FLAG_IAUTHED): Delete.
+       (con_cookie): Delete.
+       (con_unreg): Delete.
+       (con_auth): Make comment capitalization consistent.
+       (con_iauth): Delete.
+       (CLIREG_*): Delete.
+       (cli_unreg): Delete.
+       (cli_cookie): Delete.
+       (cli_iauth): Delete.
+       (con_unreg): Delete.
+       (con_iauth): Delete.
+       (IsIAuthed): Delete.
+       (SetIAuthed): Delete.
+       (SNO_AUTH): New server notice flag.
+       (SNO_ALL): Update to include SNO_AUTH.
+       (SNO_OPER): Update to include SNO_AUTH.
+
+       * include/ircd_auth.h: Delete file.
+
+       * include/ircd_features.h (HIS_STATS_IAUTH): New feature.
+
+       * include/s_auth.h: Rewrite almost everything for new auth system.
+
+       * include/s_user.h (COOKIE_VERIFIED): Delete.
+       (register_user): Remove redundant nick and username arguments.
+
+       * ircd/ircd_auth.c: Delete file.
+
+       * ircd/ircd_features.c (HIS_STATS_IAUTH): New feature.
+
+       * ircd/ircd_lexer.l (PROGRAM): New token in grammar.
+
+       * ircd/ircd_log.c (masks): Add SNO_AUTH flag.
+
+       * ircd/ircd_parser.y (stringlist): Simplify production.
+       (iauthblock): Revise to only include a PROGRAM production.
+
+       * ircd/list.c (make_client): Do not assign to deleted field.
+
+       * ircd/m_cap.c (cap_ls): Use auth_cap_start() instead of
+       cli_unreg().
+       (cap_req): Likewise.
+       (cap_end): Use auth_cap_done() instead of cli_unreg().
+
+       * ircd/m_pass.c (mr_pass): Merge arguments to PASS.  Use
+       auth_set_password() to notify iauth of password.
+
+       * ircd/m_pong.c (mr_pong): Use auth_set_pong() instead of
+       cli_cookie() and cli_unreg().
+
+       * ircd/m_user.c (m_user): Use auth_set_user() instead of
+       cli_unreg(), etc.
+
+       * ircd/s_auth.c: Rewrite most of the infrastructure for the new
+       auth system.
+
+       * ircd/s_conf.c (rehash): Call auth_*() instead of iauth_*().
+
+       * ircd/s_misc.c (exit_one_client): Do not use iauth_exit_client().
+       (exit_client): Use auth_send_exit() instead.
+
+       * ircd/s_stats.c (statsinfo): Include iauth and iauthconf.
+
+       * ircd/s_user.c (clean_user_id): Delete (moved into s_auth.c).
+       (register_user): Remove nick and username parameters; move conf
+       interactions and username validation to s_auth.c.
+       (set_nick_name): Use auth_set_nick() instead of cli_cookie(),
+       cli_unreg(), etc.
+
+       * tools/iauth-test: Implementation of iauth for testing purposes.
+
+2006-02-15  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/ircd_snprintf.c (doprintf): Fix typecast for %hu.
+
+2006-02-15  Michael Poole <mdpoole@troilus.org>
+
+       * include/ircd_signal.h (SigChldCallBack): New typedef.
+       (register_child): Declare.
+       (unregister_child): Declare.
+       (reap_children): Declare.
+
+       * ircd/ircd_signal.c (alloc_crec): New function.
+       (release_crec): New function.
+       (register_child): New function.
+       (do_unregister_child): New function.
+       (unregister_child): New function.
+       (sigchld_callback): New function.
+       (setup_signals): Hook SIGCHLD.
+       (reap_children): New function.
+
+       * ircd/ircd.c (server_restart): Call reap_children() on exit.
+
+2006-02-15  Michael Poole <mdpoole@troilus.org>
+
+       * include/ircd_osdep.h (os_socketpair): Declare.
+
+       * ircd/os_generic.c (is_blocked): New local function.
+       (os_*): Use is_blocked() instead of cut-and-pasted code.
+       (os_socketpair): New function.
+
+2006-02-15  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/match.c (match): Fix backtracking bug after an escape
+       (reported by Michael, I think).
+
+2006-02-04  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/ircd.c (try_connections): Scan all Connect blocks for the
+       earliest hold time (suggested by Michael).
+
+2006-02-04  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/m_join.c (m_join): Remove #if 0 code and update comment.
+
+       * ircd/m_mode.c (ms_mode): Remove self-op support.
+
+2006-01-12  Michael Poole <mdpoole@troilus.org>
+
+       * include/patchlevel.h (PATCHLEVEL): Update for 2.10.12.pre06.
+
+2006-01-12  Michael Poole <mdpoole@troilus.org>
+
+       * include/patchlevel.h (PATCHLEVEL): Update for release.
+
+2006-01-11  Michael Poole <mdpoole@troilus.org>
+
+       * doc/Makefile.in: Make install target VPATH-safe.
+
+       * doc/example.conf: Comment out example IAuth block.
+
+       * ircd/m_burst.c (ms_burst): Change isdigit() to IsDigit(),
+       silencing a warning on Solaris.
+
+2006-01-09  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/s_user.c (register_user): Do not send +r flag to user when
+       they first connect.
+
+2006-01-09  Michael Poole <mdpoole@troilus.org>
+
+       * include/ircd_features.h (FEAT_ZANNELS): Actually, put it back.
+
+       * ircd/ircd_features.c (FEAT_ZANNELS): Likewise.
+
+2006-01-06  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/channel.c (mode_process_clients): Do not reveal zombies who
+       are being opped (MODE and KICK crossed).  Reported by coekie.
+
+2006-01-06  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/m_join.c (ms_join): Wipe out all modes (not just chanops)
+       when replacing a resurrected channel.
+
+       * ircd/convert-conf.c (dupstring): Fix probable off-by-one size
+       passed to memcpy().
+
+2006-01-03  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/channel.c (modebuf_flush_int): Also send timestamp when &me
+       originates the MODE going to other servers (currently just when a
+       client joins a zannel or uses an A/U password).
+
+2006-01-02  Michael Poole <mdpoole@troilus.org>
+
+       * include/ircd_features.h (FEAT_ZANNELS): Remove.
+
+       * ircd/channel.c (sub1_from_channel): Remove reference to
+       FEAT_ZANNELS.
+
+       * ircd/ircd_features.c (FEAT_ZANNELS): Remove.
+
+       * ircd/m_destruct.c (ms_destruct): Do not try to remove a destruct
+       event for channels that do not have them (created by BURSTing a
+       zannel but not yet destroyed by EOB).
+
+2005-12-31  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/m_whowas.c (m_whowas): Mention that IP is untracked in WHOWAS.
+       Spotted by Progs.
+
+2005-12-30  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/m_topic.c: Remove block comment about sptr, cptr, etc.
+       (do_settopic): Add doxygen comment. Move permissions checks..
+       (m_topic): .. to here.  Update doxygen comment.
+       (ms_topic): Update doxygen comment here too.
+
+2005-12-30  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/s_conf.c (conf_debug_iline): Fix display of null passwords.
+
+2005-12-30  Michael Poole <mdpoole@troilus.org>
+
+       * RELEASE.NOTES: Mention removal of HIS_STATS_h.
+
+       * ircd/convert-conf.c (removed_features): Add AUTOHIDE,
+       HIS_DESYNCS and TIMESEC.
+       (get_connect): Do not downcase connection name on insert.
+       (do_feature): Do not upcase feature name (cf HIS_STATS_k).
+
+2005-12-30  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/engine_devpoll.c (engine_loop): Remove bogus assert.
+
+2005-12-31  Perry Lorier <isomer@undernet.org>
+
+       * convert-conf.c: Skip with a warning, H:'s that are missing a
+       corresponding C:
+
+2005-12-28  Michael Poole <mdpoole@troilus.org>
+
+       * ircd-patch: Do not use [ for test, and do not use $[] for expr.
+       (Solaris /bin/sh, among others, have problems with those.)
+
+2005-12-23  Michael Poole <mdpoole@troilus.org>
+
+       * config.guess: Update to current version.
+
+       * config.sub: Likewise.
+
+2005-12-23  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/m_join.c: get rid of MAGIC_REMOTE_JOIN_TS; perform the
+       deop-other-users loop only when creation < channel timestamp or
+       when the channel in question happens to be a zannel; actually deop
+       users, don't just say we are and not do it
+
+       * ircd/m_create.c (ms_create): get rid of MAGIC_REMOTE_JOIN_TS
+
+       * include/channel.h: get rid of MAGIC_REMOTE_JOIN_TS
+
+2005-12-13  Michael Poole <mdpoole@troilus.org>
+
+       * configure.in: Define a macro when compiling on Solaris.
+
+       * ircd/ircd_crypt_native.c (_XOPEN_SOURCE): Turn down to 500 so
+       that Solaris doesn't complain that SUSv3 requires C99.
+
+       * ircd/os_generic.c (_XOPEN_SOURCE): Likewise, but leave it at 600
+       on non-Solaris platforms so that IPv6 stays supported.
+
+2005-12-13  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/m_join.c (ms_join): Prevent net rides allowed by moving the
+       channel timestamp backwards in time without deopping current ops.
+       (Reported by Wouter Coekaerts.)
+
+2005-12-13  Michael Poole <mdpoole@troilus.org>
+
+       * doc/example.conf: Remove extraneous "Other" Client block.
+
+       * ircd/convert-conf.c (finish_operators): Fix operator precedence
+       bug.
+
+       * ircd/ircd_parser.y (clientclass): Fix typo in error message.
+
+2005-11-27  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/Makefile.in (version.c): version.c also depends on
+       version.h, patchlevel.h and source files.
+
+2005-11-27  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/m_join.c (m_join): Count a join to a new channel as a
+       target change.
+
+2005-11-19  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/s_stats.c (stats_servers_verbose): Display IPv6 support
+       flag with the other per-server flags.
+
+2005-11-19  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/convert-conf.c (finish_features): Only emit "Features {"
+       once in the converted configuration file.  Display the original
+       input line for each feature line in the output.
+
+2005-11-18  Michael Poole <mdpoole@troilus.org>
+
+       * include/patchlevel.h (PATCHLEVEL): Update for pre05.
+
+2005-11-18  Michael Poole <mdpoole@troilus.org>
+
+       * include/patchlevel.h (PATCHLEVEL): Update for release.
+
+2005-11-15  Brian Cline <brian.cline@gmail.com>
+
+       * doc/example.conf: Add new line for HIS_MODEWHO feature.
+
+       * doc/readme.features: Document new HIS_MODEWHO feature.
+
+       * include/ircd_features.h: Declare new HIS_MODEWHO feature.
+
+       * ircd/channel.c (modebuf_flush_int): Use new HIS_MODEWHO feature
+       to show or hide the server name that performed a channel mode change.
+
+       * ircd/ircd_features.c: Place new HIS_MODEWHO setting in the feature
+       table and give it a default value of true, which will hide the
+       originating server name.
+
+2005-11-16  Michael Poole <mdpoole@troilus.org>
+
+       * doc/example.conf (Features): Mention ZANNELS default.
+
+       * doc/readme.features: Document OPLEVELS and ZANNELS.
+
+2005-11-17  Carlo Wood <run@alinoe.com>
+
+       * include/ircd_features.h (Feature): Add ZANNELS.
+       * ircd/ircd_features.c (FeatureDesc): idem.
+       * ircd/channel.c (sub1_from_channel): Don't keep zannels
+       around when ZANNELS and OPLEVELS are FALSE.
+       * ircd/m_destruct.c (ms_destruct): Use JOIN instead of
+       CREATE to recreate a non-empty channel after DESTRUCT.
+
+2005-11-16  Michael Poole <mdpoole@troilus.org>
+
+       * tools/convert-conf.py: Delete obsolete code.
+
+2005-11-16  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/m_names.c (m_names): Fix handling of NAMES #a,#b.
+       (ms_names): Likewise.
+
+2005-11-15  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/m_nick.c (ms_nick): Clarify message when an older nick
+       overrules a newer nick.  When killing a client for a nick
+       collision, make sure to use the numnick as the first argument.
+
+2005-11-14  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/channel.c (member_can_send_to_channel): After prodding from
+       reed, always allow remote users to send to a channel.  He also
+       pointed out a bug in the first version of this change.
+
+2005-11-14  Carlo Wood <run@alinoe.com>
+
+       * ircd/channel.c (modebuf_flush_int): Fix test for limitdel.
+       (modebuf_mode_uint): Make sure the limit is included as an
+       argument when necessary (and only when necessary) in a bounce.
+
+       * ircd/m_destruct.c (ms_destruct): Generate a mode bounce instead
+       of burst to resynchronize a non-empty destructed channel.
+
+2005-11-14  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/channel.c (find_no_nickchange_channel): Disallow nick
+       changes by voiceless no-account users on a +r channel.
+
+2005-11-14  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/m_kick.c (ms_kick): Fix test for whether a client's own
+       server is kicking him.
+
+2005-11-13  Michael Poole <mdpoole@troilus.org>
+
+       * include/patchlevel.h (PATCHLEVEL): Bump for pre04.
+
+2005-11-13  Michael Poole <mdpoole@troilus.org>
+
+       * include/patchlevel.h (PATCHLEVEL): Update for release.
+
+2005-11-13  Carlo Wood <run@alinoe.com>
+
+       * ircd/m_create (ms_create): Accept CREATE for zannels.
+
+       * ircd/m_join.c (m_join): MODE +o for a zannel must come from the
+       server for compatibility with older versions.
+
+2005-11-12  Michael Poole <mdpoole@troilus.org>
+
+       * include/patchlevel.h (PATCHLEVEL): Bump for pre03.
+
+2005-11-12  Michael Poole <mdpoole@troilus.org>
+
+       * include/patchlevel.h (PATCHLEVEL): Update for release.
+
+2005-11-11  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/ircd_res.c (proc_answer): Follow CNAME when doing A
+       and AAAA lookups as well as PTR.
+
+2005-11-07  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/channel.c (mode_parse_client): Allow clients to specify
+       oplevel in MODE #channel +o.
+       (mode_process_clients): Allow oplevel 999 to deop another 999.
+
+       * ircd/kick.c (m_kick): Allow oplevel 999 to kick another 999.
+
+2005-10-31  Michael Poole <mdpoole@troilus.org>
+       (Based on a patch by Romain Bignon <progs@ir3.org>)
+
+       * ircd/channel.c: Some modes (currently only WASDELJOINS) should
+       not be propagated to remote servers.
+
+2005-10-30  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/channel.c (mode_parse_apass): Move all send_reply() errors
+       inside an if (MyUser(state->sptr)) test.
+
+       * ircd/m_join.c (m_join): Reorganize zannel join check to match
+       surrounding code.
+
+2005-10-30  Carlo Wood <run@alinoe.com>
+
+       * ircd/channel.c (sub1_from_channel): Delay destruction for -A
+       channels.  They become zombie channels (zannels).
+       (mode_parse_upass): Add duration to ERR_NOMANAGER message.
+       (mode_parse_apass): Likewise.  Unconditionally set the member who
+       sets Apass as oplevel 0.  Clear Upass when clearing Apass.
+       (joinbuf_join): Remove code to pass oplevel in JOIN.
+
+       * ircd/m_burst.c (ms_burst): Handle zannels.
+
+       * ircd/m_join.c (m_join): Handle a join to a zannel.  If the user
+       is joining with ops and/or an oplevel, send those.
+       (ms_join): Stop trying to parse oplevels in JOIN.  Copy join
+       timestamp when a user joins a zannel.
+
+       * ircd/m_mode.c (ms_mode): Never generate HACK3.  Silently allow a
+       user to op himself if he is the only one in a channel.
+
+       * ircd/s_err.c (ERR_UPASSSET): Remove extra space.
+       (ERR_UPASSNOTSET): Likewise.
+       (ERR_NOMANAGER): Add field for channel lifetime.
+
+2005-10-30  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/m_join.c (m_join): Fix check for OVERRIDE when the real
+       channel key is OVERRIDE.  (Reworked patch from a1kmm.)
+
+2005-10-30  Michael Poole <mdpoole@troilus.org>
+
+       * .cvsignore: Add autom4te.cache.
+
+       * ircd/.cvsignore: Add convert-conf.
+
+       * ircd/test/.cvsignore: Add ircd_match_t.
+
+       * patches/.cvsignore: Add marks.
+
+2005-10-28  Alex Badea  <vamposdecampos@gmail.com>
+
+       * ircd/m_kick.c (ms_kick): Fix format string typo (bug #1339538)
+
+2005-10-17  Diane Bruce  <db@db.net>
+
+       * ircd/ircd_res.c: Don't send retries if the client did
+       not resolve (SERVFAIL); this fixes a bug causing a flurry
+       of retries in this case
+
+2005-10-14  Michael Poole <mdpoole@troilus.org>
+
+       * include/patchlevel.h (PATCHLEVEL): Update to pre02.
+
+2005-10-14  Michael Poole <mdpoole@troilus.org>
+
+       * doc/readme.cvs: Document tag name consistently with the release
+       name.
+
+       * include/patchlevel.h (PATCHLEVEL): Bump patchlevel for release
+       of 2.10.12.01.
+
+2005-10-12  Michael Poole <mdpoole@troilus.org>
+
+       * doc/example.conf: Update documentation to match this change.
+
+       * ircd/client.c (client_set_privs): Make default global oper
+       privileges match what was in 2.10.11.
+
+2005-10-11  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/os_generic.c (os_get_rusage): Make conditional on DEBUGMODE
+       to mitigate bug #1313429.
+
+2005-10-12  Perry Lorier <isomer@undernet.org>
+
+       * include/s_stats.h: Add new "Local" only flag to /stats.
+
+       * ircd/m_stats.c: Consult it.
+
+       * ircd/s_stats.c: Use the flag.
+
+2004-01-04  Kevin L Mitchell  <klmitch@mit.edu>
+
+       * ircd/s_numeric.c (do_numeric): fix a crash when a numeric is
+       sent to a channel...
+
+2005-10-06  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/m_join.c (m_join): Report too-long channel names as
+       non-existent.
+
+2005-10-05  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/m_names.c (m_names): Fix format string when forwarding
+       /names -D to other servers.
+       (ms_names): Likewise.  Add support for remote /names -D.
+
+2005-10-05  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/class.c (do_find_class): Fix bug from previous commit.
+
+       * ircd/ircd_parser.y (clientblock): Allow setting Client port.
+
+       * ircd/s_conf.c (check_limit_and_attach): Merge into attach_iline.
+       (attach_iline): Only set FLAG_DOID when we are sure we will attach
+       this Client block to the client. [Credit: Jukka Ollila and others]
+
+2005-10-04  Michael Poole <mdpoole@troilus.org>
+       [Based on a patch by Jukka Ollila]
+
+       * include/class.h (find_class): Rename to do_find_class().
+
+       * ircd/class.c (class_delete_marked): Keep invalid classes in list
+       until next rehash.
+       (add_class): Use new parameter to do_find_class() to allow a class
+       to be "resurrected".
+       (find_class): Rename.
+       (report_classes): Use 'y' instead of 'Y' when reporting invalid
+       classes.
+
+2005-10-01  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/m_kick.c (ms_kick): If the kick target is join-delayed,
+       only send the KICK to the kicker.  Spotted by Cesar_.
+
+2005-10-01  Michael Poole <mdpoole@troilus.org>
+
+       * include/patchlevel.h (PATCHLEVEL): Update to pre1.
+
+       * ircd/class.c (init_class): Only set default class's ->next
+       pointer when first allocating it.
+
+2005-09-30  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/m_who.c (m_who): Handle matchsel & WHO_FIELD_ACC when
+       matching users.
+
+2005-09-30  Michael Poole <mdpoole@troilus.org>
+
+       * include/patchlevel.h: Update for release.
+
+2005-09-28  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/m_kick.c (ms_kick): Use correct oplevel when bouncing a
+       chanop being kicked.
+
+2005-09-26  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/whocmds.c (do_who): Fix uninitialized variable warning
+       about 'chan'.
+
+2005-09-26  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/parse.c (del_msg_element): Only delete empty subtrees, and
+       leave subtrees that may still contain data.
+
+2005-09-26  Michael Poole <mdpoole@troilus.org>
+
+       * include/channel.h (struct ModeBuf): Add mbm_oplevel to args
+       array.
+       (MB_OPLEVEL): New corresponding macro.
+       (modebuf_mode_client): Add corresponding argument.
+
+       * ircd/channel.c (modebuf_flush_int): Adjust worst-case buffer
+       usage to include :999 suffix.  Change format for oplevel passing.
+       (modebuf_mode_client): Set oplevel field in mbuf args array.
+       (struct ParseState): Add oplevel field to cli_change array.
+       (mode_parse_client): Accept and record oplevel suffix from
+       servers; fix it up if we're bouncing a deop.
+       (mode_process_clients): If a valid oplevel was parsed, use it.
+
+       * ircd/m_burst.c (ms_burst): Pass oplevel to modebuf_mode_client().
+
+       * ircd/m_clearmode.c (do_clearmode): Likewise.
+
+       * ircd/m_create.c (ms_create): Likewise.
+
+       * ircd/m_kick.c (ms_kick): Likewise.
+
+2005-09-23  Michael Poole <mdpoole@troilus.org>
+
+       * include/whocmds.h (WHOSELECT_DELAY): Define new constant.
+
+       * ircd/m_who.c (m_who): Accept 'd'/'D' as a way to set
+       WHOSELECT_DELAY, just like 'o' for WHOSELECT_OPER.  Do not skip
+       join-delayed users if WHOSELECT_DELAY is set.
+
+       * ircd/whocmds.c (do_who): Remember membership for shared channel
+       if one exists.  Use it when displaying flags, adding '<' for
+       join-delayed users.
+
+2005-09-22  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/channel.c (mode_parse_key): Only accept the new key when
+       the current one is empty or "greater" than the new one.
+       (mode_parse_upass): Likewise, for upass.
+       (mode_parse_apass): Likewise, for apass.
+
+2005-09-22  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/gline.c (gline_checkmask): Add missing digit in mask length
+       check.
+
+2005-09-21  Michael Poole <mdpoole@troilus.org>
+
+       * doc/example.conf: Remove confused and outdated references to
+       Martians.
+
+2005-09-20  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/Makefile.in: Regenerate "make depend" dependencies.
+
+       * ircd/test/Makefile.in: Likewise.
+
+2005-09-16  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/m_join.c (last0): fix problem leading to protocol
+       violations on certain combinations of /join 0 from remote servers
+       (probably from local users, too) [bug #1291029]; remove redundant
+       !IsChannelChar() check
+
+2005-09-14  Michael Poole <mdpoole@troilus.org>
+
+       * doc/readme.cvs: Document the branching scheme for 2.10.12.
+
+2005-09-14  Michael Poole <mdpoole@troilus.org>
+
+       * include/patchlevel.h (PATCHLEVEL): Increment to reflect the
+       pre-release code freeze.
+
+2005-09-14  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/channel.c (find_ban): Fix the sense of another check.
+
+2005-09-13  Michael Poole <mdpoole@troilus.org>
+
+       * include/channel.h (clean_channelname): Remove prototype.
+
+       * ircd/m_invite.c (m_invite): Do not clean channel name; just
+       reject invalid channel names.
+
+       * ircd/m_join.c (m_join): Likewise.
+
+       * ircd/m_mode.c (m_mode): Do not clean channel name.
+
+       * ircd/m_names.c (m_names): Likewise.
+
+       * ircd/m_opmode.c (mo_opmode): Likewise.
+
+2005-09-13  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/channel.c (find_ban): Revert to older style of comparison,
+       fixing the sense of one check.  Spotted by Alex Badea.
+
+2005-09-13  Alex Badea <vamposdecampos@gmail.com>
+
+       * ircd/ircd.c (try_connections): modify autoreconnect logic to
+       allow FEAT_CONNECTFREQUENCY to be smaller than Class connectfreq
+
+2005-09-13  Alex Badea <vamposdecampos@gmail.com>
+
+       * ircd/s_conf.c (close_mappings): NULL out GlobalServiceMapList,
+       otherwise the linked list has an invalid ending sentinel on rehash
+
+2005-09-12  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/channel.c (find_ban): Compare ban mask against hostname
+       even when it looks like an IP, to match things like *!*@1.* when
+       users have a hostname like 1.2.3.example.com.
+
+2005-09-12  Michael Poole <mdpoole@troilus.org>
+
+       * RELEASE.NOTES: Note the resolution of ambiguous ipmasks.
+
+       * ircd/ircd_string.c (ipmask_parse): Implement it.
+
+2005-09-12  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/m_join.c (m_join): If we find an empty key, null out the
+       key pointer.
+
+2005-09-11  Michael Poole <mdpoole@troilus.org>
+
+       * RELEASE.NOTES: Mention the side benefits of this change.
+
+       * include/ircd_string.h (ipmask_parse): Declare function here.
+       (ircd_aton): Becomes a special case of ipmask_parse().
+
+       * include/match.h (check_if_ipmask): Undeclare function.
+       (ipmask_parse): Remove function prototype from this file.
+
+       * ircd/ircd_string.c (ircd_aton_ip4): Add nullable pbits parameter
+       to accept ipmask length.  Rework to fill that in.
+       (ircd_aton): Rework into...
+       (ipmask_parse): this function, which knows how to fill in its own
+       pbits parameter.
+
+       * ircd/m_burst.c (ms_burst): Rely on make_ban() to set the ban
+       flags correctly, to avoid call to check_if_ipmask().
+
+       * ircd/match.c (ipmask_parse_ipv4): Delete function.
+       (check_if_ipmask): Likewise.
+       (ipmask_parse): Delete this version in favor of ircd_string.c's.
+
+       * ircd/test/ircd_in_addr_t.c (ipmask_test): New struct type.
+       (test_masks): New array of ipmask_test.
+       (test_ipmask): Function to run one of those tests.
+       (main): Call test_ipmask().
+
+2005-09-11  Alex Badea <vamposdecampos@gmail.com>
+
+       * ircd/m_ping.c (ms_ping, mo_ping): misplaced chunk of code
+       (probably during the forward port) which broke AsLL; fixed.
+
+2005-09-01  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/gline.c (make_gline): Remove debug output from when IPv6
+       support was being debugged.
+       (do_gline): Likewise.
+       (gline_lookup): Likewise, plus remove redundant code.
+
+2005-09-01  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/channel.c (joinbuf_join): Ignore joinbuf type when joining
+       0, since no other call passes a null channel.
+
+       * ircd/m_join.c: Remove comment discussing argument meanings.
+       (last0): Make this also handle the JOIN 0 logic, doxyfy.
+       (join0): Merge into last0.
+       (m_join): Doxygenate.  Remove check for join0.  Further
+       reorganize, so new versus old channel handling are moved to just
+       one place each within this function.
+       (ms_join): Doxygenate.  Remove check for join0.
+
+2005-09-01  Michael Poole <mdpoole@troilus.org>
+
+       * RELEASE.NOTES: Bump revision date and highlight this change.
+
+       * include/channel.h (MAGIC_OPER_OVERRIDE): Remove.
+       (can_join): Remove declaration.
+
+       * ircd/channel.c (compall): Remove.
+       (can_join): Remove.
+
+       * ircd/m_join.c (m_join): Remove redundant check for control
+       characters (clean_channelname() will get them). Reorganize initial
+       flags calculation.  Accept channel keys like RFC 1459 says; this
+       requires the old compall()/can_join() logic to modify 'keys', so
+       inline the code and reorganize it.
+
+2005-08-30  Michael Poole <mdpoole@troilus.org>
+
+       * include/channel.h (PASSLEN): Remove; use KEYLEN instead.
+
+       * ircd/channel.c (mode_parse_upass): Likewise.
+       (mode_parse_apass): Likewise.
+       The inconsistency (in clean_key()) was reported by Reed.
+
+2005-08-30  Michael Poole <mdpoole@troilus.org>
+
+       * RELEASE.NOTES: Document +D and +d channel modes.
+
+2005-08-29  Michael Poole <mdpoole@troilus.org>
+
+       * include/numeric.h (ERR_NOMANAGER_LONG): Undefine.
+       (ERR_NOMANAGER_SHORT): Rename to ERR_NOMANAGER.
+
+       * ircd/s_err.c (replyTable): Change to reflect that.
+
+       * ircd/channel.c (clean_key): New function.
+       (mode_parse_key): Use it, and check that keys do not start with :.
+       (mode_parse_upass): Likewise, and adjust for ERR_NOMANAGER.
+       (mode_parse_apass): Likewise.
+       The key and password changes fix bugs reported by coekie.
+
+2005-08-27  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/channel.c (add_user_to_channel): Use SetOpLevel() instead
+       of assigning directly to member->oplevel.
+       (mode_parse_apass): Likewise.
+       (mode_process_clients): Users opped by outsiders should get
+       oplevel 1, since they are not channel managers.
+
+       * ircd/m_burst.c (ms_burst): Use SetOpLevel() instead of assigning
+       directly to member->oplevel.
+
+2005-08-25  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/channel.c (member_can_send_to_channel): At coekie's
+       suggestion, disallow channel manager talking after Apass is set,
+       so they set and use Upass sooner.
+
+       * ircd/class.c (init_class): Default class should have 1 link.
+       (report_classes): Return links count minus one to match old output.
+
+       * ircd/m_trace.c (do_trace): Fix links count here, too (spotted by
+       Reed).
+
+2005-08-25  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/channel.c (mode_parse): Accept +A/+U from servers
+       regardless of FEAT_OPLEVELS.
+
+2005-08-24  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/ircd.c (parse_command_line): Mention epoll engine when run
+       with -v.
+
+2005-08-24  Michael Poole <mdpoole@troilus.org>
+
+       * include/patchlevel.h (PATCHLEVEL): Increment.
+
+       * ircd/channel.c (joinbuf_join): Double check that oplevel is 0 or
+       1 when propagating JOIN <level>:#channel, to avoid PV on receiver.
+
+       * ircd/engine_epoll.c: Add system call numbers for more CPU types.
+
+       * ircd/ircd_log.c (log_open): Remove NFS-oriented alarm() calls;
+       anyone who writes logs over NFS is mental.  (Thanks to D. Bruce.)
+
+2005-08-21  Michael Poole <mdpoole@troilus.org>
+
+       * include/s_conf.h (free_mapping): Declare new function.
+
+       * ircd/ircd_parser.y (pseudoblock): Use it.
+
+       * ircd/s_conf.c (free_mapping): Define it.
+       (close_mappings): New function.
+       (rehash): Call close_mappings() before reading file.
+
+       * ircd/m_kill.c (do_kill): Revert 2005-08-18 change.
+
+2005-08-19  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/parse.c (tok_tree): Re-add token tree structure.
+       (initmsgtree): Populate it.
+       (parse_server): Prefer it to full message tree.
+
+2005-08-18  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/m_kill.c (do_kill): When FEAT_HIS_KILLWHO, change apparent
+       source of KILLs to &his instead of &me.
+
+2005-08-16  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/channel.c (mode_parse_ban): Avoid overwriting part of
+       newban->banstr[] when the source is a server.  (Spotted by jcq.)
+
+2005-08-16  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/channel.c (joinbuf_join): Switch to &his instead of &me for
+       announcements to local users in a channel.
+
+       * ircd/m_burst.c (ms_burst): Likewise.
+
+       * ircd/m_invite.c (m_invite): Likewise.
+       (ms_invite): Likewise.
+
+       * ircd/m_kick.c (ms_kick): Likewise.
+
+       * ircd/m_topic.c (do_settopic): Another &me -> &his change for
+       HIS, and use that apparent source for the channel localcast.
+
+2005-08-16  Jukka Ollila <jaollila@niksula.hut.fi>
+
+       * ircd/s_user.c (hide_hostmask): Use HIS_SERVERNAME instead of the
+       real thing for the post-mode-x rejoin.
+
+2005-08-15  Michael Poole <mdpoole@troilus.org>
+
+       * include/supported.h (FEATURESVALUES2): Add +d channel mode.
+
+       * ircd/IPcheck.c (ip_registry_new_entry): Clarify that this is not
+       a varadic function.  (Suggested by Ian Kumlien.)
+
+       * ircd/convert-conf.c (finish_operators): Likewise.
+
+       * ircd/listener.c (close_listeners): Likewise.
+
+       * ircd/channel.c (CheckDelayedJoins): Use HIS server name to
+       remove channel mode +d.
+
+2005-08-12  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/channel.c (pretty_mask): Recognize ':' as unique to the
+       host part of a ban mask.
+
+2005-08-03  Jan Krueger <jast@heapsort.de>
+
+       * ircd/m_kick.c (m_kick): Send JOIN prior to confirming KICK on
+       invisible member.
+
+2005-08-08  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/channel.c (find_ban): For non-IPmask bans, match the ban
+       string against the string form of the client's IP address.
+
+2005-07-16  Michael Poole <mdpoole@troilus.org>
+
+       * configure.in: Apply a test for socklen_t that Reed found.
+
+       * configure: Regenerate.
+
+2005-07-16  Michael Poole <mdpoole@troilus.org>
+
+       * RELEASE.NOTES: Mention that 2.10.11 does not support oplevels.
+
+       * README.FreeBSD: Remove (merged into README).
+
+       * README.Solaris: Remove (merged into README).
+
+       * README: Merge in the above; also update for 2.10.12.
+
+       * doc/example.conf: Change mention of K-lines to say Kill blocks
+       instead.
+
+       * doc/iauth.txt: Remove (out of date).
+
+       * doc/readme.features: Update to reflect that 2.10.11 is not the
+       current release.  Change mention of various config lines to use
+       the equivalent config entries or blocks instead.
+
+       * doc/readme.log: Likewise.
+
+       * doc/api/features.txt: Change F-line mentions to say Feature
+       entry instead.
+
+       * doc/api/modebuf.txt: Change U-line mention to say Uworld entry.
+
+       * doc/api/motd.txt: Change T-line mentions to say Motd entry.
+
+2005-07-15  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/ircd_features.c (feature_init): Always call
+       feature_notify_server*() so that 'his' is initialized.
+
+       * ircd/m_whois.c (do_whois): Unswap sense of comparison to choose
+       between user->server and &his.
+
+2005-07-14  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/channel.c (mode_parse_apass): Update oplevels when setting
+       or removing the +A password.  Partial credit goes to Reed Loden.
+
+2005-07-14  Michael Poole <mdpoole@troilus.org>
+
+       * include/ircd_features.h: Declare new "his" pseudo-server to hold
+       FEAT_HIS_SERVERNAME and FEAT_HIS_SERVERINFO in a convenient place.
+
+       * ircd/ircd_features.c: Initialize and update it.
+
+       * ircd/channel.c (modebuf_flush_int): Use it as the apparent
+       source for opmodes and server mode changes (also when the source
+       is me).
+
+       * ircd/m_burst.c (ms_burst): Use it as the apparent source for net
+       rider kicks.
+
+       * ircd/m_whois.c (do_whois): Use it to simplify code here.
+
+       * ircd/s_misc.c (exit_client): Use it as the apparent killer.
+
+2005-07-14  Michael Poole <mdpoole@troilus.org>
+
+       * doc/example.conf (General): Update comment about vhost to match
+       the code change below.
+
+       * ircd/ircd_parser.y (generalvhost): Accept vhost="*"; as a
+       synonym for the default behavior (for backwards compatibility).
+       Spotted by Kev.
+
+       * ircd/channel.c (sub1_from_channel): Remove stale code and
+       comment, replacing with an up-to-date comment.  Spotted by skx.
+
+2005-07-11  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/engine_select.c: Remove outdated comment about USE_POLL.
+
+       * ircd/parse.c (msgtab): #if out CAP handler until we have caps.
+
+       * RELEASE.NOTES: Remove mention of capabilities for now.
+
+2005-07-11  Stephan Peijnik <speijnik@gmail.com>
+
+       * ircd/gline.c (gline_add): It's only a protocol violation when a
+       server issues a "whacky" gline.  If it's an oper, only tell opers
+       with SNO_GLINE.
+
+       * ircd/ircd_auth.c (iauth_protocol_violation): Likewise, the whole
+       network is not likely to care about IAuth PVs, so only tell opers
+       with SNO_CONNEXIT.
+
+2005-07-11  Michael Poole <mdpoole@troilus.org>
+
+       * doc/readme.features: Document FEAT_CHANNELLEN.
+
+       * doc/example.conf: Give an example of it.
+
+       * ircd/m_join.c (ms_join): Do not clean channel names from remote
+       servers, to avoid desynchs.
+
+       * ircd/m_names.c (ms_names): Likewise.
+
+2005-07-11  Stephan Peijnik <speijnik@gmail.com>
+
+       * include/ircd_features.h: Declare new FEAT_CHANNELLEN.
+
+       * include/supported.h: Add it to the ISUPPORT display.
+
+       * ircd/channel.c (clean_channelname): Impose the lower limit
+       between FEAT_CHANNELLEN and CHANNELLEN.
+
+       * ircd/ircd_features.c: Define FEAT_CHANNELLEN.
+
+2005-07-11  Reed Loden <reed@reedloden.com>
+
+       * include/sys.h: Move FD_SETSIZE redefinition to engine_select.c.
+
+       * ircd/s_bsd.c: Move FD_SETSIZE sanity check to engine_select.c
+       Remove unused #include <sys/poll.h>.
+
+       * ircd/engine_select.c: Put FD_SETSIZE redefinition and sanity
+       checks here, since they are not used elsewhere in the daemon.
+       [Order slightly changed by Michael Poole to compile.]
+
+2005-07-03  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/convert-conf.c: New file.
+
+       * ircd/Makefile: Compile it.
+
+2005-06-27  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/s_bsd.c (add_connection): Split logic for server versus
+       client listeners; only do IPcheck for client connections.
+
+       * ircd/s_serv.c (server_estab): There is no longer a need to
+       remove IPcheck reference, so don't.
+
+2005-06-27  Michael Poole <mdpoole@troilus.org>
+
+       * include/client.h (struct Connection): Remove con_dns_reply (and
+       associated macros).
+
+       * include/res.h (gethost_byname): Change calling signature to
+       clarify memory ownership.
+       (gethost_byaddr): Likewise.
+
+       * include/s_bsd.h (release_dns_reply): Remove function.
+
+       * ircd/hash.c: #include "match.h" to quash warning.
+
+       * ircd/ircd_auth.c (struct IAuth): Remove i_query field.
+       (iauth_dns_callback): Adjust for new gethost_byname signature.
+       (iauth_reconnect): Likewise.
+
+       * ircd/ircd_res.c (struct reslist): Make elements of query field
+       inline rather than in a contained structure.
+       (make_request): Reflect removal of DNSQuery.
+       (do_query_name): Likewise.
+       (do_query_number): Likewise.
+       (make_dnsreply): Remove now-unused function.
+       (timeout_resolver): Adjust to new callback signature.
+       (delete_resolver_queries): Reflect removal of DNSQuery.
+       (gethost_byname): Update to new signature.
+       (gethost_byaddr): Likewise.
+       (res_readreply): Reflect removal of DNSReply.
+
+       * ircd/list.c (dealloc_connection): con_dns_reply no longer
+       exists, so do not free it.
+
+       * ircd/s_auth.c (auth_verify_hostname): constify.
+       (auth_dns_callback): Adjust to new callback signature.
+       (start_auth): Adjust to new gethost_byaddr() signature.
+
+       * ircd/s_bsd.c (connect_dns_callback): Adjust to new callback
+       signature.
+       (release_dns_reply): Remove unused function.
+       (connect_server): Adjust to new gethost_byname() signature.
+
+       * ircd/s_conf.c (conf_dns_callback): Adjust to new callback
+       signature.
+       (conf_dns_lookup): Adjust to new gethost_byname() signature.
+       (attach_iline): Use cli_sockhost() instead of DNS reply.
+       (conf_check_server): Simplify use of DNS results.
+
+       * ircd/s_serv.c (server_estab): Remove call to removed function.
+
+       * ircd/s_user.c (register_user): Remove call to removed function.
+
+2005-06-27  Michael Poole <mdpoole@troilus.org>
+
+       * include/s_misc.h (get_sockhost): Remove the unused (and
+       deceptively named) get_sockhost().
+
+       * ircd/s_misc.c (get_sockhost): Likewise.
+
+2005-06-25  Andrew Miller  <a1kmm@amxl.com>
+
+       * ircd/ircd_crypt.c (ircd_crypt): strdup is not allowed, change to
+       DupStr so memdebug works.
+
+       * doc/debug_memleak_gc.patch : Update to gc6.5
+       
+2005-06-24  Andrew Miller  <a1kmm@amxl.com>
+       * ircd/m_invite.c (m_invite): Don't propagate invites to local channels.
+       
+2005-06-21  Andrew Miller  <a1kmm@amxl.com>
+
+       * ircd/m_list.c (param_parse): Add support for channel wildcards.
+       * ircd/m_list.c (show_usage): Document the new format.
+       * ircd/hash.c (list_next_channels): Check channel wildcard in list.
+       * include/channel.h (ListingArgs): Add the wildcard member.
+
+2005-06-19  Andrew Miller  <a1kmm@amxl.com>
+
+       * ircd/ircd_res.c (proc_answer): Deal with unexpected record types more
+       gracefully.
+
+       * ircd/ircd_res.c (res_readreply): Check res_ourserver before walking
+       the pending request list, to make DoS attacks harder.
+
+       * ircd/m_invite.c (m_invite): Give no such channel rather than not on
+       channel when the channel being invited to does not exist.
+       
+2005-06-18  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/s_debug.c (count_memory): Consolidate several lines; make
+       initial letter capitalization consistent.
+
+2005-06-19  Andrew Miller  <a1kmm@amxl.com>
+
+       * ircd/s_stats.c: Remove the "debug only" label on memusage stats,
+       since it no longer applies.
+
+2005-05-16  Michael Poole <mdpoole@troilus.org>
+
+       * include/channel.h (struct Ban): Make 'who' and 'banstr' direct
+       arrays, rather than pointers.
+
+       * ircd/channel.c (bans_alloc): New variable to count number of ban
+       structures allocated.
+       (bans_inuse): New variable to count number of ban structures
+       currently in use.
+       (set_banmask): Adapt to changes in struct Ban.
+       (make_ban): Likewise, and update ban counts.
+       (free_ban): Likewise.
+       (bans_send_meminfo): New function.
+       (apply_ban): Adapt to changes in struct Ban.
+       (mode_parse_ban): Likewise.
+       (mode_process_bans): Likewise.
+       (mode_parse): Likewise.
+       (RevealDelayedJoin): Fix brace placement.
+       (CheckDelayedJoins): Fix brace placement and whitespace.
+
+       * ircd/list.c (struct liststats): Add new fields to eliminate the
+       separate count variables.
+       (init_list): Adapt to those changes.
+       (alloc_client): Likewise.
+       (dealloc_client): Likewise.
+       (alloc_connection): Likewise.
+       (dealloc_connection): Likewise.
+       (make_server): Likewise.
+       (remove_client_from_list): Likewise.
+       (verify_client_list): Likewise.
+       (make_link): Likewise.
+       (free_link): Likewise.
+       (send_liststats): New function.
+       (send_listinfo): Rewrite to use new struct liststats layout.
+
+       * ircd/m_burst.c (ms_burst): Adapt to changes in struct Ban.
+
+       * ircd/m_clearmode.c (do_clearmode): Adapt to changes in struct
+       Ban.
+
+       * ircd/s_stats.c (stats_meminfo): Define unconditionally and call
+       bans_send_meminfo().
+       (statsinfo): Always give access to stats_meminfo.
+
+2005-06-16  Michael Poole <mdpoole@troilus.org>
+
+       * include/ircd_string.h: Include necessary <string.h> header.
+
+       * ircd/test/.cvsignore: Ignore log output files.
+
+       * ircd/test/Makefile.in: Remove log output files.
+
+       * ircd/test/kill-block-1.cmd: Add sleeps to try to trigger Kills.
+
+       * ircd/test/run-tests.sh: Switch sense of argument.  Send an IRC
+       debug dump to log files.
+
+2005-06-13  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/s_user.c (make_user): Unconditionally increment userCount.
+       (free_user): Unconditionally decrement it here.
+
+       * ircd/s_conf.c (make_conf): Unconditionally increment
+       GlobalConfCount.
+       (free_conf): Unconditionally decrement it here.
+
+       * ircd/s_debug.c (count_memory): Fix termination condition for
+       ban-walking loop.  Add missing "e" to "members".
+
+
+2005-06-10  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/match.c (check_if_ipmask): Strings that contain '?' cannot
+       be true IP masks.
+
+2005-05-30  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/test/Makefile.in: Add LDFLAGS variable for profiling purposes.
+
+       * ircd/test/ircd_match_t.c: Test recovery from backtracking.
+
+       * ircd/test/channel-1.cmd: Modify to improve code coverage.
+
+       * ircd/test/client-1.cmd: Likewise.
+
+       * ircd/test/gline-1.cmd: Likewise.
+
+       * ircd/test/ircd-t1.conf: Likewise.
+
+       * ircd/test/stats-1.cmd: Likewise.
+
+       * ircd/test/run-tests.sh: Explicitly start ircds.  Add new test scripts.
+
+       * ircd/test/test-driver.pl: Silently handle more signals from IRC.
+
+       * ircd/test/commands-1.cmd: New test script.
+
+       * ircd/test/feature-1.cmd: New test script.
+
+       * ircd/test/jupe-1.cmd: New test script.
+
+       * ircd/test/kill-block-1.cmd: New test script.
+
+       * ircd/test/ircd-t1-2.conf: New configuration file for test scripts.
+
+       * ircd/test/ircd-t2.conf: Likewise.
+
+2005-05-30  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/s_debug.c (count_memory): Use count_listener_memory() to
+       report memory used by listener structures.
+
+2005-05-30  Michael Poole <mdpoole@troilus.org>
+
+       * include/class.h (get_con_freq): Remove unused function.
+
+       * include/list.h (find_user_link): Remove unused function.
+
+       * include/class.c (get_con_freq): Remove.
+
+       * ircd/list.c (find_user_link): Remove.
+
+       * include/string.h (string_is_hostname, string_is_address,
+       strnChattr): Remove unused functions.
+       (init_string): Remove function that becomes a noop.
+
+       * ircd/string.h (init_string): Remove.
+       (string_is_hostname, string_is_address, strnChattr): Likewise.
+
+       * ircd/ircd.c (main): Remove call to init_string().
+
+2005-05-30  Michael Poole <mdpoole@troilus.org>
+
+       * include/numeric.h (RPL_TRACELOG, RPL_MYPORTIS,
+       RPL_NOTOPERANYMORE): Undefine unused numeric replies.
+
+       * ircd/s_err.c (replyTable): Fix format fields for certain numeric
+       arguments.  Remove some unused entries.
+
+       * ircd/s_stats.c (stats_configured_links): Move invariant
+       parameters to message format string.
+
+2005-05-30  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/client.c (privtab): Add missing LIST_CHAN privilege, move
+       WIDE_GLINE to reflect its enumerated value.
+
+       * ircd/s_debug.c (count_memory): Use user_count_memory() function
+       to count User structs in-use.
+
+       * ircd/m_server.c (mr_server): Change "C:line" to "Connect block".
+
+       * ircd/s_bsd.c (connect_server): Likewise.
+
+       * ircd/s_conf.c (conf_check_server): Likewise.
+
+       * ircd/s_err.c (replyTable): Change "O-lines" to "Operator block".
+
+2005-05-30  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/match.c (match): Rewrite to handle globs that end in an
+       escaped wildcard (and hopefully clarify the code).
+
+       * ircd/test/Makefile.in: Add new ircd_match_t test program.
+
+       * ircd/test/ircd_match_t.c: New file.
+
+       * ircd/test/test_stub.c: Emite newlines after log and debug
+       messages.
+
+2005-05-25  Reed Loden <reed@reedloden.com>
+
+       * ircd/s_err.c (replyTable): Allow for the specification of 'O' or
+       'o' in RPL_STATSOLINE.
+
+       * ircd/s_stats.c (stats_configured_links): In /stats o/O, display
+       'O' if either the oper block or the connection class has
+       PRIV_PROPAGATE (global oper) and 'o' if neither has PRIV_PROPAGATE
+       (local oper).
+
+2005-05-30  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/IPcheck.c: Add Debug()s to try to track why the connected
+       count underflows.
+
+       * ircd/m_endburst.c (ms_endofburst): Avoid dereferencing 'chan'
+       after it may be freed (in sub1_from_channel).
+
+       * ircd/s_user.c (register_user): Rearrange code to reduce number
+       of "if (MyConnect(sptr))" checks.
+
+2005-05-12  Michael Poole <mdpoole@troilus.org>
+
+       * configure.in: Do not try to outsmart the default CFLAGS.
+       Simply add parameters explicitly requested by the user.
+
+       * configure: Regenerate.
+
+       * ircd/ircd_crypt_native.c: Use _XOPEN_SOURCE 600 (which is
+       used in os_generic.c) to get crypt() on NetBSD.
+
+2005-05-11  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/ircd.c: if debugging is enabled (both DEBUGMODE defined and
+       -x given), reserve fd 2 for the use of the debugging log;
+       otherwise, some engines may attempt to use fd 2, which would end
+       up getting closed by debug_init() (actually, by
+       log_debug_reopen(), called by log_debug_init(), called by
+       debug_init())
+
+2005-08-10  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/channel.c (joinbuf_join): Do not send a MODE +o when a
+       local user creates a channel.
+
+       * ircd/umkpasswd.c (crypt_pass): Allocate the proper amount of
+       memory for the tagged output string.
+
+       * ircd/test/test-driver.pl: Add -vhost=... option.
+
+       * ircd/test/ircd-t1.conf: Add new Operator blocks.
+
+       * ircd/test/*.cmd: Rearrange and add more coverage tests.
+
+2005-08-09  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/ircd_parser.y: Move error tokens to top level of parse, and
+       make ';' a synchronizing token for them.  This avoids crashes in
+       situations like missing ';' between two Kill blocks.  Move several
+       ';'s earlier for earlier detection of syntax errors.
+
+       * ircd/motd.c (motd_memory_count): Use size_t for memory counts to
+       match the format strings used for those variables.
+
+       * ircd/msgq.c (msgq_histogram): tmp.sizes[] is an array of
+       unsigned int, not unsigned long; use correct format string.
+
+       * ircd/s_stats.c (stats_crule_list): Restore display of 'D' vs 'd'
+       based on crule type, rather than query type.
+       (statsinfo): Remove STAT_FLAG_VARPARAM from the "modules" and
+       "help" stats, which don't use the varparam.
+
+       * ircd/test/test-driver.pl: Interpreter for test scripts.b
+
+       * ircd/test/ircd-t1.conf: Configuration file for test scripts.
+
+       * ircd/test/*.cmd: New test scripts for test-driver.pl.
+
+2005-05-08  Jukka Ollila <jaollila@niksula.hut.fi>
+       (Adapted slightly by Michael Poole.)
+
+       * ircd/os_generic.c (sockaddr_to_irc): Change to use v4compat
+       addresses event when !defined(IPV6).
+
+2005-05-07  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/channel.c (joinbuf_join): Be smarter about what source to
+       use when opping a user that joins a channel.
+
+2005-05-04  Reed Loden <reed@reedloden.com>
+
+       * ircd/m_trace.c (do_trace): Show the real nickname instead of the
+       numnick.
+
+2005-05-02  Jan Krueger <jast@heapsort.de>
+
+       * ircd/channel.c (member_can_send_to_channel): if the channel can only
+       be joined by users with accounts (+r), do not allow users without
+       accounts to speak.
+
+2005-05-07  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/numnicks.c (base64toip): Fix bugs in parsing IPv6
+       addresses.
+       * ircd/test/ircd_in_addr_t.c (test_addrs): Add new entry.
+       (test_address): Test base64toip() as well.
+
+2005-05-05  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/s_user.c (umode_str): Only clear the operator flag when not
+       propagating; never set it.
+
+2005-05-04  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/channel.c (joinbuf_join): Include channel manager flag in
+       determination of oplevel.  If opping the user for a non-local
+       non-create, include oplevel in message to other servers.  Send
+       "MODE +o <client>" to local users whenever opping the client.
+
+       * ircd/m_join.c (m_join): Remove logic that moved into
+       joinbuf_join().
+       (ms_join): Look for level 0 and 1 joins from remote servers
+       and adjust value of 'flags' appropriately.
+
+2005-05-04  Michael Poole <mdpoole@troilus.org>
+
+       * include/numeric.h: Remap oplevel numerics to new range.
+
+       * ircd/s_err.c: Likewise.
+
+2005-05-03  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/s_stats.c (stats_access): Update to use new CONF_CLIENT
+       fields, fixing crash found by nighty.
+
+2005-05-02  Michael Poole <mdpoole@troilus.org>
+
+       * include/numeric.h (ERR_UPASS_SAME_APASS): New error message when
+       trying to set +U pass to the same as the +A pass.
+
+       * ircd/channel.c (mode_parse_upass): Use it.
+
+       * ircd/ircd_auth.c (iauth_exit_client): Only send ExitUser if
+       there is an active IAuth connection, fixing PR#1193808.
+       (iauth_dispose_request): Only delete the timer if it is active.
+
+       * ircd/m_invite.c (m_invite): Always forward the invite in the
+       correct direction, and then skip it as 'one' if announcing.
+       (ms_invite): Likewise.
+
+       * ircd/numnicks.c (base64toip): Do not interpret AAAAAA as
+       ::ffff:0.0.0.0; keep it as ::.
+
+       * ircd/s_err.c (replyTable): Add ERR_UPASS_SAME_APASS.
+
+2005-05-01  Michael Poole <mdpoole@troilus.org>
+
+       * doc/readme.log: Document IAUTH log target, remove docs for
+       OLDLOG log target.
+
+       * include/ircd_log.h: Add LS_IAUTH target, remove LS_OLDLOG.
+
+       * ircd/ircd_log.c (logDesc): Likewise.
+
+       * ircd/engine_epoll.c (engine_loop): Handle EPOLLHUP for all
+       sockets (e.g. when connecting) and do not generate read/write
+       events in the same pass as error or EOF events.
+
+       * ircd/ircd_auth.c: Convert old sendto and debug messages to use
+       the LS_IAUTH log target.  Consistently use IAUTH_CONNECTED flag
+       instead of comparing fd to -1.
+       (iauth_reconnect): If already connected, disconnect and schedule a
+       reconnect later, since an immediate reconnect can cause assertion
+       failure in the event engine.  Also schedule a reconnect when the
+       connection attempt fails.
+       (iauth_read): Reconnect on IO_FAILURE.
+       (iauth_sock_callback): Disconnect and schedule a reconnect on both
+       error (after reporting the error) and EOF.
+       (iauth_start_client): Record the IAuth request in the client.
+       (iauth_exit_client): Report the client exit.
+
+       * ircd/s_misc.c (exit_one_client): Fix formatting.
+
+2005-04-30  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/ircd_auth.c (iauth_connect): Initialize (but do not add)
+       timer here and set fd to -1.
+       (iauth_schedule_reconnect): Rewrite to handle previously
+       initialized timer.
+       (iauth_reconnect): If server is connected, disconnect first.
+       Update socket generator fd before calling socket_add().
+       (iauth_read): When reading 0 bytes (EOF), reconnect.
+
+2005-04-27  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/ircd_parser.y: Report non-existent class names as errors
+       earlier, and do not fall back to "default" for Client blocks.
+
+2005-04-25  Reed Loden  <reed@reedloden.com>
+
+       * ircd/ircd_lexer.l: Add missing header to squash a warning.
+
+2005-04-25  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/s_user.c (register_user): Replace call with set_user_mode()
+       with a direct parsing of user modes.  To match this, revert the
+       initial display of usermode to how it was done before.
+
+2005-04-24  Michael Poole <mdpoole@troilus.org>
+
+       * doc/example.conf: Document new autoconnect field of Connect.
+
+       * include/s_conf.h: Add CONF_AUTOCONNECT and field for it.
+
+       * ircd/ircd.c (try_connections): Skip non-autoconnect servers.
+
+       * ircd/ircd_lexer.l: Recognize autoconnect token.
+
+       * ircd/ircd_parser.y: Add autoconnect= option to Connect block.
+
+       * ircd/m_invite.c (m_invite): Avoid sending channel timestamp to
+       user being invited.
+       (ms_invite): Likewise.
+
+       * ircd/s_user.c (register_user): Show class name rather than
+       pointer-as-integer.
+
+2005-04-24  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/ircd_parser.y: Rewrite so each error condition gets its own
+       error message, and so that invalid parameters are printed out.
+
+2005-04-23  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/channel.c (apply_ban): Consistently free newban->banstr
+       when the function fails.
+       (mode_process_bans): Free banstr for all BAN_DEL bans.
+
+       * ircd/ircd_parser.y: Fix a few memory leaks from previous commit.
+
+2005-04-23  Michael Poole <mdpoole@troilus.org>
+
+       * include/patchlevel.h: Bump to being a beta.
+
+       * ircd/ircd_lexer.l (QSTRING): Return a copy of the string so that
+       parser actions don't have to be immediately after a QSTRING.
+
+       * ircd/ircd_parser.y (FNAME): Remove unused token.
+       (QSTRING): Adjust for QSTRING being an already-copied version.
+
+2005-04-23  Michael Poole <mdpoole@troilus.org>
+
+       * doc/example.conf (UWorld): Illustrate new config extension.
+
+       * ircd/ircd_parser.y (uworldblock): Do the expected thing when
+       multiple name= entries are present.
+
+2005-04-22  Michael Poole <mdpoole@troilus.org>
+
+       * RELEASE.NOTES: Silence exceptions use ~, not -.  Oops!
+
+       * doc/example.conf: Fix typo in example Kill block.
+
+       * ircd/channel.c (mode_parse_ban): Use correct test for flag_p.
+
+       * ircd/m_silence.c (apply_silence): Make mask pretty so that later
+       processing does not convert * to @ (and match no one).
+
+2005-04-21  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/m_userip.c (userip_formatter): /userip should *never*
+       report the user's real IP unless its answering the user
+       him/herself
+
+       * ircd/m_userhost.c (userhost_formatter): /userhost should *never*
+       report the user's real host unless its answering the user
+       him/herself
+
+2005-04-20  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/ircd.c (parse_command_line): Update usage text.
+
+       * ircd/numnicks.c (base64toip): Use v4mapped address range instead
+       of v4compat address range, fixing IPv4-based /who.
+
+2005-04-19  Michael Poole <mdpoole@troilus.org>
+
+       * configure.in: When --enable-profile, add -pg to LDFLAGS.
+
+       * configure: Regenerate.
+
+2005-04-19  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/match.c (check_if_ipmask): Fix brown-paper-bag typo.
+
+       * ircd/s_conf.c (conf_debug_iline): Look for matching Kill blocks
+       once a matching Client block is found.
+
+       * ircd/m_whowas.c (m_whowas): Change strcmp() to ircd_strcmp().
+
+2005-04-18  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/match.c (check_if_ipmask): Do not interpret masks that
+       start with . or / as IP-based host masks.
+
+2005-04-17  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/channel.c (mode_process_clients): Only prohibit deops of
+       users with the same or higher oplevel where apass is set.
+       Likewise, when opping users, give them MAXOPLEVEL for non-apass
+       channels.
+       (joinbuf_join): Give new ops MAXOPLEVEL for non-apass channels.
+
+       * ircd/m_kick.c (m_kick): Only prohibit kicks of users with the
+       same or higher oplevel where apass is set.
+
+       * ircd/s_user.c (register_user): Fix order of server version vs
+       various mode strings.
+
+       * tools/linesync/linesync.sh: Add revision id field.
+
+2005-04-17  Michael Poole <mdpoole@troilus.org>
+
+       * tools/linesync/linesync.sh: Fix typo comment.  Check for
+       multiple blocks per line in the linesync input.
+
+2005-04-17  Dan <daniel@undernet.org>
+
+       * tools/linesync/linesync.sh: Update to support new syntax and to
+       avoid rehashing the ircd when the config is the same.
+
+       * tools/linesync/linesync.conf: Update allowed conf items.
+
+2005-04-16  Michael Poole <mdpoole@troilus.org>
+
+       * doc/example.conf (Kill): Document newly supported syntax.
+
+       * include/s_conf.h (DenyConf): Split realname mask into its own
+       field.  Remove the unused DENY_FLAGS_{IP,REALNAME}.
+
+       * ircd/ircd_parser.y (Kill): Only require one of usermask,
+       hostmask, realmask to be set for a valid block.
+       (killitem): Add new production killusername.
+
+       * ircd/s_conf.c (conf_erase_deny_list): Free realmask field.
+       (find_kill): Rearrange slightly to clarify control flow.
+
+       * ircd/s_err.c (RPL_STATSKLINE): Stick usermask before hostmask,
+       so the old usermask field can be adopted for realname mask.  Add
+       double quotes around the realmask field.
+
+       * ircd/s_stats.c (report_deny_list): Do so.
+       (stats_klines): Likewise.
+
+2005-04-17  Perry Lorier <isomer@undernet.org>
+       
+       * tools/convert-conf.py: Fix lots of conversion problems with
+       oper privielges (now they are converted), 
+       features (deprecated features commented out, most converted to
+       priviliges), 
+       realname klines (also add host= lines)
+       quarintines (generate blocks for them), 
+       connect blocks (don't generate empty port config lines)
+       etc...
+
+2005-04-16  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/gline.c (do_gline): Fix typo when activating IP-based
+       G-lines.
+
+2005-04-16  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/class.c (free_class): Free default_umode field.
+
+       * ircd/ircd_parser.y (classblock): Free default_umode field before
+       overwriting it.
+
+       * ircd/s_conf.c (free_conf): Free username, origin_name, hub_limit
+       fields.
+       (find_kill): Realname Kill blocks no longer have $R at the start,
+       so do not skip over the first two characters of the mask.
+
+2005-04-15  Michael Poole <mdpoole@troilus.org>
+
+       * doc/example.conf (Operator): Properly qualify plaintext password.
+       (Quarantine): Document (new) syntax.
+
+       * ircd/ircd.c: Add <sys/time.h> to make <sys/resource.h> compile
+       correctly on BSDs.
+
+       * ircd/ircd_parser.y (qconf): Remove global variable.
+       (killuhost): Null terminate username when present.
+       (quarantineblock): Replace with a syntax that works.
+
+       * ircd/s_stats.c: #include <querycmds.h> for UserStats.
+       (stats_server_verbose): Reinstate check for UserStats.
+
+2005-04-09  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/ircd.c: conditionally include sys/resource.h; otherwise,
+       RLIMIT_CORE will not be defined and so set_core_limit() will never
+       be defined, much less run.
+
+       * configure.in: add sys/resource.h to the list of headers to
+       search for
+
+       * configure: regenerate configure
+
+       * config.h.in: rerun autoheader to add HAVE_SYS_RESOURCE_H to
+       config.h.in
+
+2005-04-08  Michael Poole <mdpoole@troilus.org>
+
+       * include/s_conf.h (conf_debug_iline): Declare new function.
+
+       * ircd/ircd.c (dbg_client): New file-scoped variable.
+       (parse_command_line): Set it from the new -c option.
+       (main): If dbg_client is set during chkconf, use it.
+
+       * ircd/ircd_string.c (ircd_aton): Generate IPv4-mapped addresses,
+       not IPv4-compatible addresses, to match ipmask_parse().
+
+       * ircd/m_whowas.c (m_whowas): Split display of real host to a
+       separate line, in hopes of not confusing opers in the future.
+
+       * ircd/s_conf.c (conf_debug_iline): Implement new function.
+
+2005-04-06  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/m_burst.c (ms_burst): Clear channel manager bit when wiping
+       out locally opped and voiced channel members.
+
+2005-04-06  Michael Poole <mdpoole@troilus.org>
+
+       * include/numeric.h (RPL_APASSWARN): Replace with three distinct
+       values.
+       (ERR_NOMANAGER_LONG): Assign new numeric.
+       (ERR_NOMANAGER_SHORT): Assign new numeric.
+
+       * ircd/channel.c (parse_mode_upass): Adapt to new formats for
+       ERR_NOTMANAGER separation.
+       (parse_mode_apass): Likewise.  Also adapt to RPL_APASSWARN split.
+
+       * ircd/s_err.c (RPL_APASSWARN): Replace with three message
+       strings, to avoid embedding long message strings in the logic
+       implementation.
+       (ERR_NOTMANAGER): Likewise (but not the same strings).
+
+2005-04-06  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/ircd_parser.y (clientblock): Use the password field.
+
+       * ircd/s_user.c (register_user): Allow aconf->password to be a
+       single digit, since per-IP limit is now in a separate field.
+
+2005-04-06  Michael Poole <mdpoole@troilus.org>
+
+       * acinclude.m4 (unet_PIPE_CFLAGS): Remove; -pipe is obsolete in
+       current gcc releases and is slower than files for previous
+       releases on most OSes.
+
+       * configure.in (AC_PREREQ): Bump to 2.59 because of AS_HELP_STRING.
+       (unet_PIPE_CFLAGS): Remove use of macro.
+
+       * aclocal.m4: Regenerate.
+
+       * configure: Likewise.
+
+2005-04-04  Michael Poole <mdpoole@troilus.org>
+
+       * configure.in: For developers' ease, allow passing an option to
+       configure to persistently set optimization CFLAGS.
+
+       * configure: Regenerate.
+
+2005-04-04  Michael Poole <mdpoole@troilus.org>
+
+       * doc/example.conf (Jupe): Make the default Jupe block follow
+       CFV-0255.  (Thanks to FrankP for pointing me at this and to DinTn
+       for getting me a copy of the CFV.)
+
+2005-04-04  Michael Poole <mdpoole@troilus.org>
+
+       * include/capab.h (CAPFL_STICKY): Define.
+       (CAPLIST): Remove the entries used for testing.
+
+       * include/client.h (Connection): Clarify comment about the
+       distinction between con_capab and con_active.
+
+       * ircd/m_cap.c: Add doxygen comments and replace the long
+       discussion of m_handler functions with an xref to it.
+       (send_caplist): Add new parameters and change the terminal vs
+       non-terminal line distinction to make compliant with current draft
+       specification.
+       (cap_empty): Rename to cap_ls().
+       (cap_req): Track modified capabilities bitwise, so that the
+       responding ACK contains all the appropriate flags.
+       (cap_ack): Add comment explaining why there is no response.
+       (cap_clear): Build and send a list of cleared capabilities, as
+       required by the current draft.
+       (cap_list): Send capability list using LIST subcommand.
+       (cmdlist): Add handler for LS subcommand.  Remove entries for the
+       empty and LSL subcommands, which are no longer allowed.
+       (m_cap): Require at least one argument from user.
+
+2005-04-01  Michael Poole <mdpoole@troilus.org>
+
+       * include/s_conf.h (SMAP_FAST): Define.
+       (s_map): Add 'flags' field.
+
+       * ircd/ircd_lexer.l: Recognize 'FAST' token.
+
+       * ircd/ircd_parser.y (FAST): New token.
+       (pseudoitem): Add pseudoflags alternative.
+       (pseudoflags): New production, recognizing FAST token.
+
+       * ircd/parse.c (register_mapping): Set MFLG_SLOW conditionally.
+       Remove outdated comment.
+
+2005-04-01  Michael Poole <mdpoole@troilus.org>
+
+       * include/handlers.h (ms_privs): Declare.
+
+       * include/msg.h (TOK_PRIVS): Assign token.
+       (CMD_PRIVS): Define.
+
+       * ircd/m_privs.c: Add doxygen comments and replace the long
+       discussion of m_handler functions with an xref to it.
+       (mo_privs): Forward requests for non-local users
+       to their own server.
+       (ms_privs): Implement.
+
+       * ircd/parse.c (PRIVS): Dispatch to ms_privs when a server sends
+       the message.
+
+2005-03-30  Michael Poole <mdpoole@troilus.org>
+
+       * include/client.h (struct Client): Explain where cli_username
+       comes from.
+
+       * include/struct.h (struct User): Explain where this username
+       comes from, too
+
+       * ircd/ircd_res.c (timeout_resolver): Update parameter name in
+       Doxygen comment, too.
+
+       * ircd/s_misc.c (get_client_name): Reorganize to have less
+       indentation and behave like 2.10.11 when client is not idented.
+
+2005-03-29  Michael Poole <mdpoole@troilus.org>
+
+       * doc/example.conf: Remove no-longer-used HIS_STATS_h.
+
+       * doc/readme.features: Likewise.
+
+       * include/ircd_features.h: Likewise.
+
+       * ircd/ircd_features.c: Likewise.
+
+2005-03-20  Reed Loden <reed@reedloden.com>
+
+       * include/ircd_features.h: Alphabetize HIS_STATS_? features.
+
+       * ircd/ircd_features.c: Likewise.
+
+2005-03-29  Michael Poole <mdpoole@troilus.org>
+       (The previously unapplied part of another patch (by Carlo Wood?).)
+
+       * ircd/m_part.c (ms_part): Remove a check that should already be
+       done by the user's own server.
+
+2005-03-29  Michael Poole <mdpoole@troilus.org>
+
+       * doc/example.conf: Add HIS_STATS_J entry.
+
+       * doc/readme.features: Likewise.
+
+2005-03-25  Reed Loden <reed@reedloden.com>
+
+       * include/hash.h: Add needed prototypes for new
+       stats_nickjupes() function.
+
+       * include/ircd_features.h: Add FEAT_HIS_STATS_J.
+
+       * include/numeric.h: Add RPL_STATSJLINE (222) for new nick
+       jupes stats. Correct a typo in a comment.
+
+       * ircd/hash.c: Add stats_nickjupes() function to report all
+       nick jupes to an oper. Because of the nature of hash tables,
+       there is no way to sort this list so the results look weird.
+
+       * ircd/ircd_features.c: Add FEAT_HIS_STATS_J (default: TRUE).
+
+       * ircd/s_err.c: Add RPL_STATSJLINE (222) for new nick jupes
+       stats.
+
+       * ircd/s_stats.c: Add RPL_STATSJLINE (222) for new nick jupes
+       stats. Make 'j' case sensitive. Modify the comment for stats
+       uworld.
+
+2005-03-27  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/m_burst.c (ms_burst): Do not send numeric oplevels in a -A
+       channel when forwarding a channel burst line.
+
+2005-03-25  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/m_server.c (set_server_flags): New function.  Unlike the
+       old code, this recognizes the IPv6 flag.  (Spotted by Reed.)
+       (mr_server): Use the new function.
+       (ms_server): Likewise.  Also don't show "Net junction:" message if
+       any closer server is still bursting (also spotted by Reed).
+       Finally, forward the +6 flag to other servers.
+
+       * ircd/s_serv.c (server_estab): Forward the +6 flag here, too.
+
+       * ircd/s_bsd.c (client_sock_callback): Re-set cli_error() after it
+       may be cleared by completed_connection().
+
+2005-03-23  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/m_burst.c (ms_burst): Remove limit and keys when a channel
+       is wiped out during burst.
+
+2005-03-22  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/ircd_res.c (check_resolver_timeout): I give up.  Use the
+       kludgy earlier version of the timeout fix.
+
+2005-03-22  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/channel.c (send_channel_modes): Fix test for when to send
+       membership mode suffix, to avoid sending it more than once.
+
+2005-03-22  Michael Poole <mdpoole@troilus.org>
+       (Many thanks to nex and Reed for helping hunt this down and
+       doing the testing of various patches.)
+
+       * ircd/ircd_events.c (timer_chg): Properly change a timer that is
+       in the middle of executing its expiration event.
+
+       * ircd/ircd_res.c (check_resolver_timeout): Simplify the test for
+       whether to use timer_chg() or timer_add().
+       On second thought, use timer_add() unconditionally; the server
+       connection loop does.
+       (timeout_resolver): Do not try to re-schedule the DNS timeout
+       unless it is the expiration event.
+       (do_query_number): Properly initialize request->state.
+       (res_readreply): Mention the response code that was bad.
+
+2005-03-22  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/engine_kqueue.c (engine_delete): The kernel removes
+       close()'d FDs from the activity list, so don't try to remove the
+       FD here (the caller may have already close()'d it).
+
+2005-03-20  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/IPcheck.c: Fix typos in comments and strings to reduce
+       future slumming for credit.
+
+       * ircd/channel.c, ircd/crule.c, ircd/engine_epoll.c: Likewise.
+       * ircd/fileio.c, ircd/hash.c, ircd/ircd.c: Likewise.
+       * ircd/ircd_auth.c, ircd/ircd_crypt.c: Likewise.
+       * ircd/ircd_crypt_native.c, ircd/ircd_crypt_smd5.c: Likewise.
+       * ircd/ircd_features.c, ircd/ircd_log.c: Likewise.
+       * ircd/ircd_parser.y, ircd/ircd_res.c: Likewise.
+       * ircd/ircd_reslib.c, ircd/ircd_string.c, ircd/list.c: Likewise.
+       * ircd/m_burst.c, ircd/m_clearmode.c, ircd/m_destruct.c: Likewise.
+       * ircd/m_invite.c, ircd/m_ison.c, ircd/m_kill.c: Likewise.
+       * ircd/m_server.c, ircd/m_squit.c, ircd/m_topic.c: Likewise.
+       * ircd/m_who.c, ircd/m_whois.c, ircd/m_whowas.c: Likewise.
+       * ircd/match.c, ircd/msgq.c, ircd/numnicks.c: Likewise.
+       * ircd/os_generic.c, ircd/parse.c, ircd/s_auth.c: Likewise.
+       * ircd/s_bsd.c, ircd/s_conf.c, ircd/s_debug.c: Likewise.
+       * ircd/s_misc.c, ircd/s_numeric.c, ircd/s_serv.c: Likewise.
+       * ircd/s_stats.c, ircd/s_user.c, ircd/table_gen.c: Likewise.
+       * ircd/umkpasswd.c, ircd/uping.c, ircd/whowas.c: Likewise.
+
+       * ircd/test/test_stub.c: Make exit_client() argument list
+       consistent with that in s_misc.c so doxygen is not confused.
+
+2005-03-20  Michael Poole <mdpoole@troilus.org>
+       (Thanks to Reed Loden for pointing these out.)
+
+       * ircd/channel.c: Fix typos in comments.
+
+       * ircd/m_create.c: Likewise.
+
+       * ircd/m_list.c: Likewise.
+
+       * ircd/m_names.c: Likewise.
+
+       * ircd/numnicks.c: Likewise.
+
+       * ircd/s_bsd.c: Likewise.
+
+2005-03-20  Michael Poole <mdpoole@troilus.org>
+       (Thanks to Reed Loden for pointing these out.)
+
+       * doc/Configure.help: Remove outdated file.
+
+       * doc/exaconf.2: Likewise.
+
+       * doc/snomask.html: Add missing <tr>, SNO_AUTO, SNO_DEBUG, and
+       update SNO_OPERDEFAULT list.
+
+       * tools/mkpasswd.c: Remove outdated file (use ircd/umkpasswd
+       instead).
+
+       * tools/Makefile.crypt: Remove outdated file.
+
+       * tools/mkpasswd.c: Likewise.
+
+       * tools/transition: Likewise.
+
+2005-03-19  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/channel.c (sub1_from_channel): Check apass rather than mode
+       to determine whether an apass is set (MODE_KEY/APASS/UPASS are not
+       set in mode.mode).
+       (send_channel_modes): Use the same change when determining how to
+       send oplevels for channels.
+
+2005-03-19  Michael Poole <mdpoole@troilus.org>
+
+       * include/IPcheck.h (IPcheck_connect_fail): Take a Client
+       parameter instead of irc_in_addr.
+
+       * ircd/IPcheck.c (IPcheck_connect_fail): Likewise.  Assert that
+       the client has been IP-checked.
+       (IPcheck_remote_connect): Assert that the client has not yet been
+       charged for connecting.
+       (IPcheck_connect_succeeded): Assert that the client has been
+       charged for connecting.
+       (IPcheck_disconnect): Likewise.
+
+       * ircd/m_nick.c (m_nick): Pass rejected client to
+       IPcheck_connect_fail() when somebody takes the nick first.
+       (ms_nick): Likewise.
+
+       * ircd/s_serv.c (server_estab): Pass new server to
+       IPcheck_connect_fail().
+
+       * ircd/s_user.c (register_user): When rejecting a user, pass
+       the struct Client to IPcheck_connect_fail().
+
+2005-03-19  Michael Poole <mdpoole@troilus.org>
+
+       * doc/example.conf (Connect): Remove a buggy comment about leaf
+       directives; refer the reader to the Connect block instead.
+
+       * tools/convert-conf.py: Set "leaf;" rather than "leaf = yes;"
+
+2005-03-19  Michael Poole <mdpoole@troilus.org>
+
+       * doc/example.conf (Operator): Correct the comment explaining
+       hashed passwords.
+
+       * ircd/m_oper.c (oper_password_match): Check correct variable to
+       determine whether the hashed password matched.
+
+2005-03-08  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/match.c (ipmask_parse): Explicitly zero-initialize the mask
+       and bit count for "*".
+       (ipmask_check): Make more robust to similar errors.
+
+2005-03-07  Michael Poole <mdpoole@troilus.org>
+
+       * configure.in: Consistently use a constant in AC_DEFINE().
+
+       * configure: Regenerate.
+
+       * doc/example.conf (Port): Add comment about the mask option.
+       (Port): Fix the vhosted Port example.
+
+       * ircd/ircd_parser.y (clientblock): Correctly initialize the IP
+       address and addrbits for a Client block with no IP mask.
+
+       * ircd/match.c (ipmask_parse): Accept * as a zero-bit mask.
+
+       * ircd/s_auth.c (start_auth_query): Count socket allocation
+       failure as a failed auth check, as .11 does.
+
+       * ircd/s_debug.c (debug_serveropts): Add '6' to server options
+       when compiled with IPv6 support.
+
+2005-02-23  Michael Poole <mdpoole@troilus.org>
+
+       * doc/example.conf: Explain apass_opmode privilege, pointing out
+       that, unlike previous privs, the default is OFF for global opers.
+
+       * include/client.h (PRIV_APASS_OPMODE): Define new privilege.
+
+       * ircd/channel.c (mode_parse_upass): Only prevent local opers
+       without the apass_opmode privilege from forcing a +U change.
+       (mode_parse_apass): Likewise, for +A.
+
+       * ircd/client.c (client_set_privs): Turn off PRIV_APASS_OPMODE in
+       the default privileges for global opers.
+
+       * ircd/ircd_lexer.l (apass_opmode): Recognize keyword.
+
+       * ircd/ircd_parser.y (TPRIV_APASS_OPMODE): New token.
+       (privtype): Fix typo for local_badchan privilege value.
+       Accept apass_opmode token.
+
+2005-02-23  Michael Poole <mdpoole@troilus.org>
+
+       * doc/example.conf: Fix comment's description of "whox" privilege.
+
+2005-02-21  Michael Poole <mdpoole@troilus.org>
+
+       * include/channel.h (ShowChannel): Remove PRIV_LIST_CHAN check
+       from here, so /whois does not show secret global channels.
+
+       * ircd/m_list.c (param_parse): Require PRIV_LIST_CHAN to use
+       "/list s".
+       (m_list): Allow opers with PRIV_LIST_CHAN to see secret channels.
+
+2005-02-21  Perry Lorier <isomer@undernet.org>
+
+       * ircd/s_stats.c: Hide the hub IP's.  They're kinda important.
+
+2005-02-20  Perry Lorier <isomer@undernet.org>
+
+       * ircd/ircd_parser.y: Moved some parse errors from log_write()'s to
+       parse_error()'s so that ./ircd -k will display them.  Also clarified
+       the warning about oper blocks.
+
+2005-02-20  Perry Lorier <isomer@undernet.org>
+
+       * tools/convert-conf.py: A multitude of changes to deal with parsing
+       mistakes, generate a newer config file, better error handling,
+       being smarter about what config elements you generate etc.
+       
+2005-02-20  Perry Lorier <isomer@undernet.org>
+
+       * ircd/engine_epoll.c: Change a size_t to socklen_t to match
+       getsockopt prototype, so it compiles without warning on amd64
+
+2005-02-19  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/ircd_parser.y (clientblock): Parse IP address before
+       allocating ConfItem; if the parse fails, generate an error.
+
+       * ircd/s_err.c (RPL_STATSCLINE): Add format field to prefix IPv6
+       addresses starting with ':'.
+       (RPL_STATSILINE): Likewise.
+       (RPL_STATSOLINE): Add format field for username.
+
+       * ircd/s_stats.c (stats_configured_links): Pass the appropriate
+       argument for the RPL_STATSxLINE changes.
+       Change RPL_STATSILINE to use * instead of <NULL> when IP or host
+       is null.
+
+2005-02-18  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/IPcheck.c (ip_registry_find): Use canonical form of IP
+       address to look up and compare against hash entries.
+
+       * ircd/channel.c (apply_ban): Do not free a succesful BAN_DEL ban.
+
+       * ircd/ircd_parser.y (clientblock): Stash IP string in aconf->name.
+       (clienthost): Split hosts that contain '@' into username and host.
+       (clientip): Split IPs that contain '@' into username and IP.
+       (killreason): Add missing ~ to mask off DENY_FLAGS_FILE.
+
+       * ircd/m_silence.c (forward_silences): When we reject a silence,
+       splice it out of the ban list.  Warn the user if he is local.
+
+       * ircd/s_bsd.c (connect_inet): Set IP TOS for outbound server
+       connections.
+
+       * ircd/s_stats.c (stats_configured_links): Display correct field
+       when listing CONF_UWORLD entries.
+
+2005-02-09  Michael Poole <mdpoole@troilus.org>
+
+       * configure.in (YACC): Only warn if we cannot get a version number
+       from $YACC.
+
+       * configure: Regenerate.
+
+       * ircd/ircd_res.c (check_resolver_timeout): Try another way to
+       avoid timer_chg() on a non-queued/active timer.
+
+       * ircd/ircd_string.c (ircd_aton): Set part_start to handle input
+       strings like "::127.0.0.1".
+
+       * ircd/test/ircd_in_addr_t.c (test_addrs): Add a test for that.
+
+2005-02-02  Michael Poole <mdpoole@troilus.org>
+
+       * Makefile.in (install): Do not create ${prefix}/include since it
+       is no longer used.
+
+       * ircd/Makefile.in (install-*): Remove commented-out code to touch
+       and chown MPATH and RPATH.
+
+       * ircd/gline.c (gline_find): Allow searching for host-based
+       G-lines by plain hostname (not *@host), thus preventing "GLINE
+       test ..." from inserting duplicate G-lines.
+
+       * ircd/motd.c (motd_create): Null out new Motd's hostmask when
+       appropriate, avoiding an uninitialized or stale pointer.
+
+2005-01-26  Michael Poole <mdpoole@troilus.org>
+
+       * include/ircd_alloc.h (DoMallocZero): Parenthesize macro
+       arguments, fixing operator precedence problems.
+       (DoFree): Make debug version also overwrite p.
+
+       * include/memdebug.h (fda_get_byte_count, fda_get_block_count):
+       Declare functions used outside memdebug.c.
+
+       * ircd/Makefile.in (UMKPASSWD_SRC): Add memdebug.c.
+
+       * ircd/ircd_alloc.c (DoMalloc, DoMallocZero, DoRealloc): Do not
+       use these if using the memdebug version.
+
+       * ircd/memdebug.c: #include "send.h" and <string.h> to get
+       declarations for certain functions.
+
+       * ircd/umkpasswd.c (CurrentTime): Define in case of memdebug.
+       (sendto_opmask_butone): Likewise.
+
+2005-01-25  Michael Poole <mdpoole@troilus.org>
+
+       * configure.in: Fix typos and thinkos in previous commut.
+
+       * configure: Regenerate.
+
+       * doc/example.conf: Change class name in Connect block to be
+       consistent with earlier Class block.
+
+       * ircd/ircd.c (try_connections): Consider Connect blocks with hold
+       time of 0.  Fix Links() vs MaxLinks() comparison to reflect ref
+       count starting at 1.
+
+       * ircd/ircd_parser.y (cruleblock, iauthblock): Clear unused
+       variables after use.
+
+2005-01-24  Michael Poole <mdpoole@troilus.org>
+
+       * configure.in: Make sure that $LEX and $YACC are reasonable and
+       actually run.
+
+       * configure: Regenerate.
+
+       * ircd/ircd_res.c (check_resolver_timeout): Use correct macro to
+       test whether the timer is already pending.
+
+2005-01-23  Michael Poole <mdpoole@troilus.org>
+
+       * doc/example.conf (Kill): Fix typo in realname Kill block
+
+       * include/client.h (infousermodes): Fix typo in comment.
+
+       * ircd/ircd.c (parse_command_line): -k implies BOOT_TTY.
+       (main): Move daemon_init() before event_init() to work around BSD
+       lameness.
+
+2005-01-23  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/test/Makefile.in: Add missing "install" target.  Make
+       compatible with BSD make (which has no $^ and no $(CPPFLAGS) in
+       its default .c.o rule).
+
+2005-01-21  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/engine_kqueue.c: Move <sys/types.h> earlier to fix build on
+       FreeBSD 5.x (which needs it for <sys/event.h>).
+
+       * ircd/fileio.c (fbopen): Replace BSDism S_IREAD, S_IWRITE with
+       portable equivalents.
+
+       * ircd/ircd_log.c (log_open): Likewise.
+
+       * ircd/os_generic.c (_XOPEN_SOURCE): Increase to 600 (SuSv3?) so
+       that IPv6 definitions become visible on FreeBSD 5.3.
+
+       * ircd/s_auth.c: Remove apparently unused <sys/file.h> because
+       it fails to compile on FreeBSD 5.3.
+
+2005-01-22  Perry Lorier <isomer@undernet.org>
+
+       * ircd/ircd_parser.y: Fix missing ;
+
+2005-01-19  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/m_invite.c (m_invite, ms_invite): Include timestamp in
+       outbound INVITE messages.  On incoming INVITEs, ignore if the
+       timestamp is too recent or if the timestamp is missing and the
+       peer server is in burst.
+
+2005-01-15  Michael Poole <mdpoole@troilus.org>
+
+       * RELEASE.NOTES: Mention CIDR support for Client, Operator, bans
+       and silences.  Mention net.rider kick change.
+
+       * doc/example.conf (Class): Add documentation for restart and
+       local_opmode privileges.  Fix name of local_jupe privilege.
+
+       * ircd/ircd_lexer.l: Recognize local_opmode privilege.
+
+2005-01-14  Michael Poole <mdpoole@troilus.org>
+
+       * RELEASE.NOTES: Further updates (mention Pseudo blocks, clarify
+       CAP comment, mention named /stats, list config heteromorphisms.
+
+       * doc/readme.features: Document HIS_STATS_a, HIS_STATS_L,
+       HIS_STATS_R, LOCAL_CHANNELS, TOPIC_BURST.
+
+       * ircd/channel.c (mode_parse_apass): Change old mention of +u mode
+       to say +U.
+
+2005-01-13  Michael Poole <mdpoole@troilus.org>
+
+       * RELEASE.NOTES: Update for 2.10.12.
+
+2005-01-08  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/channel.c (@page zombie): Add synopsis to explain what
+       zombies are supposed to do.
+
+       * doc/example.conf (Features): Transfer recommended LOG features
+       from 2.10.11 example.conf.
+
+2005-01-03  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/ircd.c (try_connections): Test Connect hold time before
+       updating it (spotted by Kev).
+
+2005-01-03  Michael Poole <mdpoole@troilus.org>
+
+       * Makefile.in: Add ircd/test as a subdirectory.
+
+       * ircd/.cvsignore: Ignore umkpasswd binary.
+
+       * ircd/Makefile.in: Update dependencies.
+
+       * ircd/test/.cvsignore: New file.
+
+       * ircd/test/Makefile.in: Use ${} instead of $().  Add build,
+       depend, distclean targets to integrate with rest of build system.
+
+2005-01-03  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/IPcheck.c (ip_registry_check_remote): Do not count clones
+       that have an invalid IP address.
+
+       * ircd/ircd.c (try_connections): Update Connect hold time before
+       skipping it, to prevent infinite loops.
+
+2005-01-03  Kevin L Mitchell  <klmitch@mit.edu>
+
+       * ircd/s_user.c (is_silenced): is_silenced() would core if sptr
+       was a server; fixed to skip servers
+
+2004-12-28  Michael Poole <mdpoole@troilus.org>
+
+       * include/s_bsd.h (VirtualHost): Replace with separate variables
+       for IPv4 and IPv6 virtual hosts.
+
+       * include/uping.h (uping_echo): Remove declaration.
+
+       * ircd/ircd_auth.c (iauth_reconnect): Select VirtualHost_v4 or
+       VirtualHost_v6 based on iauth server address family.
+
+       * ircd/ircd_lexer.l: Do not recognize RESOLVER token.
+
+       * ircd/ircd_parser.y (ResolverAddr): Remove declaration.
+       (RESOLVER): Remove definition.
+       (generalresolver): Remove.
+       (generalvhost): Assign address to either VirtualHost_v4 or
+       VirtualHost_v6, depending on format.
+
+       * ircd/ircd_res.c (res_socket): Replace with separate variables
+       for IPv4 and IPv6 resolver sockets.
+       (ResolverAddr): Remove definition.
+       (restart_resolver): Attempt to set up both IPv4 and IPv6 sockets.
+       (send_res_msg): Select outbound FD based on resolver address type.
+       (res_readreply): Recognize either inbound socket FD.
+
+       * ircd/os_generic.c (sockaddr_from_irc): Require irc != NULL.
+       (os_socket): Require local != NULL.
+
+       * ircd/s_bsd.c (VirtualHost): Replace with separate variables
+       for IPv4 and IPv6 virtual hosts.
+       (connect_inet): Select virtual host based on destination address.
+
+       * ircd/uping.c (UPingFIleDescriptor): Remove.
+       (upingSock): Split into separate IPv4 and IPv6 variables.
+       (uping_echo_callback): Incorporate uping_echo() body here, so the
+       proper socket FD can be used.
+       (uping_init): Attempt to set up both v4 and v6 UPING sockets.
+       (uping_server): Create uping socket with appropriate local address.
+
+       * doc/example.conf (General): Update example config file to
+       reflect removal of Resolver setting and support for separate IPv4
+       and IPv6 VHost settings.
+
+2004-12-28  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/sys.h (BITS_ZERO_ON_*, HAVE_RELIABLE_SIGNALS, DOCURSES,
+       DOTERMCAP, IRC_UID, IRC_GID, LIMIT_FMT, FALSE, TRUE): Remove
+       unused macros.
+
+       * ircd/ircd_auth.c, ircd/listener.c, ircd/s_auth.c, ircd/s_bsd.c,
+       ircd/s_conf.c, ircd/uping.c, ircd/whocmds.c: Remove obsolete
+       #include <arpa/inet.h>.
+
+2004-12-28  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/match.c: Remove obsolete #include <arpa/inet.h>.
+       (ipmask_parse_ipv4): We already parse the dotted quads from the
+       input string, so use them instead of inet_addr() to populate
+       out->s_addr.
+
+       * ircd/gline.c: Remove obsolete #includes <arpa/inet.h>, "sys.h".
+       (do_gline): Pass SHOW_IP instead of TRUE as argument to
+       get_client_name().
+
+       * ircd/ircd.c (try_connections): Revise to use fewer temporary
+       variables.
+
+2004-12-28  Michael Poole <mdpoole@troilus.org>
+
+       * include/res.h: Implement irc_in_addr_* as macros.
+
+       * ircd/ircd_res.c: Remove the function bodies.
+
+       * ircd/ircd_string.c (irc_in_addr_is_ipv4): Remove body.
+       (ircd_ntoa_r): Do not append extra ':' when unparsing 0::.
+       (ircd_aton): Accept IPv6 addresses with all eight segments
+       specified (e.g. 0:0:0:0:0:0:0:0).  Correctly parse addresses
+       with IPv4 bits at the end (e.g. ::FFFF:127.0.0.1).
+
+       * ircd/test/ircd_in_addr_t.c, ircd/test/test_stub.c: New files.
+
+       * ircd/test/Makefile: Convert to Makefile.in for proper VPATH
+       support.  Add test_stub.c and ircd_in_addr_t.c references.
+
+       * configure.in: Generate ircd/test/Makefile as an output file.
+
+       * configure: Update.
+
+2004-12-18  Michael Poole <mdpoole@troilus.org>
+
+       * include/client.h: Move unreg, privs, capab and active fields
+       from struct Client to struct Connection since that is how they
+       are really associated.  Adjust macros to match.
+       (SetPriv, ClrPriv): New macros.
+
+       * ircd/client.c (client_set_privs): Exit earlier for remote
+       clients.  Adjust macro use to correspond.
+
+       * ircd/m_server.c (mr_server): Grant all privileges except
+       PRIV_SET to peer servers.
+
+2004-12-18  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/s_user.c (hide_hostmask): Add a missing "break;" to fix bug
+       #1087461.
+
+2004-12-18  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/engine_kqueue.c (engine_loop): Remove an assertion that the
+       socket's FD is the same after processing as it was before; local
+       clients apparently have s_fd() == -1 after close.
+
+2004-12-18  Kevin L Mitchell  <klmitch@mit.edu>
+
+       * ircd/s_user.c: make absolutely certain register_user() is never
+       called with cli_unreg non-zero; transition set_nick_name() over to
+       the new way of determining whether client is ready for
+       register_user()
+
+       * ircd/s_err.c: add ERR_UNKNOWNCAPCMD for reporting failure to
+       understand a given CAP subcommand
+
+       * ircd/parse.c: add "CAP" command
+
+       * ircd/m_user.c (m_user): transition over to new way of
+       determining whether client is ready for register_user()
+
+       * ircd/m_pong.c (mr_pong): transition over to new way of
+       determining whether client is ready for register_user()
+
+       * ircd/m_cap.c: implementation of the IRC capabilities draft
+
+       * ircd/list.c (make_client): initialize cli_unreg element of
+       client structure
+
+       * ircd/ircd_string.c: correct old bugs in ircd_strn?cmp()
+       functions that were never found because cross-case ordering has
+       not been needed until now
+
+       * ircd/Makefile.in: add m_cap.c to list of .c files
+
+       * include/numeric.h (ERR_UNKNOWNCAPCMD): define new error reply to
+       indicate an unknown CAP subcommand
+
+       * include/msg.h: add "CAP" command
+
+       * include/handlers.h: add m_cap() to list of handlers
+
+       * include/client.h: add support for client capabilities; rototill
+       the registration mechanism to dovetail well with the capability
+       system--i.e., allow the capability system to suspend registration
+       if the user issues one of the CAP commands
+
+       * include/capab.h: header file to define client capabilities
+
+2004-12-17  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/channel.h (apply_ban): Add new flag to indicate whether
+       newban should be free()'d after it is used.
+
+       * ircd/channel.c (apply_ban): Likewise.  Also set BAN_DEL flag
+       when setting BAN_OVERLAPPED, and free newban when BAN_DEL.
+       (mode_parse_ban): Delete buggy shortcut when channel banlist is
+       empty.
+       (mode_process_bans): Always give ownership of ban->banstr to the
+       mode buffer, avoiding a memory leak.
+
+       * ircd/m_silence.c (apply_silence): Pass new parameter to
+       apply_ban.
+
+2004-12-17  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/channel.c (sub1_from_channel): Immediately destroy
+       non-Apass channels when oplevels are enabled; otherwise, they can
+       stay opless for a considerable period.
+       (mode_parse_ban): Initialize banstr to NULL so that set_ban_mask()
+       does not try to free() an invalid pointer.
+
+       * ircd/ircd_parser.y (uworldblock): Put UWorld server name into
+       aconf->host, not aconf->name.
+
+       * ircd/m_server.c (mr_server, ms_server): Attach CONF_UWORLD items
+       by host here..
+
+       * ircd/s_conf.c (conf_check_server): .. rather than by name here.
+       (attach_conf_uworld): New function to attach CONF_UWORLD items.
+       (rehash): Use attach_conf_uworld() instead of attaching by name.
+
+2004-12-15  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/m_topic.c (do_settopic): Allow +k services to set topics on
+       channels they are not joined.
+
+2004-12-15  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/IPcheck.c (IPTargetEntry): Make count unsigned to squash
+       warning.
+       (ip_registry_canonicalize): New function to convert an IP address
+       into a canonical form for clone checks.
+       (ip_registry_hash): Update to reflect canonical form.
+       (ip_registry_find): Use ip_registry_canonicalize().
+       (ip_registry_check_local, ip_registry_check_remote): Likewise.
+
+       * ircd/numnicks.c (iptobase64): Map 6to4 addresses to IPv4 when
+       sending them to a non-IPv6 server.
+
+2004-02-17  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/s_user.c (hide_hostmask): Preserve user's visibility in a
+       +D channel when they hide their hostmask.
+
+2004-12-15  Michael Poole <dmpoole@troilus.org>
+
+       * doc/example.conf: Remove the example Server blocks since they
+       are no longer used (were merged into Connect).
+
+       * ircd/ircd_res.c (restart_resolver): Fix typo in previous commit.
+
+       * ircd/m_server.c (check_loop_and_lh): Use a different argument to
+       test whether an introduced server is directly connected or not.
+
+2004-12-14  Michael Poole <mdpoole@troilus.org>
+
+       * include/client.h (FLAG_IPV6): New value for enum Flag.
+       (IsIPv6, SetIPv6): Accessor macros for it.
+
+       * include/numnicks.h (iptobase64): Add flag indicating whether to
+       use full IPv6 addresses or fake them in an IPv4-compatible way.
+
+       * ircd/numnicks.c (iptobase64): Use the new flag.
+
+       * include/send.h (sendcmdto_flag_serv_butone): New function to
+       send different lines to servers based on flags (like FLAG_IPV6).
+
+       * ircd/send.c (sendcmdto_flag_serv_butone): Implement it.
+
+       * ircd/s_bsd.c (completed_connection): Advertise IPv6 support in
+       our server flags.
+
+       * ircd/s_serv.c (server_estab): Likewise.  Also make sure we send
+       compatible IP addresses for the new server.
+
+       * ircd/s_user.c (register_user): Only send full IPv6 addresses to
+       links that have FLAG_IPV6 set.
+
+2004-12-13  Michael Poole <mdpoole@troilus.org>
+
+       * doc/example.conf: Update General block comment to mention
+       new RESOLVER option and to explain IPv6 support.
+
+       * ircd/ircd_lexer.l: Recognize RESOLVER token.
+
+       * ircd/ircd_parser.y: Declare RESOLVER token and use it in an
+       alternative for generalitem.
+
+       * ircd/ircd_res.c: Define global ResolverAddr variable.  If it is
+       valid, use it instead of VirtualHost in restart_resolver().
+
+2004-12-13  Michael Poole <mdpoole@troilus.org>
+
+       * doc/example.conf: Update configuration to move Client block
+       comment after sample Class blocks, and update entries in it.
+
+       * ircd/ircd_lexer.y: Recognize IP and USERNAME tokens.
+
+       * ircd/ircd_parser.y: Add ip and username global variables and IP
+       and USERNAME tokens.  Add clientip and clientusername alternatives
+       for clientitem, and update clientblock to correspond.
+
+       * ircd/ircd_res.c (delete_resolver_queries): Do not try to walk
+       the request_list before request_list is initialized.
+       (cres_mem): Likewise.
+
+       * ircd/os_generic.c (sockaddr_from_irc): Improve guessing of
+       proper address family.
+
+       * ircd/s_conf.c (attach_iline): Allow aconf->host == NULL, which
+       means DNS reply is optional.  If aconf->addrbits >= 0, test it.
+
+       * tools/crypter: Delete.
+
+2004-12-11  Kevin L Mitchell  <klmitch@mit.edu>
+
+       * ircd/*.c: use new assert() in ircd_log.h in preference to system
+       assert()
+
+       * ircd/umkpasswd.c: use new assert in ircd_log.h; add necessary
+       glue so that umkpasswd will successfully compile and link
+
+       * ircd/test/ircd_chattr_t.c: comment out include of assert.h since
+       there are no calls to assert()
+
+       * ircd/ircd_log.c: add sentinel (log_inassert) to prevent assert()
+       from looping should there be an assertion failure somewhere in the
+       logging subsystem
+
+       * include/ircd_log.h: custom implementation of assert() that calls
+       log_write()
+
+2004-11-21  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/channel.c (mode_parse_upass): Allow forced mode changes to
+       be done by non-channel-managers, fixing a crash from OPMODE.
+       (mode_parse_apass): Likewise.
+
+2004-11-20  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/m_create.c (ms_create): Complain if a user tries to CREATE
+       a channel they are already in, but do not add them again.
+
+2004-11-09  Michael Poole <mdpoole@troilus.org>
+
+       * include/res.h (init_resolver): Delete, and initialize lazily.
+
+       * ircd/ircd.c (main): Do not call init_resolver().
+
+       * ircd/ircd_res.c (restart_resolver): Use default VirtualHost for
+       local resolver socket address.
+       (init_resolver): Delete.
+       (make_request): Call restart_resolver() if necessary.
+       (query_name): Use ircrandom() instead of rand().
+
+       * ircd/os_generic.c (sockaddr_from_irc): Convert last argument to
+       a file descriptor that indicates the socket family to use.
+       (os_sendto_nonb,os_socket,os_connect_nonb): Update to match.
+
+2004-11-09  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/engine_epoll.c (engine_delete): Do not attempt to remove a
+       socket from epoll on delete, since the kernel does that for us.
+
+2004-11-07  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/m_server.c (m_server, ms_server): Assign timestamp before
+       it might be used in exit_new_server().
+
+2004-11-07  Michael Poole <mdpoole@troilus.org>
+
+       * aclocal.m4, config.h.in, configure, ircd/Makefile.in: Regenerate
+       to reflect the changes since these files' last rebuild.
+
+2004-11-07  Michael Poole <mdpoole@troilus.org>
+
+       * include/ircd_crypt.h (ircd_crypt): This should return char*, not
+       const char*, since it does not own the returned pointer.
+
+       * ircd/ircd_crypt.c (ircd_crypt): Change return type.
+
+       * ircd/ircd_crypt_smd5.c (irc_crypt_smd5): Make passwd a static
+       field since it is returned but this function must own the buffer.
+
+       * ircd/m_oper.c (oper_password_match): Free the string returned by
+       ircd_crypt().
+
+       * ircd/engine_epoll.c (engine_loop): Fix a memory leak.
+
+2004-11-07  Michael Poole <mdpoole@troilus.org>
+
+       * acinclude.m4: Look for a 64-bit integer type.
+
+       * configure.in: Look for inttypes.h, since some systems have that
+       but not stdint.h (and define 64-bit integers therein).
+
+       * include/client.h: Delete con_sendK, con_receiveK.  Make
+       con_sendB and con_receiveB 64 bits wide.
+
+       * include/s_misc.h: Delete is_cks, is_ckr, is_sks, is_skr.
+       Convert the other byte counters and the connected time counters to
+       64 bits wide.
+
+       * ircd/ircd_snprintf.c (doprintf): Unconditionalize the
+       HAVE_LONG_LONG bits, and use the 64-bit integer types from above.
+
+       * ircd/packet.c (update_bytes_received): Remove use of
+       cli_receiveK().
+
+       * ircd/s_bsd.c (deliver_it): Likewise.
+       (close_connection): Likewise.
+
+       * ircd/s_misc.c (tstats): Likewise.  Update format strings to use
+       %Lu for 64-bit integer parameters.
+
+       * ircd/s_stats (stats_links): Convert cli_sendK() and
+       cli_receiveK() use shifted versions of the byte counters, and
+       update format strings to use %Lu for 64-bit integer parameters.
+
+2004-11-07  Michael Poole <mdpoole@troilus.org>
+
+       * include/s_user.h (add_silence): Delete.
+       (del_silence): Delete.
+
+       * include/struct.h (struct User): Convert silence list to struct Ban.
+
+       * ircd/m_silence.c (apply_silence, forward_silences): New functions.
+       (m_silence): Use forward_silences() instead of add_silence().
+       (ms_silence): Likewise.
+
+       * ircd/s_err.c (replyTable): Update RPL_SILELIST.
+
+       * ircd/s_misc.c (exit_one_client): Update to new silence list type.
+
+       * ircd/s_user.c (is_silenced): Use find_ban() to search for
+       silences.  If one is found, send it plus any silence exceptions.
+       (del_silence): Delete.
+       (add_silence): Delete.
+
+2004-11-07  Michael Poole <mdpoole@troilus.org>
+
+       * include/channel.h: Remove declarations for undefined functions
+       cancel_mode(), add_token_to_sendbuf(), IsMember().  Delete
+       add_banid(), next_removed_overlapped_ban().  Add BAN_EXCEPTION
+       flag and new functions find_ban(), apply_ban().
+
+       * ircd/channel.c (PartFmt*, next_ban, prev_ban, removed_bans_list,
+       LocalChanOperMode): Remove unused variable definitions.
+       (make_nick_user_host): Delete.
+       (add_banid): Delete.
+       (next_removed_overlapped_ban): Delete.
+       (find_ban): New function, which knows about exceptions.
+       (is_banned): Use find_ban() and only work on a struct Membership.
+       (bmatch): New function, which knows about CIDR bans.
+       (apply_ban): New function to replace add_banid().
+       (mode_parse_ban): Use apply_ban().
+
+2004-10-28  Michael Poole <mdpoole@troilus.org>
+
+       * configure.in (AC_PREREQ): Depend on autoconf 2.50 since we use
+       new macros like AC_LINK_IFELSE and AC_LANG_PROGRAM.
+
+2004-10-22  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/m_invite.c (m_invite, ms_invite): Fix INVITE forwarding
+       with announcements enabled (do not "announce" to the recipient,
+       and unconditionally send to the recipient).
+
+       * ircd/send.c (sendcmdto_channel_servers_butone): Properly skip
+       the "from" client and implement SKIP_NONOPS and SKIP_NONVOICES.
+
+2004-10-21  Michael Poole <mdpoole@troilus.org>
+
+       * include/channel.h (Ban): Add fields address, nu_len, addrbits to
+       support netmask-based bans.
+
+       * ircd/channel.c (set_ban_mask): New function to parse a ban as
+       either netmask-based or not.
+       (make_ban): Use set_ban_mask().
+       (make_nick_user_ip): Becomes unused; remove it.
+       (is_banned): Rewrite to match only once against the nick!user part
+       of a ban, and compare addresses if BAN_IPMASK is set.
+       (mode_parse_ban): Use set_ban_mask().
+
+2004-10-21  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/s_conf.c (attach_iline): Test resolved host names against
+       aconf->host, not the (NULL) aconf->name.
+
+2004-10-19  Michael Poole <mdpoole@troilus.org>
+
+       * include/channel.h: Move ban flags out of channel flags and
+       rename to reflect this.
+
+       * ircd/channel.c: Update ban constant names.
+
+       * ircd/m_burst.c: Likewise.
+
+2004-10-18  Michael Poole <mdpoole@troilus.org>
+
+       * include/list.h (SLink): Remove ban elements from here...
+
+       * include/channel.h (Ban): And move to the new struct Ban.
+       (Channel): Update banlist field to match.
+       (next_removed_overlapped_ban): Update return type to match.
+       (make_ban, free_ban): New functions.
+
+       * ircd/channel.c (next_ban, prev_ban, removed_bans_list): Update
+       list types.
+       (free_bans): New variable to hold unused Ban elements.
+       (make_ban, free_ban): New functions.
+       (destruct_channel, add_banid, next_removed_overlapped_ban): Update
+       to use struct Ban.
+       (is_banned, send_channel_modes, send_ban_list): Likewise.
+       (ParseState, mode_parse_ban, mode_process_bans): Likewise.
+       (mode_parse): Likewise.
+
+       * ircd/m_burst.c (ms_burst): Update to use struct Ban.
+
+       * ircd/m_clearmode.c (do_clearmode): Update to use struct Ban.
+
+       * ircd/s_debug.c (count_memory): Update to use struct Ban.
+
+2004-10-18  Kevin L Mitchell  <klmitch@mit.edu>
+
+       * ircd/gline.c (gline_find): unless we're looking for an exact
+       match, we should call match() on hostnames, not ircd_strcmp()
+
+2004-10-17  Michael Poole <mdpoole@troilus.org>
+
+       * include/s_conf.h (ConfItem): Add new field username.  Replace
+       unused field bits with addrbits.
+       (find_conf_exact): Replace user and host arguments with cptr.
+       (find_conf_name, read_tlines, find_restrict): Remove declaration
+       for undefined functions.
+       (conf_parse_userhost): New function.
+
+       * ircd/m_oper.c (m_oper): Update calls to find_conf_exact(): both
+       resolved hostname and IP are matched in one pass now.
+
+       * ircd/s_bsd.c (close_connection): Update call to find_conf_exact().
+
+       * ircd/s_conf.c (conf_parse_userhost): New function.
+       (check_limit_and_attach): Use correct ConfItem field to determine
+       maximum connections per IP.
+       (attach_iline): Replace user@host matching with shorter, clearer
+       matching against username and host/IP fields.
+       (find_conf_exact): Likewise.
+
+       * ircd/ircd_parser.y: Replace assignment to aconf->host for
+       CONF_CLIENT and CONF_OPERATOR with calls the CIDR-aware
+       conf_parse_userhost().  This means CONF_CLIENT ConfItems no longer
+       use the name field or the IP token.  Remove the latter.
+
+       * ircd/ircd_lexer.l: Remove unused token IP.
+
+2004-10-17  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/crule.c (crule_via): Simplify the lookup for the directly
+       connected server name.
+
+2004-10-16  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/class.c: Make find_class() return NULL for unknown classes,
+       rather than returning the start of connClassList.
+
+       * ircd/match.c (parse_ipmask): Translate IPv4 masks as
+       IPv4-compatible addresses.
+       (check_ipmask): Fix comparison of IP masks.
+
+       * ircd/motd.h, ircd/motd.c: Add a new MOTD type, MOTD_IPMASK, that
+       uses CIDR style masks in the hostname field of a Motd block.
+
+2004-10-16  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/numeric.h: Remove the unused RPL_STATMEM and
+       RPL_STATMEMTOT.  Move the RPL_BOUNCE comment to its current
+       value (the former RPL_STATMEM).
+
+       * ircd/s_err.c: Remove format strings for RPL_STATMEM and
+       RPL_STATMEMTOT.
+
+2004-10-16  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/m_server.c: Look up server configuration by name of our
+       directly connected peer rather than the server being introduced.
+
+2004-10-13  Michael Poole <mdpoole@troilus.org>
+
+       * include/channel.h: Delete MODE_LISTED and is_listed().  Replace
+       ListingArgs.chptr with ListingArgs.bucket.  Move declaration of
+       list_next_channels() to..
+
+       * include/hash.h: here, and drop the "nr" argument.
+
+       * ircd/channel.c: Remove redundant scan of local clients for
+       channels being listed.  Delete list_next_channels() function.
+
+       * ircd/hash.c: Add list_next_channels() here, revising to not use
+       MODE_LISTED and to use ListingArgs.bucket instead of chptr.  Also
+       decide when to stop sending RPL_LISTs based on a half-full sendq.
+
+       * ircd/m_burst.c, ircd/s_misc.c: Delete mention of MODE_LISTED.
+
+       * ircd/m_list.c: Delete mention of MODE_LISTED.  Unconditionally
+       call list_next_channels(sptr).
+
+       * ircd/s_bsd.c: Remove the "nr" argument to list_next_channels().
+
+       * ircd/Makefile.in: Update dependencies (for hash.c).
+
+2004-10-13  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/ircd_parser.y: Consistently zero out global variables after
+       they are used (prevents double frees and other problems).
+
+2004-10-12  Michael Poole <mdpoole@troilus.org>
+
+       * include/client.h: Rename FLAGSET_ISSET, _SET, _CLEAR to FlagHas,
+       Set, Clr respectively.  Get rid of FLAG_CHKACCESS and FLAG_LOCAL.
+       Delete con_fd (get from con_socket) and con_port.  Move sentalong
+       from send.c to struct Connection, and cli_lasttime and cli_since
+       from struct Client to struct Connection.  Update cli_*() macros to
+       use con_*(cli_connect(cli)).
+
+       * ircd/client.c: Replace PrivSet() with FlagSet(), PrivClr() with
+       FlagClr(), PrivHas() with FlagHas().
+
+       * ircd/ircd_parser.y: Likewise.
+
+       * ircd/list.c: Remove assignment to cli_local() since it is now a
+       calculated value.
+
+       * ircd/s_bsd.c: Remove uses of cli_port().
+
+       * ircd/s_conf.c: Remove uses of ClearAccess().
+
+       * ircd/send.c: Delete sentalong array and replace with references
+       to con_sentalong().
+
+2004-10-12  Michael Poole <mdpoole@troilus.org>
+
+       * doc/example.conf: Update example config to reflect the changes
+       made in the remainder of this patch.
+
+       * include/list.h: Make make_conf() take a type argument.
+
+       * include/s_conf.h: Delete CONF_LEAF and CONF_HUB.  Add "maximum"
+       and "hub_limit" to ConfItem to compensate.
+
+       * ircd/ircd_lexer.l: Recognize MAXHOPS token.
+
+       * ircd/ircd_parser.y: Get rid of aconf global variable and add
+       hub_limit global variable.  Add MAXHOPS token, and productions
+       inside connectblock to recognize it and hub masks.  Allow maxlinks
+       field in a Client block, rather than overloading password field.
+       Convert serverblock to uworldblock and remove extraneous fields.
+
+       * ircd/m_server.c: Make check_loop_and_lh() look up ConfItem and
+       calculate LHcptr and active_lh_line.  Merge some duplicated code
+       so handling active_lh_line cases is clearer.
+
+       * ircd/s_conf.c: Make make_conf() take a type argument.  Delete
+       CONF_LEAF and CONF_HUB.  Do not overwrite server name with what
+       is specified in the config file.
+
+       * ircd/s_err.c: Remove the unused RPL_STATSNLINE and
+       RPL_STATSHLINE.  Remove useless parameters and format fields from
+       RPL_STATSCLINE, RPL_STATSILINE, RPL_STATSLLINE, RPL_STATSOLINE and
+       RPL_STATSULINE.
+
+       * ircd/s_serv.c: Delete CONF_LEAF and CONF_HUB.
+
+       * ircd/s_stats.c: Get rid of report_array and make
+       stats_configured_links() directly use RPL_STATSxLINE (adding the
+       new fields for Server and Client blocks).  Remove /stats h, since
+       that has no meaning.
+
+2004-10-12  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/m_burst.c: Mask off channel modes in a wiped-out channel by
+       default rather than by listing which should be wiped out.
+
+2004-10-09  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/m_server.c: Forward port checks for leaf and hub config
+       rules, and reorganize mr_server() and ms_server() by moving out
+       common code.  Add doxygen comments for the file.
+
+2004-10-09  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/hash.c: Fix thinko in hash function: It is not indexed
+       simply by character value, so we cannot just remap the values
+       by case.
+
+2004-10-05  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/hash.c: Replace the old hash function with one based on
+       randomized CRC-32.  The new one avoids a big table from the old
+       function.
+
+2004-10-05  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/random.c: Convert to use ircd_md5 interface and hopefully
+       keep more internal random state.
+
+2004-10-05  Michael Poole <mdpoole@troilus.org>
+
+       * include/ircd_md5.h, ircd/ircd_md5.c, ircd_crypt_smd5.c,
+       ircd/umkpasswd.c: Get rid of the GoodMD5xxx/BrokenMD5xxx
+       prefixes.
+
+2004-10-05  Michael Poole <mdpoole@troilus.org>
+
+       * adns, lib/adns: Remove unused adns library.
+
+2004-10-05  Michael Poole <mdpoole@troilus.org>, hikari <hikari@undernet.org>, Perry Lorier <isomer@undernet.org>
+
+       * include/*.h, ircd/*.c: Convert comments to Doxygen-compatible
+       format, and add new comments where needed.
+
+       * Doxyfile: New file to tell Doxygen how to run.
+
+2004-09-21  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/s_auth.c (HeaderMessages): Make the compiler, not the
+       programmer, generate magic numbers.
+       (AuthIncompleteList): Remove.
+       (AuthPollList): Remove.
+
+2004-09-19  Michael Poole <mdpoole@troilus.org>
+
+       * acinclude.m4: Clean up AC_DEFINE()s so we no longer need
+       acconfig.h.
+
+       * acconfig.h: Remove since it is now redundant.
+
+       * aclocal.m4, config.h.in, configure: Regenerate.
+
+2004-09-19  hikari <hikari@undernet.org>
+
+       * configure.in: Fixed configure script rules to fail if (f)lex or yacc/bison 
+       aren't found as they're essential for compilation.  Regenerated files with 
+       autreconf.
+               
+2004-09-18  Michael Poole <mdpoole@troilus.org>
+
+       * doc/example.conf: Add NETWORK feature example.  Fix typos in
+       eaxmples for HANGONGOODLINK and IRCD_RES_TIMEOUT.
+
+       * include.class.h: Make max_links and ref_count unsigned ints.
+       Make ping_freq and conn_freq unsigned short. (No more negative
+       numbers in /stats y.)
+
+       * ircd/ircd.c: Report configuration file name for "ircd -k".
+
+2004-09-18  hikari <hikari@undernet.org>
+
+       * ircd/Makefile.in: Fixed a missing internal build dependency.
+       
+2004-09-16  Michael Poole <mdpoole@troilus.org>
+
+       * INSTALL: Fix name of example.conf and mention its installed
+       location.
+
+       * include/supported.h (FEATURESVALUES2): Fix a reference to
+       channel mode +u that escaped earlier rename attempts.
+
+       * ircd/ircd_auth.c (iauth_connect): Assign port number after
+       zeroing out the destination address.
+       Add some additional debug statements to help follow operations.
+
+       * ircd/ircd_parser.y (iauthblock): Do not require "name" to be set.
+
+2004-09-11  Bas Steendijk <steendijk@xs4all.nl>
+
+       * include/channel.h, include/supported.h, ircd/channel.c,
+       ircd/s_err.c: Use +U instead of +u for user keys.
+
+2004-09-13  Michael Poole <mdpoole@troilus.org>
+
+       * doc/example.conf: Remove sample VIRTUAL_HOST setting.
+
+       * doc/readme.features: Remove VIRTUAL_HOST documentation, and
+       update NODNS documentation to match current behavior.
+
+       * include/s_conf.h: Remove now-unused vhost_address field and
+       set_virtual_host() function.
+
+       * include/ircd_features.h, ircd/ircd_features.c, ircd/s_debug.c:
+       Remove VIRTUAL_HOST.
+
+       * ircd/ircd_auth.c, ircd/s_bsd.c: Use VirtualHost as local address
+       if we do not have a more specific alternate.
+
+       * ircd/ircd_parser.y: Check for sanity in General blocks (from old
+       conf_add_local()) and assign vhost directly to VirtualHost.
+
+       * ircd/ircd_res.c (irc_in_addr_valid): Fix thinko; obviously any
+       value will be either != 0 or != 0xffff.
+
+       * ircd/os_generic.c: Use AF_INET instead of AF_INET6 when the
+       local addresses are specified as IPv4 addresses.
+
+       * ircd/s_conf.c: Remove unused conf_add_local() and
+       set_virtual_host().
+
+2004-09-13  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/listener.c (add_listener): Consolidate duplicated code, and
+       make sure listener->server is set before calling inetport() on it.
+
+2004-09-12  Michael Poole <mdpoole@troilus.org>
+
+       * include/channel.c (mode_parse_upass, mode_parse_apass): Only let
+       services (not normal opers) force a change of +A or +u.
+
+2004-09-11  Michael Poole <mdpoole@troilus.org>
+
+       * include/s_stats.h: Add sd_name to struct StatDesc.  Stop
+       publishing the statsinfo and statsmap arrays; replace them with
+       stats_find().  Change argument list of StatFunc() to work with
+       names.
+
+       * ircd/m_stats.c: Use stats_find() instead of statsmap[].  Use the
+       full argument instead of just the first character in reports.
+
+       * ircd/s_stats.c: Adapt individual stats handler functions to new
+       argument list.  Add long names to statsinfo[].  Add new functions
+       stats_cmp(), stats_search(), stats_find().  Sort statsinfo[] in
+       stats_init().
+
+       * ircd/s_err.c: Change ENDOFSTATS to display a string rather than
+       a single character.
+
+       * ircd/s_user.c: Send an error to the user when a message loses
+       its target in transit.
+
+       * include/class.h include/gline.h include/ircd_features.h
+       include/listener.h include/motd.h include/msgq.h include/res.h
+       include/s_debug.h include/s_misc.h include/userload.h ircd/class.c
+       ircd/gline.c ircd/ircd_features.c ircd/ircd_res.c ircd/listener.c
+       ircd/motd.c ircd/msgq.c ircd/s_debug.c ircd/s_misc.c
+       ircd/userload.c: Adjust stats handlers to new argument list.
+
+2004-09-11  Michael Poole <mdpoole@troilus.org>
+
+       * include/numeric.h, ircd/s_err.c: Remove RPL_TRACEPING, and
+       replace with RPL_TRACEEND.
+
+       * ircd/s_trace.c: Move all the duplicated code in m*_trace() to
+       do_trace().  Implement RPL_TRACEEND, per RFE#830291.
+
+2003-06-20  Alexander Maassen <outsider@key2peace.org>
+
+       * ircd/m_topic.c : Don't allow banned users to set a topic in a
+       channel.
+
+2004-09-11  Kevin L Mitchell  <klmitch@mit.edu>
+
+       * config.h.in, tools/Makefile.crypt: Remove wrong pathname from
+       comment in header.
+
+       * ircd/m_clearmode.c, ircd/m_opmode.c: Fix wrong pathname in
+       header comment.
+
+       * ircd/m_away.c, ircd/m_kill.c, ircd/m_notice.c, ircd/m_ping.c,
+       ircd/m_pong.c, ircd/m_privmsg.c, ircd/m_quit.c, ircd/m_topic.c,
+       ircd/m_version.c: Remove "template" moniker from comments.
+
+       * ircd/test/ircd_chattr.0.dat (IsChannelPrefix): Drop + from
+       channel prefix list.
+
+2004-09-11  Michael Poole <mdpoole@troilus.org>
+
+       * doc/example.conf: Add examples for FEAT_HIS_* features.
+
+2003-06-08 Matthias Crauwels <ultimate_@wol.be>
+       [Feature renamed to FEAT_HIS_WHOIS_LOCALCHAN by Michael Poole.]
+
+       * include/ircd_features.h: new feature FEAT_HIS_LOCAL_CHAN_WHOIS
+
+       * ircd/ircd_features.c: new feature FEAT_HIS_LOCAL_CHAN_WHOIS
+
+       * ircd/m_whois.c: hide local channels in local WHOIS, this breaks HIS
+
+       * doc/readme.features: documented FEAT_HIS_LOCAL_CHAN_WHOIS
+
+       * doc/ircd.conf.sample: default value for FEAT_HIS_LOCAL_CHAN_WHOIS
+
+2004-09-11  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/ircd_relay.c (server_relay_channel_message,
+       server_relay_channel_notice): Do not allow other servers to send
+       or relay to local channels.
+
+       * ircd/m_wallchops (ms_wallchops): Likewise.
+
+       * ircd/m_wallvoices (ms_wallvoices): Likewise.
+
+2004-09-11  Kevin L Mitchell  <klmitch@mit.edu>
+
+       * ircd/gline.c (gline_add): fix GLINE logging (Bug #750927)
+
+       * ircd/channel.c: removing limits shouldn't gobble an argument;
+       this was a subtle interaction issue with modebuf...fixed by adding
+       MODE_LIMIT to modebuf_flush_int() and short-circuiting
+       modebuf_mode_uint() to add MODE_LIMIT to mbuf->mb_rem in the
+       removal case.  Note that this is not proof against the sequence,
+       "modebuf_mode_uint(mbuf, MODE_ADD | MODE_LIMIT, 10);
+       modebuf_mode_uint(mbuf, MODE_DEL | MODE_LIMIT, 10);"
+       (Bug #916138)
+
+2004-09-11  Michael Poole <mdpoole@troilus.org>
+
+       * include/supported.h: Kev pointed out I misinterpreted the
+       meaning of CHANMODES; fix this.  Also define CHANNELLEN and
+       STATUSMSG from the ISUPPORT draft.
+
+2004-09-10  Michael Poole <mdpoole@troilus.org>
+
+       * include/supported.h (FEATURESVALUES2): Include A,u, in CHANMODES
+       when oplevels are enabled.
+
+2004-09-10  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/channel.c (send_channel_modes): Only send oplevels for
+       channels that actually use them -- for -A channels, send chanops
+       as :o even if OPLEVELS is enabled.
+
+       * ircd/ircd.c: Fix -k (chkconf mode) and show in usage help.
+
+       * ircd/numnicks.c (base64toip): Fill in the right number of 0
+       words when we see _ in a base64-encoded IPv6 address.
+
+2004-09-10  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/ircd.c: Add -k as a chkconf-like option to exit after
+       reading the configuration file.
+
+       * ircd/chkconf.c: Remove as unused.
+
+       * ircd/Makefile.in: Remove last mentions of chkconf from Makefile.
+
+2004-09-10  Michael Poole <mdpoole@troilus.org>
+
+       * doc/example.conf: Remove examples for unused features (TIMESEC,
+       CRYPT_OPER_PASSWORD) and add for new feature (ANNOUNCE_INVITES).
+
+       * doc/readme.features: Remove documentation for unused features
+       (TIMESEC, CRYPT_OPER_PASSWORD, oper/locop privileges,
+       HIS_DESYNCS), update defaults for SOCKSENDBUF and SOCKRECVBUF, and
+       add documentation for ANNOUNCE_INVITES.
+
+       * include/ircd_features.h: Remove unused features (TIMESEC,
+       CRYPT_OPER_PASSWORD, LIST_CHAN, HIS_DESYNCS).
+
+       * include/ircd_features.c: Likewise.
+
+       * ircd/ircd_res.c: Actually use FEAT_IRCD_RES_RETRIES and
+       FEAT_IRCD_RES_TIMEOUT where appropriate.
+
+       * ircd/s_debug.c: Do not display setting of unused (and now
+       non-existent) FEAT_CRYPT_OPER_PASSWORD.
+
+2004-09-10  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/os_generic.c (sockaddr_from_irc): Fix IPv4 implementation
+       to use the correct address family and IP offset.
+
+2004-09-10  Michael Poole <mdpoole@troilus.org>
+
+       * include/s_conf.h (struct ConfItem): Add origin and origin_name
+       fields.
+
+       * ircd/ircd_parser.y: Add new global variable "origin."  Add a new
+       "connectionvhost" production that accepts vhost = "IP" inside a
+       Connect block and assigns the IP to origin_name.
+
+       * ircd/s_bsd (connect_inet): If aconf has a valid origin, use it
+       as the local address.  Otherwise, fall back to the old logic (if
+       VIRTUAL_HOST="TRUE", use the virtual host setting).
+
+       * ircd/s_conf.c (lookup_confhost): If the ConfItem has an
+       origin_name, try to parse it as an IP address.
+
+2004-04-17  Isomer <isomer@undernet.org>
+       * ircd/parse.c: Don't rate limit /gline messages
+
+2004-09-10  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/ircd_parser.y: Replace references to yylval.whatever with
+       references to the appropriate term.  This fixes bugs like
+       "1 hour 30 minutes" being misrecognized as 30 seconds.
+
+2004-09-10  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/ircd_features.c (features): Change default values for
+       SOCKSENDBUF and SOCKRECVBUF to SERVER_TCP_WINDOW, so that users
+       need not specify them in ircd.conf.
+
+2004-09-10  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/ircd_parser.y (serverblock): Server blocks should default
+       to CONF_LEAF status.
+
+       * doc/example.conf: Update example to reflect this.
+
+2004-09-10  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/parse.c (msg_tree_parse): Reject commands that contain
+       non-alphabetic characters.
+
+2004-09-09  Michael Poole <mdpoole@troilus.org>
+
+       * config.h.in: Remove duplicated and unused macro definitions.
+
+2004-08-24  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/client.h: Properly parenthesize "flag" argument to
+       FLAGSET_INDEX() and FLAGSET_MASK() macros.
+
+2004-08-22  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/channel.c (send_channel_modes): If oplevels are disabled,
+       send 'o' for chanops instead of the member's oplevel.
+
+2004-08-22  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/s_conf.c: find_conf_byip() should use irc_in_addr_cmp()
+       instead of memcmp().  (Fixes IPv4 servers linking to an IPv6
+       server.)
+
+2004-08-22  Alex Badea  <decampos@users.sourceforge.net>
+
+       * include/ircd_defs.h: increased SOCKIPLEN to fit ipv6 addresses
+
+2004-08-19  Michael Poole <mdpoole@troilus.org>
+
+       * include/res.h: Remove unused function gethost_byname_type().
+
+       * ircd/ircd_res.c: Likewise, and clean up some small functions
+       only used once (remove_dlink(), timeout_resolver()).  Use rand()
+       for random request IDs instead of the deprecated *rand48().  Make
+       resolver timeout event fire only when needed instead of once a
+       second.
+
+2004-08-17  Michael Poole <mdpoole@troilus.org>
+
+       IPv6 support, with lots of code and design borrowed from a patch
+       by Alex Badea.
+
+       * config.h.in: Add place to #define IPV6 support.
+
+       * configure.in: Check for struct sockaddr_in6, and use that as
+       the default choice for IPv6 support.
+
+       * configure: Regenerate.
+
+       * include/IPcheck.h, include/client.h, include/gline.h,
+       include/ircd_string.h, include/listener.h, include/match.h,
+       include/res.h, include/s_bsd.h: Convert from struct in_addr (from
+       <netinet/in.h>) to struct irc_in_addr (from "res.h").
+
+       * include/ircd_osdep.h, include/s_conf.h, include/uping.h: Convert
+       from struct sockaddr_in (from <netinet/in.h>) to struct
+       irc_sockaddr (from "res.h").  Add new functions os_socket(),
+       os_accept(), os_sendto_nonb() to help abstract away actual
+       sockaddr types.
+
+       * include/ircd_chattr.h, ircd/table_gen.c: Define new bit to mark
+       characters valid in IPv6 addresses.
+
+       * include/numnicks.h, ircd/numnicks.c: New functions iptobase64()
+       and base64toip() to convert from base64 to struct irc_in_addr.
+
+       * ircd/IPcheck.c, ircd/channel.c, ircd/m_nick.c, ircd/m_oper.c,
+       ircd/m_userip.c, ircd/m_who.c, ircd/m_whois.c, ircd/s_misc.c,
+       ircd/s_serv.c, ircd/s_user.c, ircd/whocmds.c: Use struct
+       irc_in_addr instead of unsigned int or struct in_addr.
+
+       * ircd/gline.c: Use new more-generic ipmask functions.
+
+       * ircd/ircd.c: Use struct irc_sockaddr instead of separate port
+       fields.
+
+       * ircd/ircd_reslib.c: Use struct irc_sockaddr and ircd_aton()
+       instead of irc_ssaddr and irc_getaddrinfo().
+
+       * ircd/ircd_string.c: Implement new functions: IPv6-capable
+       ircd_ntoa_r(), ircd_aton_ip4(), ircd_aton().
+
+       * ircd/match.c: Delete IPv4-only matchcompIP().  Replace with
+       IPv6-capable ipmask_parse() and ipmask_check().
+
+       * ircd/numnicks.c: Implement new functions: iptobase64() and
+       base64toip().
+
+       * ircd/os_generic: Convert external parameters to be struct
+       irc_addrinfo.  When using IPv6 support, sockaddr_in6 is native.
+       Implement new functions os_sendto_nonb(), os_socket() and
+       os_accept().
+
+       * ircd/ircd_auth.c, ircd/ircd_parser.y, ircd/ircd_res.c,
+       ircd/listener.c, ircd/m_connect.c, ircd/s_auth.c, ircd/s_bsd.c,
+       ircd/s_conf.c, ircd/s_stats.c, ircd/uping.c: Use struct
+       irc_sockaddr instead of separate in_addr and port fields and new
+       OS support functions.
+
+       * include/ircd_addrinfo.h, ircd/ircd_getaddrinfo.c,
+       ircd/ircd_getnameinfo.c: Remove, since these functions are no
+       longer used.
+
+       * ircd/os_bsd.c, ircd/os_linux.c, ircd/os_openbsd.c,
+       ircd/os_solaris.c, ircd/res_adns.c, ircd/res_libresolv.c: Remove,
+       since these are unused and not compatible with IPv6 support.
+
+       * ircd/Makefile.in: Remove references to ircd_getXxxxinfo.c.
+       Regenerate dependencies.
+
+2004-08-17  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/ircd_lexer.l: Change tokenizer to reduce number of lexer
+       states and be case-insensitive again.
+
+2004-08-15  Michael Poole <mdpoole@troilus.org>
+
+       * aclocal.m4: Check for uintNN_t instead of u_intNN_t, since the
+       former is from C99 (and the latter is absent on Solaris).
+
+       * configure.in: Remove check for inttypes.h (which is a C99 format
+       string header); replace with check for stdint.h.  Add checks for
+       sys/param.h and sys/socket.h.  Check for socklen_t being defined
+       (OS X does not set it).  Run program tests for lex and yacc, and
+       use them rather than assuming flex and bison.  Remove OSDEP_C and
+       mention to adns.  Remove check for res_mkquery().
+
+       * config.h.in: Update u_intNN_t #undef lines.  Add #undef
+       socklen_t so configure test can set it.
+
+       * configure: Regenerate.
+
+       * include/ircd_addrinfo.h: #include headers needed for netdb.h and
+       to define struct addrinfo and uintNN_t.
+
+       * include/ircd_reslib.h: Replace u_intNN_t with uintNN_t.
+
+       * include/res.h: #include "ircd_addrinfo.h" to get proper type
+       definitions.  #define INADDR_NONE if it is not defined (as on
+       Solaris).
+
+       * ircd/Makefile.in: Replace LEX and YACC definitions.  Remove
+       OSDEP_C and OSDEP_SRC; always compile os_generic.c.  Remove adns
+       directory from CPPFLAGS.  Regenerate dependencies.
+
+       * ircd/client.c: Return when no propagation set for oper, to
+       squash warning about use of "defaults" before it is set.
+
+       * ircd/engine_epoll.c: #include correct C99 integer header.
+
+       * ircd/engine_poll.c: Last argument to getsockopt() should be of
+       socklen_t, not size_t; fix.
+
+       * ircd/engine_select.c: Squash warning about bzero().
+
+       * ircd/ircd_auth.c: OS X does not define in_addr_t, so replace it
+       with uint32_t.  We need <stdint.h> for that, so include it.
+
+       * ircd/ircd_getnameinfo.c, ircd/memdebug.c: Replace u_int32_t with
+       uint32_t.
+
+       * ircd/ircd_lexer.l: Replace flex-isms with portable syntax.
+       There is no portable way to do %option, so remove that.  lex on
+       Solaris needs several of its internal tables to be bigger, so
+       increase those sizes.
+
+       * ircd/ircd_parser.y: Remove the second declarations of two
+       tokens, since standard yacc warns about changing precedence.
+
+       * ircd/os_generic.c: Make this compile on common OSes (Linux,
+       Solaris, OS X, FreeBSD, OpenBSD).
+
+       * ircd/table_gen.c: Make arguments to isprint() all unsigned char
+       to squash warnings on Solaris that array index is "char."
+
+       * ircd/umkpasswd.c: Remove #include <libgen.h> since it is not
+       portable, and replace basename() with an equivalent.
+
+       * ircd/uping.c: Typecast printf arguments for 64-bit OSes.
+
+2004-07-27  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/m_burst.c: Add new netride_modes() function to check
+       which modes could be used in a net.ride.  Use this instead
+       of the old check for just +i or +k.
+       (Based on patches by beware and pomac.)
+
+2004-07-25  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/ircd_parser.y: Remove redundant semicolon; it causes
+       errors on some versions of yacc.
+
+2004-07-21  Michael Poole <mdpoole@troilus.org>
+
+       * include/client.h, ircd/ircd_auth.c, ircd/ircd_crypt_smd5.c,
+       ircd/ircd_reslib.c: Fix warnings from gcc -pedantic.
+
+2004-07-21  Michael Poole <mdpoole@troilus.org>
+
+       New DNS resolver code, courtesy of Dianora and the rest of the
+       Hybrid team.  (Bugs are of course my fault.)
+
+       * configure.in, Makefile.in, ircd/Makefile.in: Remove adns and
+       libresolv from the build process.  Update dependencies.
+
+       * configure: Regenerate.
+
+       * include/client.h: Change connection's DNS reply type.
+
+       * include/ircd_features.h, ircd/ircd_features.c: New HIS_STATS_a.
+
+       * include/numeric.h, ircd/s_err.c, ircd/s_stats.c: Add new
+       RPL_STATSALINE and /stats a to list DNS servers.
+
+       * include/ircd_addrinfo.h, include/ircd_reslib.h, include/res.h,
+       ircd/ircd_getaddrinfo.c, ircd/ircd_getnameinfo.c, ircd/ircd_res.c,
+       ircd/ircd_reslib.c: New resolver files.
+
+       * ircd/ircd_auth.c, ircd/s_auth.c, ircd/s_bsd.c, ircd/s_conf.c:
+       Update to new resolver callback interface and to only deal with
+       one IP and one name per DNS reply.
+
+       * ircd/parse.c: Remove /DNS command, since new resolver does not
+       track those statistics.
+
+2004-07-20  Michael Poole <mdpoole@troilus.org>
+
+       * doc/readme.features: Change references to O:, Y:, etc lines into
+       references to the appropriate block types.
+
+2004-07-01  Michael Poole <mdpoole@troilus.org>
+
+       * include/fileio.h: Elaborate on "works for any file descriptor."
+
+       * include/iauth.h: Remove unused file.
+
+2004-07-01  Michael Poole <mdpoole@troilus.org>
+
+       * include/map.h, ircd/map.c: Remove unused code.
+
+       * ircd/m_links.c, ircd/m_map.c, ircd/s_misc.c: Remove includes of
+       map.h and a call to map_update().
+
+       * ircd/Makefile.in: Remove map.c and regenerate dependencies.
+
+       * ircd/ircd_parser.y: Recognize Diane Bruce as a copyright holder
+       for the new config parser.
+
+       * ircd/match.c: Remove pointless pointer dereference (Reed points
+       out that this generates a warning with old gcc).
+
+       * ircd/s_user.c: Display connection class in CONNEXIT connection
+       notice as a string rather than an integer.
+
+       * tools/ringlog.c, tools/ringlog.pl: At Kevin's request, remove
+       lines (falsely) identifying ringlog as related to IRC; the files
+       are general purpose.
+
+       * configure.in, include/ircd_snprintf.h: Add checks for
+       va_copy()-like alternatives and use them if va_copy() is missing.
+
+       * configure, config.h.in: Regenerate.
+
+2004-02-01  beware <steendijk@xs4all.nl>
+
+       * ircd/channel.c: Check bans that look like IP bans against user's
+       hostname just in case they have a host like 1234.domain.tld.
+
+2003-12-18  Timothy Grant Vogelsang <net@astrolink.org>
+
+       * ircd/ircd_log.c, ircd/send.c: va_list is not a scalar type
+
+2004-04-02  Gavin Grieve <hektik@dimebox.net>
+
+       * ircd/ircd_parser.y: Fix rehash warnings for servername and
+       numeric so they only warn if changed in the config file.
+
+2004-06-30  Michael Poole <mdpoole@troilus.org>
+
+       * doc/readme.iauth, include/ircd_auth.h, ircd/ircd_auth.c: New
+       files.
+
+       * doc/example.conf: Illustrate IAUTH configuration.
+
+       * include/client.h: Add fields to record IAUTH status.
+
+       * ircd/Makefile.in: Add ircd_auth.c to Makefile.
+
+       * ircd/ircd_lexer.l, ircd/ircd_parser.y: Add new IAUTH section.
+
+       * ircd/s_conf.c: Notify IAUTH code when reloading a configuration
+       so that an obsolete connection can be abandoned.
+
+       * ircd/s_misc.c: Report client exits via IAUTH.
+
+       * ircd/s_user.c: If IAUTH is active and a connecting user has not
+       been checked against it, interrogate the IAUTH server.
+
+2004-06-25  Michael Poole <mdpoole@troilus.org>
+
+       * configure.in: Check for crypt.h as well.
+
+       * configure: Regenerate.
+
+       * ircd/ircd_crypt_native.c: Move XOPEN defines earlier so they
+       affect the first includes of system headers.  Include crypt.h if
+       it is available.
+
+       * ircd/umkpasswd.c: Quash a gcc warning.
+       
+2004-06-23  Michael Poole <mdpoole@troilus.org>
+
+       * doc/Authors: Add contributors to ircu2.10.11 and myself.
+
+       * ircd/gline.c: Fix buglet in my forward port of Alex Badea's fix.
+
+       * configure.in: Add missing check for inttypes.h; remove obsolete
+       display of Head-in-sand, add display of epoll() engine.
+
+       * INSTALL, INSTALL_FR, doc/readme.cvs: Update descriptions of how
+       to use SourceForge's CVS server, from the u2.10.11 branch.
+
+2003-11-09 beware <steendijk@xs4all.nl>
+
+        * ircd/s_user.c: move assigning a numeric to a local client from
+       when nick is set, to when connection becomes client, to not waste
+       numerics.
+
+2004-06-08  Kevin L Mitchell  <klmitch@mit.edu>
+
+       * ircd/parse.c: don't let rank-and-file users escape HIS
+       limitations with /jupe...
+
+2004-06-18  Alex Badea  <decampos@users.sourceforge.net>
+
+       * ircd/gline.c (gline_lookup): only return a gline if it's
+       active
+
+       * ircd/s_conf.c (find_kill): don't check for active gline,
+       since gline_lookup does now
+
+2002-11-11  hikari <shadow@undernet.org>
+       * ircd/ircd.c: added call to irc_crypt_init() - someone hurry up and 
+       modularise :P
+
+       * ircd/ircd_xopen.c: removed, superseded by new crypto system.
+
+       * ircd/ircd_crypt.c: wrote scary ircd_crypt() interface function,
+       wrote ircd_crypt_mech_register() function, various other bits 
+       designed to create a near-pluggable crypto system for ircu.  currently
+       this code also loads the various mechanisms i've written code for.
+
+       * ircd/ircd_crypt_smd5.c: imported the crypt_md5 function from 
+       elsewhere, manipulated to suit ircu, returns a salted MD5 password.
+
+       * ircd/ircd_crypt_native.c: replaces the old ircd_xopen.c file,
+       generate a crypted password using the systems native crypt() function.
+
+       * ircd/ircd_crypt_plain.c: plain text crypt mechanism, should really
+       only be used for testing purposes.
+
+       * ircd/ircd_md5.c: main gubbins of the MD5 hashing code, lifted from
+       elsewhere, ircuified.
+
+       * ircd/umkpasswd.c: mkpasswd program for ircu.
+
+       * include/ircd_xopen.h: removed, superseded by new crypto system.
+
+       * include/ircd_crypt.h: external definitions for the new ircd_crypt()
+       function and definition of the ircd_crypt_mech structure for containing
+       crypto mechanism data.
+
+       * include/ircd_crypt_smd5.h: sundary definitions for the salted MD5
+       mechanism.
+
+       * include/ircd_crypt_native.h: sundary definitions for the native 
+       crypt() mechanism.
+
+       * include/ircd_crypt_plain.h: sundary definitions for the plain text
+       mechanism.
+
+       * include/umkpasswd.h: fluff for umkpasswd.
+
+2003-03-11  Landon Fuller (landonf) <landonf@sf.net>
+
+       * configure.in: allow ircu to build on OS X.
+
+2004-05-24  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/m_invite.c (m_invite): Include channel name in invitation
+       announcements.
+       (ms_invite): Likewise, and also fix a use-before-assignment bug in
+       them.
+
+2004-05-18  Michael Poole <mdpoole@troilus.org>
+
+       Announce invitations to other channel operators.
+
+       * include/ircd_features.h, ircd/ircd_features.c
+       (ANNOUNCE_INVITES): Add new boolean feature, default off.
+
+       * include/numeric.h, ircd/s_err.c (RPL_ISSUEDINVITE): Add new
+       reply.
+
+       * include/send.h, ircd/send.c (sendcmdto_channel_butserv_butone):
+       Add 'skip' parameter that is needed elsewhere.
+       (sendcmdto_channel_servers_butone): New function.
+
+       * ircd/channel.c, ircd/m_burst.c, ircd/m_kick.c, ircd/m_topic.c,
+       ircd/s_user.c: Add argument for 'skip' to calls to s_c_b_b.
+
+       * ircd/m_invite.c (m_invite, ms_invite): If ANNOUNCE_INVITES, send
+       the INVITE message to all interested servers, and send a numeric
+       to all local chanops.
+
+2004-05-18  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/res_adns.c (res_ourserver): Remove unused function.
+       (validate_name): Likewise.
+
+2004-05-17  Michael Poole <mdpoole@troilus.org>
+
+       * include/ircd_features.h, ircd/ircd_features.c, ircd/s_debug.c:
+       Rip out feature settings related to oper privileges.
+
+       * include/client.h: Comment a few unexplained privileges.
+
+       * ircd/ircd_lexer.l: Rename privilege keywords to match their
+       names in code and /PRIVS output.  Add support for two "new"
+       privileges (FORCE_OPMODE, FORCE_LOCAL_OPMODE).
+
+       * include/class.h, ircd/client.c, ircd/ircd_parser.y,
+       ircd/m_oper.c: Replace the removed feature settings with
+       per-connection class operator privileges.
+
+       * doc/example.conf: Document the change.
+
+       * ircd/ircd_parser.y (portblock): Fix slight memory leak.
+
+2004-05-16  Michael Poole <mdpoole@troilus.org>
+
+       * doc/example.conf: Make this show the new NICKLEN default.
+
+2004-05-14  Kevin L Mitchell  <klmitch@mit.edu>
+
+       * ircd/ircd_features.c: per CFV-0243, NICKLEN default is increased
+       to 12
+
+2004-05-14  Kevin L Mitchell  <klmitch@mit.edu>
+
+       * ircd/s_user.c: process account creation timestamp if present in
+       user mode portion of a N protocol message; add account creation
+       timestamp to outgoing N protocol messages if that timestamp is
+       non-zero
+
+       * ircd/m_account.c: process account creation timestamp if present
+       in AC protocol message
+
+       * include/struct.h: add account creation timestamp
+
+2004-05-16  Michael Poole <mdpoole@troilus.org>
+
+       * doc/example.conf: Document operator privilege settings.
+
+2004-05-16  Michael Poole <mdpoole@troilus.org>
+
+       Get rid of CONF_LOCOP; use PRIV_PROPAGATE instead.
+
+       * ircd/ircd_parser.y (invert): New variable.
+       (operlocal): Remove production.
+       (operpriv): Use "invert" variable.
+       (privtype): Add LOCAL alternative production.
+
+       * ircd/m_oper.c (m_oper): Remove references to CONF_LOCOP; replace
+       with CONF_OPERATOR or PRIV_PROPAGATE checks, as appropriate.
+
+       * ircd/s_conf.c (AuthorizationCheckResult, find_conf_exact):
+       Likewise.
+
+       * ircd/s_stats.c (report_array, statsinfo): Likewise.
+
+       * ircd/s_user.c (set_user_mode): Likewise.
+
+2004-05-15  Michael Poole <mdpoole@troilus.org>
+
+       * patches/diffs/astralnet.diff, patches/diffs/nocfv.diff: Remove
+       patches obsoleted by F: lines.
+
+       * patches/diffs/topicburst.diff: Remove patch that was integrated
+       into the main code.
+
+2004-05-15  Isomer <isomer@undernet.org>
+
+       [Original ChangeLog date: 2003-11-05 -MDP]
+
+       * ircd/m_whois.c: On remote whois, show +s local channels with a *
+       prefix to opers.
+
+2004-05-15  Michael Poole <mdpoole@troilus.org>
+
+       * include/gline.h, ircd/gline.c, ircd/s_err.c: Forward port a lot
+       of gline-related fixes from 2.10.11.  Things that work are due to
+       Kev, Isomer, Spike, hikari, and probably others; CVS makes it hard
+       to figure out who did what.  Any mistakes are mine.
+
+2004-05-15  Isomer <isomer@undernet.org>
+
+       [Original ChangeLog date: 2003-11-05 -MDP]
+
+       * ircd/s_misc.c, ircd/s_user.c: added numnick to SNO_CONNEXIT
+       messages (so you can match EXIT's to CONN's)
+
+2004-05-15  Reed Loden <reed@reedloden.com>
+
+       [Original ChangeLog date: 2003-05-01 -MDP]
+
+       * ircd/s_err.c: Added network to text and edited 001 a bit.
+
+       * ircd/s_user.c: Send network with 001.
+
+2004-05-15  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/s_user.c (add_target): Move free target invite check...
+
+       * ircd/s_user.c (check_target_limit): to here, matching 2.10.11's
+       behavior.
+
+2004-05-15  Isomer <isomer@undernet.org>
+
+       [Original ChangeLog date: 2003-11-23 -MDP]
+
+       * ircd/s_user.c: Don't credit users with an extra attempt if they
+       are klined/glined, throttle them!
+
+2004-05-15  Jeekay <jeekay@netgamers.org>
+
+       [Original ChangeLog date: 2003-04-24 -MDP]
+
+       * ircd/s_user.c: Altered (K-lined) to depend on find_kill type
+
+2004-05-15  splidge <splidge@quakenet.org>
+
+       [Original ChangeLog date: 2003-09-03 -MDP]
+
+       * ircd/s_user.c: Made hide_hostmask() not show bogus joins for
+       channels where the user is a zombie.
+
+2004-05-15  beware <steendijk@xs4all.nl>
+
+       [Original ChangeLog date: 2003-10-25 -MDP]
+       
+        * ircd/m_whois.c: Fixed /whois comma separated list with wildcards
+       cpu hog bug
+
+2004-05-15  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/s_conf.c (rehash): Call clear_quarantines on rehash since
+       2.10.11 does.  Show ident and IP for clients being killed by new
+       G-lines and K-lines.
+
+2004-05-15  hikari <shadow@undernet.org>
+
+       [Original ChangeLog date: 2003-06-27 -MDP]
+       
+       * ircd/ircd.c: After thought, update the next check time based on
+       when an unregistered client should expire.
+
+2004-05-15   hikari <shadow@undernet.org>
+
+       [Original ChangeLog date: 2003-06-22 -MDP]
+
+       * ircd/ircd.c: Fixed check_pings() - shouldn't be any problem with
+       clients not being able to connect anymore.
+
+2004-05-15  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/channel.c (can_join): Revert to using IsInvited() rather
+       than walking the list directly.
+       (modebuf_flush_int): Fix errant HEAD_IN_SAND_SNOTICES check to
+       use feature_bool(FEAT_HIS_SNOTICES) instead.
+
+2004-05-15  Kevin L Mitchell  <klmitch@mit.edu>
+
+       [Original ChangeLog date: 2004-01-31 -MDP]
+
+       * ircd/channel.c (mode_parse_key): don't allow , in keys!
+
+2003-04-12  David Mansell (splidge) <splidge@sf.net>
+
+       [Original ChangeLog date: 2003-04-14 -MDP]
+
+       * ircd/channel.c: When keys and limits conflict on burst, the key
+       which is first alphabetically or the limit which is lower will be 
+       used by both servers. This matches pre-2.10.11 behaviour.  
+       Closes: (#713930)
+
+2004-05-15  David Mansell <splidge@quakenet.org>
+
+       [Original ChangeLog date: 2002-12-28 -MDP]
+
+       * ircd/channel.c (mode_parse_limit): don't allow -l when no limit is
+       set, don't allow -l with negative parameter (or unsigned >2^31).
+2004-05-15  David Mansell <splidge@quakenet.org>
+
+       [Original ChangeLog date: 2002-12-31 -MDP]
+
+       * ircd/m_burst.c (ms_burst): when kicking net riders, clear
+       invites too.
+
+2004-05-15  Isomer <isomer@undernet.org>
+
+       [Original ChangeLog date: 2003-11-04 -MDP]
+
+       * ircd/s_serv.c: Burst glines/jupes early
+
+2004-05-15  volta <volta2@gmx.de>
+
+       [Original ChangeLog date: 2003-04-26 -MDP]
+
+         * ircd/m_userip.c, ircd/m_userhost.c: Small fix, that
+         allows users to see their own ip & hostname. (Should solve
+         all problems with dcc)
+
+2004-05-15  Kevin L Mitchell  <klmitch@mit.edu>
+
+       [Original ChangeLog date: 2003-06-13 -MDP]
+
+       * ircd/m_settime.c: it's supposed to be %ld, not %l
+
+2004-05-15  Isomer <isomer@undernet.org>
+
+       [Original ChangeLog date: 2004-03-20 -MDP]
+
+       * ircd/m_invite.c: Disallow invites to non existant channels
+
+2004-05-15  David Mansell <splidge@quakenet.org>
+
+       [Original ChangeLog date: 2003-04-26 -MDP]
+
+       * ircd/m_invite.c: let +k users invite into channels they aren't on.
+
+2004-05-15  hikari <shadow@undernet.org>
+
+       [Original ChangeLog date: 2003-07-13 -MDP]
+       
+       * ircd/IPcheck.c: Fixed (another) overflow problem in
+       ip_registry_check_local()
+
+       [Original ChangeLog date: 2003-06-29 -MDP]
+
+       * ircd/IPcheck.c: Fixed overflow problem in
+       ip_registry_connect_fail()
+
+2004-05-15 Isomer <isomer@undernet.org>
+
+       [Original ChangeLog date: 2003-05-02 -MDP]
+       
+       * ircd/IPcheck.c: Added assert()'s to check for underflow
+
+2004-05-15  Kevin L Mitchell  <klmitch@mit.edu>
+
+       [Original ChangeLog date: 2003-11-22 -MDP]
+
+       * tools/wrapper.c: commit uid on chroot fix from ubra
+
+       * ircd/version.c.SH: fix generation generation
+
+2004-05-15  Isomer <isomer@undernet.org>
+
+       [Original ChangeLog date: 2003-11-23 -MDP]
+       
+       * ircd/os_*.c, ircd/ircd_features.c: Default changing window sizes
+       to off.  if an admin is smart enough to understand these features
+       they can enable them manually.
+
+2004-05-15  splidge  <splidge@quakenet.org>
+
+       [Original ChangeLog date: 2003-03-26 -MDP]
+
+       * ircd/include/ircd_features.h, include/ircd_osdep.h,
+         ircd/ircd_features.c, ircd/listener.c, ircd/os_bsd.c, 
+         ircd/os_generic.c, ircd/os_linux.c, ircd/os_openbsd.c
+         ircd/os_solaris.c, ircd/s_bsd.c: Patch to allow socket bufs to be 
+         altered via F: lines
+
+2004-05-15  Isomer <isomer@undernet.org>
+
+       [Original ChangeLog date: 2003-11-18 -MDP]
+
+       * ircd/s_auth.c, ircd/res_libresolv.c, ircd/res_adns.c: Clean up
+       the preregistration subsystem allowing customisation of timers,
+       make the dns resolver stats oper only, and make it much more clear
+       what all the numbers are.
+
+2004-05-15  Spike <spike@undernet.org>
+
+       [Original ChangeLog date: 2003-11-23 -MDP]
+
+       * ircd/IPcheck.c: Make IPcheck constants configurable
+
+2004-05-14  Kevin L Mitchell  <klmitch@mit.edu>
+
+       [Original ChangeLog date: 2003-11-22 -MDP]
+
+       * ircd/m_nick.c (m_nick): truncate the nickname to the minimum of
+       the maximum allowed length (NICKLEN) or the allowed nickname
+       length specified as the NICKLEN feature
+
+       * ircd/ircd_features.c: declare NICKLEN and set its default value
+       to 9
+
+       * include/supported.h: add MAXNICKLEN to ISUPPORT and do a little
+       rearranging...
+
+       * include/ircd_features.h: add NICKLEN feature
+
+       * include/ircd_defs.h (NICKLEN): raise max NICKLEN to 15
+
+       * doc/readme.features: document new NICKLEN feature
+
+       * doc/example.conf: list new NICKLEN F-line
+
+2004-05-14  Matthias Crauwels <ultimate_@wol.be>
+
+       [Original ChangeLog date: 2003-06-08 -MDP]
+       
+       * ircd/gline.c: fixed the counting bug in gline_memory_count
+       * ircd/jupe.c: fixed the counting bug in jupe_memory_count
+
+2004-05-14  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/m_mode.c (ms_mode): Do not always try to call
+       set_user_mode() when parv[1] is a channel name.
+
+2004-05-10  Michael Poole <mdpoole@troilus.org>
+
+       Implement a per-connection-class default usermode option.
+
+       * doc/example.conf: Illustrate how to use the option.
+
+       * include/class.h (struct ConnectionClass): New "default_umode"
+       field.
+       (ConfUmode): New macro.
+
+       * include/client.h (client_get_default_umode): New function.
+
+       * ircd/client.c (client_get_default_umode): Implement it.
+
+       * ircd/ircd_lexer.l (usermode): New token.
+
+       * ircd/ircd_parser.y (classblock, etc): New syntax.
+
+       * ircd/s_user.c (register_user): Set default user modes for user.
+       This sends the new mode to the user, so the explicit send later
+       is no longer necessary.
+
+2004-05-10  Michael Poole <mdpoole@troilus.org>
+
+       Forward port of asuka-topicburst.patch from Quakenet's "Asuka"
+       patch set.
+
+       * include/ircd_features.h (FEAT_TOPIC_BURST): Add new feature.
+
+       * ircd/channel.c (send_channel_modes): If F:TOPIC_BURST:TRUE,
+       also send a TOPIC to the peer.
+
+       * ircd/ircd_features.c (FEAT_TOPIC_BURST): Add new boolean
+       feature, defaulting to FALSE.
+
+       * ircd/m_topic.c (do_settopic): Add argument for topic timestamp,
+       and allow F:HIS_BANWHO to hide the originator of the topic.
+       (ms_topic): Parse optional timestamp arguments to TOPIC, and use
+       them to decide whether to ignore the topic.
+
+2004-05-10  Michael Poole <mdpoole@troilus.org>
+
+       Forward port of delayed-join.patch from Quakenet's "Asuka" patch
+       set (which was a port of code I wrote for the other ircu).
+
+       * include/channel.h (CHFL_DELAYED): New membership flag.
+       (MODE_DELJOINS, MODE_WASDELJOINS): New channel modes.
+       (infochanmodes): Add +D to list of supported channel modes.
+       (IsDelayedJoin, SetDelayedJoin, ClearDelayedJoin): New macros.
+       (member_can_send_to_channel, client_can_send_to_channel): Add
+       "reveal" parameter to indicate whether a request should cause
+       a join-delayed user to become visible.
+       (RevealDelayedJoin, CheckDelayedJoins): New functions.
+
+       * include/numeric.h (RPL_DELNAMREPLY): New numeric.
+       
+       * include/s_user.h (NAMES_DEL): New flag for do_names().
+
+       * include/supported.h (FEATURESVALUES2): Add +D to list of
+       supported channel modes.
+
+       * ircd/channel.c (remove_member_from_channel,
+       member_can_send_to_channel, client_can_send_to_channel,
+       joinbuf_join): Handle join-delayed users.
+       (channel_modes, modebuf_flush_int, modebuf_mode, modebuf_flush,
+       modebuf_extract, mode_process_clients, mode_parse_mode,
+       mode_parse): Handle delayed-join channels.
+       (RevealDelayedJoin, CheckDelayedJoins): New functions.
+
+       * ircd/ircd_relay.c (relay_channel_message, relay_channel_notice,
+       server_relay_channel_message, server_relay_channel_notice): Add
+       argument for "reveal" parameter to client_can_send_to_channel().
+
+       * ircd/m_burst.c (ms_burst): Support MODE_DELJOINS channels.
+
+       * ircd/m_clearmode.c (do_clearmode): Support clearing mode +D.
+
+       * ircd/m_join.c (join0): Pass the CHFL_DELAYED flag when parting a
+       channel with JOIN 0.
+
+       * ircd/m_kick.c (m_kick): For join-delayed members, only send the
+       KICK to the kicker and kickee.  Then check whether +d can be
+       removed.
+
+       * ircd/m_names.c (do_names): Show join-delayed users if and only
+       if the NAMES_DEL flag is given.  If NAMES_DEL is given, also use
+       RPL_DELNAMREPLY instead of RPL_NAMREPLY.
+       (m_names): If NAMES -D, pass NAMES_DEL to do_names().
+
+       * ircd/m_part.c (m_part, ms_part): Add "reveal" argument for
+       member_can_send_to_channel().  Set CHFL_DELAYED join in joinbuf if
+       the user is join-delayed.
+
+       * ircd/m_quit.c (m_quit): Handle join-delayed users and new
+       argument for member_can_send_to_channel().
+
+       * ircd/m_topic.c (do_settopic): If a join-delayed channel member
+       changes the topic, reveal the member.
+
+       * ircd/m_wallchops.c (m_wallchops, ms_wallchops): Add argument for
+       "reveal" parameter to client_can_send_to_channel().
+
+       * ircd/m_wallvoices.c (m_wallvoices, ms_wallvoices): Likewise.
+
+       * ircd/m_who.c (m_who): Skip join-delayed members where we skip
+       zombies.
+
+       * ircd/m_whois.c (do_whois): Use '<' as a prefix for join-delayed
+       users.  Use slightly more efficient macros rather than function
+       calls to test for ops and voice.
+
+       * ircd/s_err.c (RPL_DELNAMREPLY): New numeric response string.
+
+       * ircd/s_user.c (hide_hostmask): For users with no modes in a
+       join-delayed channel, do not send JOIN to other members after the
+       QUIT :Registered.
+
+       * ircd/send.c (sendcmdto_common_channels_butone): Skip
+       join-delayed users where we skip zombies.
+       
+2004-05-10  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/ircd_events.c: Actually reference and try to use the epoll
+       event engine.  Omitted from yesterday's commit.
+
+2004-05-09  Michael Poole <mdpoole@troilus.org>
+
+       Forward port of Paul "Zoot" Chang's pseudo-command.patch and
+       pseudo-support.patch.
+
+       * doc/example.conf: Illustrate how to use the feature.
+
+       * include/handlers.h (m_pseudo): Declare new handler function.
+
+       * include/ircd_features.h (HIS_STATS_R): Add a feature to control
+       user visibility of the pseudo-commands.
+
+       * include/msg.h: Add flag and field for the extra information used
+       to select a pseudo-command's target.
+
+       * include/numeric.h (RPL_STATSRLINE, ERR_SERVICESDOWN): Add
+       definitions.
+
+       * include/parse.h (register_mapping, unregister_mapping): Declare.
+
+       * include/s_conf.h (struct nick_host, struct s_map,
+       GlobalServiceMapList): Define.
+
+       * ircd/Makefile.in: Add m_pseudo.c to IRCD_SRC.  Add generated
+       files to "make depend" dependency list.  Update dependencies.
+
+       * ircd/ircd_features.c (HIS_STATS_R): Define feature type and
+       default value.
+
+       * ircd/ircd_lexer.l (pseudo, prepend): Recognize new tokens.
+
+       * ircd/ircd_parser.y: Support "Pseudo" configuration blocks.
+
+       * ircd/parse.c (msgtab): Add initializer for field "extra" to all
+       commands.
+       (msg_tree_insert, msg_tree_remove, register_mapping,
+       unregister_mapping): New functions.
+       (parse_client): Implement MFLG_EXTRA extra argument passing.
+
+       * ircd/s_conf.c (GlobalServiceMapList): New variable.
+
+       * ircd/s_err.c (RPL_STATRLINE, ERR_SERVICESDOWN): Add format
+       strings for new numeric responses.
+
+       * ircd/s_stats.c (stats_mapping): New function.
+       (statsinfo): Add entry for /stats R and make old /stats r entry
+       case-sensitive.
+       
+2004-05-09  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/ircd_parser.y (parse_error): Convert to being a wrapper for
+       yyerror() so that configuration errors all go to the same place.
+
+       * ircd/s_conf.c: New variables conf_error and conf_already_read.
+       conf_error is cleared by read_configuration_file() and set by
+       yyerror(); conf_already_read is set by read_configuration_file()
+       and never cleared.  Make yyerror() display error to stderr before
+       conf_already_read is set.  Make configuration errors a fatal
+       condition in init_conf().
+
+2004-05-09  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/Makefile.in: Pass the source directory as an argument to
+       version.c.SH so it knows where to find the source files for an
+       out-of-srcdir build.
+
+       * ircd/version.c.SH: Use that information.
+
+2004-05-09  Michael Poole <mdpoole@troilus.org>
+
+       * Makefile.in: Ensure ${prefix}/include exists, since the adns
+       install puts files in that directory.  (The adns Makefile does
+       not use configure's ${includedir}.)
+
+2004-05-09  Michael Poole <mdpoole@troilus.org>
+
+       * doc/readme.features: The logic for F:AUTOHIDE was removed, but
+       not its documentation.  Fix that omission.
+
+       * include/ircd_features.h, ircd/ircd_features.c: Remove the unused
+       definitions for FEATURE_AUTOHIDE.
+
+2004-05-09  Michael Poole <mdpoole@troilus.org>
+
+       * doc/readme.who: Document the support for account matching and
+       display in the WHO command.
+
+2004-05-09  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/ircd.c (main): Move check_pid() call until after we read
+       the configuration file so that F:PPATH works correctly.
+
+2004-05-09  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/match.c (match): Use ToLower() instead of tolower() for
+       character comparisons.
+
+2004-05-09  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/s_user.c (register_user): Initialize "flag" (user's old
+       modes) passed to send_umode() so that the real set of modes are
+       sent to the user.
+       
+2004-05-09  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/m_server.c (ms_server): Apply +h/+s flags only to the new
+       server, not to a hub between us and the new server.
+
+       * ircd/ircd_relay.c (relay_directed_message): Check FLAG_SERVICE
+       on target server rather than FLAG_CHSERV (so that directed
+       messages work at all).
+
+2004-05-09  Michael Poole <mdpoole@troilus.org>
+
+       * configure.in: Add checks for epoll_* system call family.
+
+       * configure: Regenerate.
+
+       * ircd/engine_epoll.c: New file; forward ported from 2.10.11
+       branch.
+
+2004-05-09  Michael Poole <mdpoole@troilus.org>
+
+       * include/ircd_alloc.h: Add definitions for MyRealloc, since they
+       are needed by kqueue and epoll event engines; kill #if 0'd block.
+
+       * include/memdebug.h: Declare dbg_realloc() helper function.
+
+       * ircd/ircd_alloc.c: Implement DoRealloc() helper function.
+
+       * ircd/memdebug.c: Implement dbg_realloc() helper function.
+
+2004-05-09  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/channel.c (find_no_nickchange_channel): Disallow nick
+       changes on a moderated channel with neither ops nor voice.
+
+       * ircd/s_err.c: Update ERR_BANNICKCHANGE message to match.
+
+2004-01-20  Perry Lorier <isomer@undernet.org>
+
+       * ircd/ircd_parser.y: Fixed parser to work with a more modern bison
+
+2004-01-21 Gavin Grieve <hektik@dimebox.net>
+
+       * ircd/channel.c, include/channel.h: bring forward the IsUserParting()
+         code to resolve the multiple part messages bug written by Entrope.
+
+2003-08-12 Timothy Vogelsang <net@astrolink.org>
+
+        * ircd/match.c: (match) rewrote function based on existing
+          code from the hybrid ircd -- death to goto
+
+2003-07-07  Bas Steendijk <steendijk@xs4all.nl>
+
+        * ircd/s_user.c: invalidate ban cache for user on host hiding/account
+
+2003-07-04  Bas Steendijk <steendijk@xs4all.nl>
+
+        * include/client.h, ircd/m_userhost.c, ircd/m_userip.c, ircd/m_who.c,
+        ircd/m_whois.c, ircd/whocmds.c: the same code, for "can user A see user
+        B is an oper", appeared in a lot of places. made it a define SeeOper.
+
+2003-07-04  Bas Steendijk  <steendijk@xs4all.nl>
+        * ircd/s_user.c: umode_str (user modes in N token) internal flags var
+       was not initialized to the user's flags, returned a string with
+       random modes set.
+
+2003-07-01  Bas Steendijk  <steendijk@xs4all.nl>
+
+        * ircd/m_names.c: length counter being incremented one too many
+        for each nick, resulting names reply messages are about 50 chars
+        shorter than possible. fixed.
+
+2003-06-29  Bas Steendijk  <steendijk@xs4all.nl>
+
+        * ircd/channel.c: don't ever send mode changes for local channels to
+       servers.
+
+2003-06-27  Bas Steendijk  <steendijk@xs4all.nl>
+
+        * include/channel.h, include/client.h, ircd/s_user.c, ircd/s_err.c:
+        moved the supported channel/user mode strings of the 004 reply from
+        s_err.c to the header files where the channels/user modes are
+        defined, and show or hide +Au based on OPLEVELS setting.
+
+2003-06-25  Bas Steendijk  <steendijk@xs4all.nl>
+
+        * ircd/m_burst.c: Clear topic set by netrider on burst.
+
+2003-08-05 Diane Bruce  <db@db.net>
+
+        * ircd/parse.c: Fixed the typo the fix of the typo created
+
+2003-08-01 Diane Bruce  <db@db.net>
+
+       * ircd/parse.c: Fixed typo
+
+2003-06-22  Diane Bruce  <db@db.net>
+
+       * ircd/parse.c: Completely rewritten June 2, 2003 - Dianora
+
+2003-06-22  Bas Steendijk  <steendijk@xs4all.nl>
+
+        * include/ircd_features.h, include/supported.h, ircd/ircd_features.c,
+       ircd/ircd_features.c, ircu2.10/ircd/m_join.c, doc/example.conf: 
+       Make ability to create local channels a feature which can be disabled.
+
+2003-06-22  Bas Steendijk  <steendijk@xs4all.nl>
+
+       * include/ircd_features.h, ircd/channel.c, ircd/ircd_features.c,
+       ircd/m_kick.c, doc/example.conf: Added OPLEVELS feature, which
+       makes it possible to disable the +Au/oplevels functions.
+
+2003-06-17  Alex Badea  <vampire@p16.pub.ro>
+
+       * ircd/res_adns.c: included sys/types.h, for non-Linux
+       headers
+
+2003-03-06  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * libs/dbprim: database primitives library, including
+       flexible linked lists, auto-resizing hash tables, and sparse
+       matrices.  Has a test suite for everything but portions of
+       the sparse matrix routines (I'm lazy; someone help me write
+       them!).  Documentation generated by doxygen--feel free to
+       critique, suggest phrasing improvements, etc.
+
+2003-01-22  Kevin L. Mitchell  <klmitch@mit.edu>
+       * libs: put third-party libraries in this subdirectory.
+       Started by copying adns into it--will fix the rest and remove
+       the top-level copy later.
+
+2003-01-14  Andrew Miller <a1kmm@mware.virtualave.net>
+       * ircd/m_settime.c: Fixed a minor format string issue.
+       
+2003-01-12  Thomas Helvey <tom.helvey@cox.net>
+       * adns/src/check.c, adns/src/transmit.c, ircd/m_opmode.c,
+       ircd/motd.c, ircd/s_user.c: Cleanup warnings, fix precedence
+       bugs in transmit.c and m_opmode.c.
+
+2003-01-12  Thomas Helvey <tom.helvey@cox.net>
+       * include/class.h, include/ircd_string.h, ircd/class.c,
+       ircd/gline.c, ircd_string.c: Fix undefined order
+       of evaluation bug in gline.c, add general purpose hasher for
+       conf entries. 
+
+2003-01-11  Thomas Helvey <tom.helvey@cox.net>
+       * include/channel.h, include/ircd_alloc.h, ircd/channel.c,
+       ircd/client.c, ircd/gline.c, ircd/ircd_alloc.c,
+       ircd/ircd_events.c, ircd/ircd_log.c, ircd/ircd_parser.y,
+       ircd/ircd_snprintf.c, ircd/listener.c, ircd/m_nick.c,
+       ircd/m_opmode.c, ircd/m_whois.c, ircd/motd.c,
+       ircd/s_auth.c, ircd/s_bsd.c, ircd/uping.c: Server compiles
+       with g++ again, type safety, const correctness fixes,
+       remove C++ keywords again :/
+
+2003-01-11  Thomas Helvey <tom.helvey@cox.net>
+       * ircd/client.c, ircd/ircd_feature.c: Bugfix, the feature
+       table data was in a different order than the feature data
+       structure, which resulted in a wild index being used in
+       feature_bool. The feature_bool function didn't check it's
+       index before indexing the features array resulting in
+       a core dump on /oper.
+
+2003-01-10  Thomas Helvey <tom.helvey@cox.net>
+       * include/client.h, include/res.h, include/s_bsd.h,
+       ircd/ircd.c, ircd/list.c ircd/m_connect.c, ircd/res_adns.c,
+       ircd/res_libresolv.c, ircd/s_auth.c, ircd/s_bsd.c, ircd/s_conf.c:
+       Remove resolver cache wart, change hostent representation, cleanup
+       resolver clients.
+
+2003-01-10  Thomas Helvey <tom.helvey@cox.net>
+       * ircd/map.c, ircd/Makefile.in, include/map.h: Remove 
+        HEAD_IN_SAND macros to get server to build, rebuild dependencies.
+
+2003-01-08  Fredrik Soderblom <froo@quakenet.org>
+        * ircd/s_err.c, ircd/s_user.c (hide_hostmask): Simplify
+        RPL_HOSTHIDDEN and the use of it.
+
+2003-01-07  Kevin L Mitchell  <klmitch@mit.edu>
+
+       * BUGS: removed from distribution
+
+       * ChangeLog.07: moved into doc/history
+
+       * ChangeLog.10: moved into doc/history
+
+       * INSTALL: pulled up from u2.10.11.04
+
+       * README: pulled up from u2.10.11.04
+
+       * README.FreeBSD: pulled up from u2.10.11.04
+
+       * README.Solaris: pulled up from u2.10.11.04
+
+       * RELEASE.NOTES: add sysctl note from u2.10.11.04
+
+       * TODO: removed from distribution
+
+       * configure.in: add extra check for res_mkquery; remove
+       --disable-headinsand since it no longer has any effect; pull up
+       "Enable" vs. "Disable" changes from u2.10.11.04
+
+       * doc/readme.asll: pulled up from u2.10.11.04
+
+       * doc/readme.features: pull up missing documentation, including a
+       couple of corrections
+
+       * doc/readme.log: correct text to read FACILITY instead of SYSLOG
+       in the documentation for configuring syslog facility
+
+       * include/channel.h: declare IsInvited()
+
+       * include/handlers.h: do some minor reorderings
+
+       * include/ircd_defs.h: remove deprecated NETWORK and URL_CLIENTS
+       #define's
+
+       * include/ircd_policy.h: removed from the distribution
+
+       * include/jupe.h: declare jupe_memory_count()
+
+       * include/msgq.h: remove MsgCounts structure
+
+       * include/numeric.h: add a blank line after RPL_STATSQLINE; add
+       RPL_HOSTHIDDEN
+
+       * include/s_stats.h: include ircd_features.h for definition of the
+       enum; remove extraneous declarations
+
+       * ircd/Makefile.in: add LDFLAGS to table_gen
+
+       * ircd/engine_poll.c: remove commented-out assertion
+
+       * ircd/ircd.c: include s_stats.h and call stats_init()
+
+       * ircd/ircd_features.c: feature names have to be case-sensitive
+       because of some of the HIS features
+
+       * ircd/ircd_relay.c: reorder includes
+
+       * ircd/m_account.c: include string.h for strlen()
+
+       * ircd/m_clearmode.c: remove extraneous clean_channelname(); make
+       sure to refer to chname, not parv[1]
+
+       * ircd/m_create.c: remove the broken code that squits servers that
+       are >5 minutes fast; fix "badop || CHFL_CHANOP" bug that caused op
+       desyncs
+
+       * ircd/m_gline.c: if it's a server, force the gline; don't
+       gline_find() before determining if the oper had the privilege
+
+       * ircd/m_kick.c: kicks by servers should appear to be from the
+       local server thanks to HIS
+
+       * ircd/m_lusers.c: needs ircd_features.h, not ircd_policy.h
+
+       * ircd/m_map.c: needs ircd_features.h, not ircd_policy.h
+
+       * ircd/m_nick.c: added an assertion and some explanatory comments
+       pulled up from u2.10.11.04
+
+       * ircd/m_opmode.c: no longer requiring oper to be on the channel;
+       search for quarantines before allowing ops
+
+       * ircd/m_privmsg.c: one character typo that probably means nothing
+
+       * ircd/m_settime.c: add back comments I left in the code
+
+       * ircd/m_squit.c: remove protocol_violation() notices
+
+       * ircd/m_userhost.c: return realhost if user is an oper
+
+       * ircd/m_wallvoices.c: only m_wallvoices() should add a +
+
+       * ircd/m_who.c: add handling for the 'a' field
+
+       * ircd/m_whois.c: correct a typo of FEAT_HIS_SERVERNAME for
+       FEAT_HIS_SERVERINFO
+
+       * ircd/s_bsd.c: close file descriptors 0, 1, and 2; pull up some
+       ancient bug fixes from the u2.10.11 branch
+
+       * ircd/s_debug.c: include gline.h, jupe.h, motd.h, and s_stats.h;
+       call motd_memory_count(), gline_memory_count(), and
+       jupe_memory_count() when reporting memory usage; add back a
+       comment regarding "DBuf caveats"
+
+       * ircd/s_err.c: add RPL_STATSQLINE, RPL_HOSTHIDDEN, and pull up
+       change to ERR_NOPRIVILEGES wording
+
+       * ircd/s_misc.c: include ircd_features.h and not ircd_policy.h
+
+       * ircd/s_stats.c: count from 0 and not 1 when initializing the
+       stats
+
+       * ircd/s_user.c: comment out assertion; remove extraneous
+       definition of FLAGS_HOST_HIDDEN; add in hikari's "your host is now
+       hidden" reply; don't detach oper confs unless sptr is not an oper
+
+       * ircd/table_gen.c: pull up change to NTL_CHPFX (removing +);
+       change channel name character range to be from '\041' (!) to
+       UCHAR_MAX
+
+       * ircd/whocmds.c: pull up fix to /who idle time from u2.10.11.04
+
+       * tools/linesync/linesync.conf: pull up from u2.10.11.04
+
+       * tools/linesync/linesync.sh: pull up from u2.10.11.04
+
+2003-01-07 Andrew Miller <a1kmm@mware.virtualave.net>
+       * almost everything: Forward ported numerous changes from .11 to .12
+       
+2002-07-05 Andrew Miller <a1kmm@mware.virtualave.net>
+       * ircd/packet.c(connect_dopacket): Pass the job on to server_dopacket
+       when they become a server.
+       * ircd/s_bsd.c(read_packet): Check they are now a server *after* the
+       packet is sent.
+       * ircd/class.c(make_class): Fixed an assert to be more useful.
+       
+2002-07-05 Andrew Miller <a1kmm@mware.virtualave.net>
+       * ircd/packet.c
+       * ircd/packet.h: (connect_dopacket): Made a dopacket function for
+       connecting links which sends the messages through the correct message
+       handler.
+       * ircd/s_bsd.c(read_packet): Put packets through the correct handler
+       for connecting links. Properly handle unknown links becoming
+       connecting or servers.
+
+2002-07-01 Andrew Miller <a1kmm@mware.virtualave.net>
+       * include/ircd_alloc.h (MyFree): Accept NULL pointers to do nothing
+       with, this is used quite a lot.
+       * ircd/class.c (make_class): Initialise the ref_count to 1 so that
+       we don't leak.
+       * ircd/class.c (add_class): When updating a class, free the old name
+       first to prevent leakage.
+       * ircd/class.c (class_delete_marked): Decrement the ref_count for the
+       class after it is removed from the linked list.
+       * ircd/ircd_parser.y: Changed a free to MyFree().
+       * ircd/ircd_parser.y: Removed a few debugging messages.
+
+2002-07-01 Andrew Miller <a1kmm@mware.virtualave.net>
+       * s_bsd.c (read_packet): Our daily addition to the list of entities to
+       treat as servers - Connecting servers.
+       
+2002-07-01 Andrew Miller <a1kmm@mware.virtualave.net>
+       * doc/debug_memleak_gc.patch,
+       * include/ircd_ircd_alloc.h,
+       * include/memdebug.h,
+       * configure.in,
+       * ircd/Makefile.in,
+       * ircd/memdebug.c: added a Boehm's gc based leak detector to find leaks
+       and notify the operators.
+       
+2002-06-29  Andrew Miller <a1kmm@mware.virtualave.net>
+
+       * ircd/s_bsd.c (read_packet): don't make handshaking servers go through
+       the dbufs.
+       
+2002-06-18  Andrew Miller <a1kmm@mware.virtualave.net>
+
+       * ircd/s_bsd.c (read_packet): don't allow unregistered clients to flood
+       the server.
+       
+2002-06-18  Alex Badea  <vampire@p16.pub.ro>
+
+       * ircd/m_burst.c (ms_burst): kick local members if the channel
+       has a larger local TS and it's +i or +k remotely (anti net.ride)
+
+       * ircd/ircd_parser.y: fixed a bug that broke IP-based C:lines
+
+       * ircd/s_err.c: connection classes are now strings (RPL_STATSCLINE)
+
+       * include/s_conf.h: externalized lookup_confhost
+
+       * adns/Makefile.in: compilation-outside-source-tree fix
+
+2002-06-17  Alex Badea  <vampire@p16.pub.ro>
+
+       * adns/*: added a slightly hacked copy of adns
+
+       * configure.in: added a --disable-adns switch if you want
+       to use the old libresolv res.c
+
+       * configure: ran autoconf
+
+       * ircd/res_libresolv.c: renamed from res.c
+
+       * ircd/res_adns.c: added adns resolver
+
+2002-06-17  Alex Badea  <vampire@p16.pub.ro>
+
+       * ircd/ircd_parser.y: fixed 'Connect' block processing so now
+       you can actually connect to other servers
+
+2002-06-04  Alex Badea  <vampire@p16.pub.ro>
+
+       * ircd/m_stats.c (report_servers_verbose): oops, fixed it so
+       it displays all servers, not just local connects
+
+2002-05-30  Jean-Edouard Babin  <Jeb@jeb.com.fr>
+
+       * ircd/m_server.c (mr_server): fixed core bug on insufficient
+       arguments
+
+2002-05-26  Jeekay  <jeekay@irc.planetarion.com>
+       
+       * ircd/m_join.c (HasControlChars): fixed unsigned vs signed
+
+2002-05-26  Jeekay  <jeekay@irc.planetarion.com>
+       * ircd/m_join.c (m_join,HasControlChars): check if a channel
+       name has any control chars (<=32) in it before allowing a
+       local user to join.
+2002-21-05 Andrew Miller <a1kmm@mware.virtualave.net>
+       * ircd/ircd_relay.c: stop an information leak about the
+       the network topography from relayed messages.
+
+2002-04-19  Alex Badea  <vampire@p16.pub.ro>
+
+       * ircd/m_who.c (m_who): disallow non-opers to /who server.name
+
+2002-04-18  Alex Badea  <vampire@p16.pub.ro>
+
+       * ircd/s_err.c (RPL_STATSILINE): connection classes are now
+       strings
+
+2002-04-17  beware <steendijk@tomaatnet.nl>
+
+       * m_whois.c (m_whois): disallow remote queries for non-existent
+       local users when originated by a non-oper
+
+2002-04-16  Alex Badea  <vampire@p16.pub.ro>
+
+       * ircd/s_user.c (hunt_server_cmd): also send a "no such server"
+       reply if the servername contains a '*' and it doesn't exist
+
+       * include/patchlevel.h (PATCHLEVEL): bump patchlevel
+
+2002-04-16  beware <steendijk@tomaatnet.nl>
+
+       * ircd/m_whois.c: the previous patch broke whois, fixed it
+       another way
+
+       * ircd/m_admin.c: cleaned up m_admin too while we're here,
+       hunt_server_cmd can do all the work for us
+
+2002-04-15  Alex Badea  <vampire@p16.pub.ro>
+
+       * ircd/m_stats.c: added verbose server reporting (/stats v
+       or /stats V for machine-readable format) (bugzilla bug 52)
+
+       * include/numeric.h: added RPL_STATSVERBOSE 236
+
+       * ircd/s_err.c: added RPL_STATSVERBOSE
+
+       * ircd/s_stats.c: added help for stats 'v'
+
+2002-04-15  Alex Badea  <vampire@p16.pub.ro>
+
+       * ircd/class.c (get_client_class): fixed typo which caused
+       /trace (and perhaps motd) to core
+
+2002-04-15  beware <steendijk@tomaatnet.nl>
+
+       * ircd/m_whois.c: Fixed /whois servermask nomatch bug
+       where normal users could use the function to discover servers,
+       also the NOSUCHSERVER check code was missing.
+
+2002-04-14  Alex Badea  <vampire@p16.pub.ro>
+
+       * ircd/ircd_parser.y: fixed cli_info(&me) not being set
+       from 'description' conf
+
+2002-04-13  Stephane Thiell <mbuna@undernet.org>
+
+       * ircd/m_whois.c: removed FindUser() in ms_whois to fix
+       remote whois relaying.
+
+       * ircd/class.c: removed unused (and duplicated) code
+       get_client_ping().
+       
+       * include/class.h: removed unused function prototype.
+       
+       * config.guess: upgraded with latest
+       
+       * config.sub: upgraded with latest
+
+2002-04-12  Alex Badea  <vampire@p16.pub.ro>
+
+       * ircd-patch: report which files failed the dry run (so the
+       user may force the patch if the rejects are in less-than-vital
+       files, such as ChangeLog or documentation)
+
+2002-04-12  Alex Badea  <vampire@p16.pub.ro>
+
+       * ircd/m_invite.c: don't propagate invites for local channels
+
+       * include/patchlevel.h (PATCHLEVEL): bump patchlevel
+
+2002-04-10 Joseph Bongaarts <foxxe@wtfs.net>
+
+       * ircd/ircd.c: The last fix broke autoconnects completely.
+       Fixed it another way.
+       
+2002-04-09  Brian Cline  <clineb@cs.winthrop.edu>
+
+        * ircd/ircd.c (try_connections): To avoid problems with infinite event
+        loops, don't try connecting to servers whose connect frequency is 0.
+       
+2002-04-10  Alex Badea  <vampire@p16.pub.ro>
+
+       * ircd/ircd_parser.y: fixed a "features" block parse bug
+
+       * tools/convert-conf.py: added a configuration file converter
+       from 2.10.11 to 2.10.12 format
+
+       * ircd-patch: added GPL information to top of file
+
+2002-04-09  Alex Badea  <vampire@p16.pub.ro>
+
+       * configure.in: added a human-readable report of configured
+       options at the end of the configure process
+
+       * configure: regenerated with autoconf
+
+2002-04-08  Gavin Grieve  <ggrieve@ihug.co.nz>
+
+       * include/supported.h: change CHARSET to CASEMAPPING after
+       discussions as to what would be the preferred name.
+
+2002-04-05 Andrew Miller <a1kmm@mware.virtualave.net>
+       * ircd/s_conf.c, ircd_parser.y, ircd_lexer.l: Add privilege
+       specification.
+        * Fix a minor parser bug that meant rehash didn't always
+       work correctly.
+
+2002-04-03  Alex Badea  <vampire@p16.pub.ro>
+
+       * include/channel.h: fix compiler warnings (paratheses around &&)
+
+       * ircd/channel.c (modebuf_extract): fix compiler warnings
+       (uninitialized variables)
+
+       * ircd/Makefile.in: make ircd properly compile outside the
+       source tree
+
+2002-04-03  Alex Badea  <vampire@p16.pub.ro>
+
+       * include/s_user.h: added a sptr parameter to InfoFormatter
+       function type
+
+       * ircd/m_who.c: don't match IPs for clients which have a hidden host,
+       except when the inquiring user is an oper
+
+       * ircd/whocmds.c: show the fake IP from FEAT_HIDDEN_IP if the
+       target has a hidden host, but show real IP to opers
+
+       * ircd/m_userip.c (userip_formatter): add sptr parameter; show the
+       fake IP from FEAT_HIDDEN_IP if the target has a hidden host, but
+       show real IP to opers
+
+       * ircd/m_userhost.c (userhost_formatter): add (unused) sptr parameter
+
+       * ircd/s_user.c (send_user_info): pass sptr to the formatting function
+
+       * include/ircd_features.h: new feature FEAT_HIDDEN_IP (stores which
+       fake IP to show for clients with a hidden host)
+
+       * ircd/ircd_features.c: new feature FEAT_HIDDEN_IP
+
+       * doc/example.conf: default value for FEAT_HIDDEN_IP
+
+       * doc/readme.features: documented FEAT_HIDDEN_IP
+
+2002-04-03 Andrew Miller <a1kmm@mware.virtualave.net>
+       * doc/example.conf: Cleaned up some comments that ended up in
+         strange places due to problems in the merge process.
+       * ircd/m_nick.c: Cleaned up ms_nick, and fixed a bug that
+         probably dates back to Jarkko code.
+
+2002-04-02  Kevin L Mitchell  <klmitch@mit.edu>
+
+       * ircd/m_kill.c: let ms_kill() and mo_kill() seperate the message
+       from the path before calling do_kill(); add a msg argument to
+       do_kill() and use it in preference to comment; remove all that old
+       code that fiddled with the buf and the comment
+
+       * ircd/ircd_log.c (log_write_kill): add a seperate msg argument
+
+       * include/ircd_log.h: add a seperate msg argument to
+       log_write_kill()
+
+       * ircd/ircd.c: display event engine and MAXCONNECTIONS information
+2002-04-02  Alex Badea <vampire@p16.pub.ro>
+
+       * ircd-patch: Automatically generate a version string from patches
+
+2002-04-02  Alex Badea <vampire@p16.pub.ro>
+       
+       * ircd-patch: Test before doing anything dangerous, provide -f to
+               to it anyway.  exit levels for easy scripting.
+
+2002-04-01  Kevin L Mitchell  <klmitch@mit.edu>
+
+       * ircd/channel.c (joinbuf_join): don't add a channel to the list
+       in the joinbuf unless when we flush it, we empty the list
+
+2002-04-02 Andrew Miller <a1kmm@mware.virtualave.net>
+       * ircd/ircd_parser.y: Added ircd parser, lexer, to replace the
+          old configuration file format.
+       * ircd/ircd_lexer.l
+       * ircd/s_conf.c
+       * doc/example.conf
+
+2002-03-23 Bert Faes <bert.faes@pandora.be>
+
+       * s_misc.c made /trace reply always show the username
+       
+2002-03-28  Kevin L Mitchell  <klmitch@mit.edu>
+
+       * configure.in: use AC_CHECK_FUNCS to define HAVE_* macros; test
+       for setrlimit, getrusage, and times
+
+       * configure: rerun auto-conf
+
+       * config.h.in: rerun autoheader
+
+2002-03-27  Kevin L Mitchell  <klmitch@mit.edu>
+
+       * ircd/m_burst.c (ms_burst): use MODEBUF_DEST_NOKEY to suppress
+       sending of the key to the channel
+
+       * ircd/channel.c (modebuf_flush_int): when processing keys, only
+       include the actual key in the mode sent to the channel if
+       MODEBUF_DEST_NOKEY is not set
+
+       * include/channel.h: needed more bits for MODEBUF_DEST_*,
+       especially when adding MODEBUF_DEST_NOKEY to force keys in the
+       BURST to be reported as "*" to the channel
+
+       * ircd/m_oper.c (m_oper): clear the new oper's sendq so it gets
+       inherited from the class associated with the O-line
+
+2002-03-25  Kevin L Mitchell  <klmitch@mit.edu>
+
+       * ircd/s_user.c (set_nick_name): invalidate all ban valid caching
+       when a user changes his nickname so we can catch if he now matches
+       a ban
+
+2002-03-20 Reed Loden <reed@redmagnet.com>
+       * doc/example.conf: Added OPER_LIST_CHAN and LOCOP_LIST_CHAN.
+
+       * doc/readme.features: Added OPER_LIST_CHAN and LOCOP_LIST_CHAN.
+
+2002-03-20 LordLuke <lordluke@undernet.org>
+       * ircd/client.c: Add LOCOP_LIST_CHAN feature.
+
+       * ircd/ircd_features.h: Add LOCOP_LIST_CHAN feature.
+
+2002-03-19 Joseph Bongaarts <foxxe@wtfs.net>
+
+       * ircd/m_links.c: Make /links behave like /map for head_in_sand.
+       cleaned up excess code.
+
+       * ircd/map.c: Added map_dump_links_head_in_sand() Made changes in
+       map_add() and map_update() for links changes.
+
+       * include/map.h: Added info and prot to struct Map
+
+       * include/ircd_defs.h: Added MAP_CACHE_TIME for length of time
+       servers are cached in MapList
+
+       * ircd/s_misc.c: changed #ifdef for map_update()
+
+       * ircd/m_server.c: changed #ifdef for map_update()
+
+       * include/ircd_policy.h: added NO_HEAD_IN_SAND for easier removal of
+       hiding features.
+
+       * configure.in: add --disable-headinsand
+
+       * configure: Ran autoconf
+
+       * ircd/m_stats.c: Fixed a bug in /stats i and made /stats i show 
+       connect limits
+
+       * ircd/s_stats.c: Made /stats i report connect limits
+
+       * ircd/s_err.c: Modified RPL_STATSILINE to use %s instead of 
+       "*" for the password field.
+       
+2002-03-19 LordLuke <lordluke@undernet.org>
+
+       * include/channel.h: Allow opers to view +s channels in /list
+
+       * include/client.h: Add "PRIV_LIST_CHAN" oper privilege
+
+       * include/ircd_features.h: added "LIST_CHAN" feature
+
+       * ircd/channel.c: Allow opers to view +s channels in /list
+
+       * ircd/client.c: Add "PRIV_LIST_CHAN"
+
+       * ircd/ircd_features.c: Add "LIST_CHAN" feature
+
+2002-03-13 Joseph Bongaarts <foxxe@wtfs.net>
+
+       * ircd/m_kill.c: Last of the last of the bug fixes (Thanks Spike).
+       Must be more careful when forward porting by hand...
+       
+2002-03-13  Carlo Wood  <run@alinoe.com>
+
+       * include/channel.h: CHFL_CHANNEL_MANAGER, new local
+       channel flag set when someone creates a channel or joins
+       using the Apass.  IsChannelManager(), SetChannelManager():
+       macros to manipulate new channel flag.
+       channel_modes: Added new argument to avoid calling
+       find_member_link more often than needed.
+
+       * include/numeric.h: RPL_APASSWARN, ERR_NOTLOWEROPLEVEL,
+       ERR_NOTMANAGER, ERR_CHANSECURED, ERR_UPASSSET,
+       ERR_UPASSNOTSET: new numeric replies.
+
+       * ircd/channel.c: is_level0_op: removed.
+       member_can_send_to_channel: disallow channel manager
+       to talk.  channel_modes: show upass to level0 ops.
+       mode_parse_upass: Only the channel manager is allowed
+       to change the upass.  Only allow to set upass when apass
+       is also set.  mode_parse_apass: Don't allow to change the
+       Apass if the channel is older than 48 hours.  Only allow
+       to remove the apass when upass is not set.  Send clear
+       warnings regarding the importance of apass.
+       mode_process_clients: Don't change the oplevel of an opped
+       member in a channel where upass is not set.
+
+       * ircd/destruct_event.c: exec_expired_destruct_events:
+       Bug fix: send DESTRUCT message when destructing a channel.
+
+       * ircd/m_destruct.c: ms_destruct: Bug fix: use self as
+       prefix for DESTRUCT message.
+
+       * ircd/m_join.c: m_join: Handle apass and upass.
+
+       * ircd/m_kick.c: m_kick: Don't allow to kick member with
+       a higher or equal op-level.
+
+       * ircd/m_mode.c: m_mode: Now pass member to channel_modes.
+       ms_mode: Allow server to do modes on channels with apass
+       set.
+
+       * ircd/s_err.c: RPL_APASSWARN, ERR_NOTLOWEROPLEVEL,
+       ERR_NOTMANAGER, ERR_CHANSECURED, ERR_UPASSSET,
+       ERR_UPASSNOTSET: new numeric replies.
+
+
+2002-03-10 Joseph Bongaarts <foxxe@wtfs.net>
+
+       * ircd/m_kill.c: Last of the bug fixes for do_kill()
+
+       * ircd/list.c: Don't remove clients from the linked list
+       that aren't actually in the list.
+       
+2002-03-08  Carlo Wood  <run@alinoe.com>
+       * include/channel.h: Added CHFL_BURST_ALREADY_OPPED
+       and CHFL_BURST_ALREADY_VOICED.
+
+       * ircd/m_burst.c: Allow BURST outside net-burst
+       and take into account that users are already joined
+       to the channel in that case.
+
+       * ircd/m_destruct.c: Implementation of DESTRUCT
+       handling code.
+
+       * ircd/m_join.c: Set the channel creationtime to
+       the timestamp of a message when that timestamp is
+       smaller.
+2002-02-27 Reed Loden <reed@redmagnet.com>
+       * tools/crypter: Updated some variables, added another notice,
+       added CVS Id tag, and updated Perl location.
+
+       * tools/ringlog.c: Added IRC - Internet Relay Chat, 
+       tools/ringlog.c
+
+       * tools/ringlog.pl: Added IRC - Internet Relay Chat, 
+       tools/ringlog.pl
+
+       * tools/wrapper.c: Added IRC - Internet Relay Chat, 
+       tools/wrapper.c
+
+       * tools/mkpasswd.c: Added CVS Id tag
+
+       * tools/sums: Updated to comply with sums being moved to tools/
+       and added CVS Id tag
+
+       * tools/README: Updated location of file and partly rewrote to fit 
+       u2.10.11's Features
+
+       * tools/Makefile.crypt: Updated location of file and added CVS Id 
+       tag
+
+       * acconfig.h: Updated location of file
+
+       * config.h.in: Updated location of file
+
+       * tools/Bounce/bounce.conf: Added CVS Id tag
+
+       * tools/Bounce/Bounce.cpp: Updated location of file
+
+       * tools/Bounce/Bounce.h: Updated location of file
+
+       * tools/hashtoy: Added CVS Id Tag
+
+2002-02-27  Carlo Wood  <run@alinoe.com>
+
+        * /ircd/ircd.c: check_pings: First check if a PING was sent at all.
+
+2002-03-01  Carlo Wood  <run@alinoe.com>
+
+       * include/channel.h: struct Channel: new attribute destruct_event.
+       Prototype for destruct_channel().
+
+       * include/destruct_event.h: new header file for destruct_event.c.
+
+       * ircd/Makefile.in: New source file: destruct_event.c.
+
+       * ircd/channel.c: sub1_from_channel: Don't destruct channel
+       immedeately but instead schedule it for destruction after
+       some time when a channel becomes empty (and clear invite
+       only and limit in that case).
+       destruct_channel: new function, was previously the destructing
+       part of sub1_from_channel.
+       add_user_to_channel: remove destruction request if any.
+
+       * ircd/destruct_event.c: New file.  Implementation of functions
+       schedule_destruct_event_1m, schedule_destruct_event_48h,
+       remove_destruct_event and exec_expired_destruct_events.
+
+       * ircd/ircd.c: destruct_event_timer: new timer.
+       main: use destruct_event_timer to call exec_expired_destruct_events
+       once per minute.
+
+       * ircd/m_endburst.c: ms_end_of_burst: Don't complain about empty
+       channels.  Schedule new empty channels for destruction.
+
+       * ircd/m_join.c: m_join: Destruct just-created channel immedeately.
+
+2002-03-01  Carlo Wood  <run@alinoe.com>
+       * ircd/s_misc.c: exit_client: Only call map_update()
+       for servers.
+
+2002-02-28  Carlo Wood  <run@alinoe.com>
+       * include/channel.h: New attribute 'oplevel' in struct Membership.
+       Added defines MAXOPLEVELDIGITS and MAXOPLEVEL.
+       New macros:  OpLevel(member): returns op-level of member and
+       SetOpLevel(member, value): sets op-level of member.
+       Prototype of add_user_to_channel: add oplevel to parameters.
+       Prototype of mode_parse: add member to to parameters.
+
+       * include/numeric.h: added ERR_NOTLOWEROPLEVEL.
+
+       * ircd/s_err.c: idem.
+
+       * ircd/channel.c: Removed unmatched '{' braces from comments
+       (confuses vi).  add_user_to_channel: oplevel is passed to function
+       and added in the created MemberShip structure.  send_channel_modes:
+       Generate the nick:mode list of the BURST msg in the new style (with
+       op-levels).  DONE_UPASS/DONE_APASS: fixed typo in comment.  struct
+       ParseState: New attribute: member.  mode_process_clients: Disallow
+       deopping someone with an equal or higher op-level, take care of
+       inheritance of op-level.  mode_parse: member is passed to function      
+       and added in the created ParseState structure.  joinbuf_join: pass 0
+       as oplevel to add_user_to_channel as needed initialization of oplevel
+       in struct MemberShip.
+
+       * ircd/m_burst.c: ms_burst: Implementation of op-levels in the
+       decoding of a BURST message and passing on a BURST message.
+       Renamed default_mode to current_mode.
+
+       * ircd/m_mode.c: m_mode/ms_mode: pass on `member' to mode_parse.
+
+       * ircd/m_opmode.c: ms_opmode/mo_opmode: pass on NULL as member
+       to mode_parse (causes opped member to get op-level 0).                  
+
+2002-02-25  Carlo Wood  <run@alinoe.com>
+       * include/channel.h: Added two new strings to struct Mode,
+       upass and apass, both with maximum length PASSLEN (a new
+       define in this file).  Two new mode defines MODE_UPASS and
+       MODE_APASS.
+
+       * ircd/channel.c: is_level0_op: Added as dummy function.
+       channel_modes/modebuf_flush_int/modebuf_extract/mode_parse:
+       Added support for MODE_APASS (+A) and MODE_UPASS (+u).
+       mode_parse_upass: New function to parse mode +u.
+       mode_parse_apass: New function to parse mode +A.
+
+       * ircd/s_err.c: Added 'A' and 'u' to mode list (RPL_MYINFO).            
+
+2002-02-25  Carlo Wood  <carlo@alinoe.com>
+
+       * ircd/m_server.c: remove unused variables
+
+2002-02-25 Joseph Bongaarts <foxxe@wtfs.net>
+
+       * ircd/m_map.c: Modified to show a useful output to non-opered
+         clients when HEAD_IN_SAND_MAP is defined. Servers are added to
+         the list when first seen (after receiving SERVER) and that list
+         is sent to clients. Servers are excluded from the list if they are
+         hubs, services, or have been missing for more than 1 week.
+       
+       * ircd/map.c: Created file for map_* functions
+
+       * include/map.h: Created file for map_* functions
+
+       * ircd/m_server.c: Added calls to map_update()
+
+       * ircd/s_misc.c: Added call to map_update()
+
+       * ircd/parse.c: Changed to use m_map() and mo_map()
+       
+2002-02-22 Reed Loden <reed@redmagnet.com>
+
+       * ircd/m_connect.c: Removed an extra : in remote connect message.
+
+2002-02-19 Joseph Bongaarts <foxxe@wtfs.net>
+
+        * ircd/whocmds.c: Local opers should also be able to
+        see servernames in /who
+
+       * ircd/gline.c: Fix core bug in gline_find()
+
+       * ircd/m_kill.c: Bug fix for HIS_KILLWHO
+
+2002-02-19 John Buttery <john@io.com>
+
+       * ircd/ircd.c: Updated "No such file" error message.
+       
+2002-02-18 Joseph Bongaarts <foxxe@wtfs.net>
+
+       * ircd/m_kill.c: Changed m_kill() to do_kill() because its not
+       a message handler, and some general cleanups and bug fixes. 
+
+       * include/ircd_policy.h: Added HEAD_IN_SAND_KILLWHO for hiding
+       kill source.
+       
+2002-02-16  Tim Vogelsang <net@astrolink.org>
+
+        * ircd/m_kill.c: added a new static function, m_kill, which
+        performs the actual kill.
+       
+2002-02-14 Joseph Bongaarts <foxxe@wtfs.net>
+
+       * Added support for LIST STOP
+       
+2002-02-13 Joseph Bongaarts <foxxe@wtfs.net>
+
+       * Merged changes from u2_10_11 to main branch.
+       
+2002-02-08  Tim Vogelsang  <net@astrolink.org>
+
+       * ircd/m_quit.c: don't prefix user quits with "Quit:" unless a
+       reason is supplied.
+
+2002-02-06  Kevin L Mitchell  <klmitch@mit.edu>
+
+       * ircd/s_auth.c (read_auth_reply): left out an = in an
+       assertion--shouldn't have had any impact, though
+
+       * ircd/Makefile.in: add a hook for using ringlog; run make depend
+
+       * tools/ringlog.c: for the heck of it, add a comment including
+       rules for /etc/magic
+
+2002-02-05  Kevin L Mitchell  <klmitch@mit.edu>
+
+       * tools/ringlog.pl: perl script to take output from ringlog and
+       pass it to addr2line to get function, file, and line number
+       information
+
+       * tools/ringlog.c: program/object to help in building function
+       trace information
+
+2002-02-04  Alex Badea  <vampire@p16.pub.ro>
+
+       * include/ircd_features.h: added new feature MOTD_BANNER
+
+       * ircd/ircd_features.c: added new feature MOTD_BANNER
+
+       * ircd/motd.c (motd_signon): send a one-line banner from
+       FEAT_MOTD_BANNER if it's not NULL and FEAT_NODEFAULTMOTD
+       is set
+
+       * doc/example.conf: default value for MOTD_BANNER feature
+
+       * doc/readme.features: documented the MOTD_BANNER feature
+
+2002-02-04  Kevin L Mitchell  <klmitch@mit.edu>
+
+       * ircd/s_debug.c (debug_serveropts): remove deprecated CHROOTDIR
+       check; added character 'A' to the server options string to
+       indicate when assertion checking is enabled
+
+2002-02-03  Kevin L Mitchell  <klmitch@mit.edu>
+
+       * include/patchlevel.h (PATCHLEVEL): bump patchlevel
+
+       * ircd/engine_kqueue.c (set_or_clear): don't generate an ET_ERROR
+       event if the errno is EBADF, since the caller probably already
+       knows about it and just hasn't gotten around to processing it yet
+
+       * ircd/ircd_events.c: set the GEN_ERROR flag if an ET_ERROR event
+       is generated; don't process socket_events() or socket_state() if
+       an error occurred; add GEN_ERROR to list of flags in gen_flags()
+
+       * include/ircd_events.h: define new GEN_ERROR flag; add a macro to
+       clear it
+
+2002-02-01  Kevin L Mitchell  <klmitch@mit.edu>
+
+       * ircd/channel.c: change make_nick_user_{ip,host} to not use a
+       static buffer--instead, a buffer of the right size (NUH_BUFSIZE or
+       NUI_BUFSIZE--I confess they're not well-named) is allocated by the
+       caller
+
+2002-02-02  Alex Badea  <vampire@p16.pub.ro>
+
+       * include/client.h: added user flag FLAGS_HIDDENHOST
+
+       * include/ircd_features.h: added FEAT_HOST_HIDING and
+       FEAT_HIDDEN_HOST
+
+       * include/numeric.h: defined numeric 338 (RPL_WHOISACTUALLY)
+       to report real hostnames and IPs to opers
+
+       * include/s_user.h: exported hide_hostmask()
+
+       * include/send.h: changed sendcmdto_channel_butserv to
+       sendcmdto_channel_butserv_butone; ditto for
+       sendcmdto_common_channels
+
+       * include/struct.h: added realhost to struct User
+
+       * include/whowas.h: added realhost to struct Whowas
+
+       * ircd/channel.c: match bans against both real and hidden
+       hostmasks; moved some calls to use sendcmdto_*_butone
+
+       * ircd/gline.c: match glines agains real host
+
+       * ircd/ircd_features.c: added FEAT_HOST_HIDING and
+       FEAT_HIDDEN_HOST
+
+       * ircd/m_account.c: call hide_hostmask() for possibly
+       hiding the user's host
+
+       * ircd/m_burst.c: moved some calls to use sendcmdto_*_butone
+
+       * ircd/m_topic.c: moved some calls to use sendcmdto_*_butone
+
+       * ircd/m_userip.c: report IP 127.0.0.1 if the user has a hidden
+       host
+
+       * ircd/m_who.c: match real hosts, if the query comes from an oper
+
+       * ircd/m_whois.c: report real hostname and IP to opers
+
+       * ircd/m_whowas.c: report real hostname to opers
+
+       * ircd/s_err.c: added user mode 'x' to the list of supported user
+       modes in RPL_MYINFO (004); added RPL_WHOISACTUALLY for reporting
+       real hostnames to opers
+
+       * ircd/s_misc.c: moved some calls to use sendcmdto_*_butone
+
+       * ircd/s_serv.c: send real hostname to servers
+
+       * ircd/s_user.c: send real hostname to servers; added processing
+       of usermode 'x'; added hide_hostmask() which actually does the work
+       of hiding a user's host; moved some calls to use sendcmdto_*_butone
+
+       * ircd/send.c: changed sendcmdto_channel_butserv to
+       sendcmdto_channel_butserv_butone; ditto for
+       sendcmdto_common_channels
+
+       * ircd/whocmds.c: extra letter 'x' in WHO reply if the user has
+       it's host hidden
+
+       * ircd/whowas.c: if needed, store a user's real host so we can
+       report it to opers later
+
+       * doc/readme.features: documented HOST_HIDING and HIDDEN_HOST
+       features
+
+       * doc/example.conf: default values for HOST_HIDING and
+       HIDDEN_HOST features
+
+2002-02-01  Tim Vogelsang  <net@astrolink.org>
+
+       * ircd/send.c (sendwallto_group_butone): don't sent wallops to
+       ordinary users
+
+2002-01-28  Kevin L Mitchell  <klmitch@mit.edu>
+
+       * ircd/jupe.c (jupe_activate): remove a bogus assertion
+
+       * include/patchlevel.h (PATCHLEVEL): bump patchlevel
+
+       * ircd/s_err.c: added new channel mode 'r' to list of supported
+       channel modes in RPL_MYINFO (004); migrated RPL_USERIP to use
+       numeric 340 instead of 307; add ERR_NEEDREGGEDNICK (477) for
+       informing users why they can't join a +r channel
+
+       * ircd/m_clearmode.c (do_clearmode): add support for MODE_REGONLY
+       (+r) to do_clearmode(); note that it is *not* being added to the
+       default clearmode mask!
+
+       * ircd/channel.c: don't allow non-+r users to send messages to +r
+       channels from off the channel; add support for MODE_REGONLY (+r)
+       to channel_modes(); don't allow non-+r users to join +r channels
+       without an invite; add support for MODE_REGONLY to the modebuf_*()
+       family of functions (changes in modebuf_flush_int(),
+       modebuf_mode(), and modebuf_extract()); add support for
+       MODE_REGONLY to mode_parse()
+
+       * include/supported.h (FEATURESVALUES2): added the new channel
+       mode 'r' to the list of supported channel modes
+
+       * include/numeric.h: move RPL_USERIP to 340 to avoid the 307
+       conflict; add ERR_NEEDREGGEDNICK (477) for the new +r channels
+
+       * include/channel.h: remove unused MODE_SENDTS; add new
+       MODE_REGONLY
+
+       * ircd/s_bsd.c (read_packet): remove call to timer_verify()
+
+       * ircd/list.c: remove calls to timer_verify() from
+       alloc_connection() and dealloc_connection()
+
+       * ircd/ircd_events.c: turn off timer_verify(); remove calls to it
+       from timer_run()
+
+2002-01-27  Kevin L Mitchell  <klmitch@mit.edu>
+
+       * include/patchlevel.h (PATCHLEVEL): bump patchlevel
+
+       * ircd/ircd_events.c (timer_run): why did I ever use a next
+       pointer when the algorithm guarantees that the head pointer will
+       always be the next pointer?
+
+2002-01-26  Kevin L Mitchell  <klmitch@mit.edu>
+
+       * include/patchlevel.h (PATCHLEVEL): bump patchlevel
+
+       * ircd/s_bsd.c (read_packet): call timer_verify() after adding the
+       client process timer to catch any list corruption
+
+       * ircd/list.c: surround alloc_connection() and
+       dealloc_connection() with calls to timer_verify()
+
+       * ircd/ircd_events.c: add sledgehammer known as timer_verify() to
+       verify the timer list's structure; call it around timer_run()
+
+2002-01-22  Kevin L Mitchell  <klmitch@mit.edu>
+
+       * ircd/send.c (sendcmdto_common_channels): don't send message to a
+       channel that the source is a zombie on
+
+2002-01-13  Kevin L Mitchell  <klmitch@mit.edu>
+
+       * ircd/ircd_events.c (timer_enqueue): one more assertion--make
+       sure a timer has the ACTIVE flag set before enqueueing the timer
+
+       * include/patchlevel.h (PATCHLEVEL): bump patchlevel
+
+       * ircd/list.c (dealloc_connection): assert that the process timer
+       has been removed from the timer queue before dealloc_connection()
+       is called
+
+2002-01-12  Kevin L Mitchell  <klmitch@mit.edu>
+
+       * ircd/res.c: don't accept T_A when we're looking for T_PTR
+
+       * ircd/channel.c (modebuf_flush_int): nuke the code that would
+       send a HACK DESYNCH notice on a HACK(2)--it would be far too
+       chatty
+
+       * ircd/m_away.c (user_set_away): use AWAYLEN instead of TOPICLEN
+
+       * include/supported.h: add AWAYLEN to the list of supported
+       features
+
+       * include/ircd_defs.h: add AWAYLEN to specify the maximum length
+       of an away message
+
+       * include/patchlevel.h (PATCHLEVEL): bump patchlevel
+
+       * ircd/m_mode.c (m_mode): pass extra parameter to channel_modes()
+
+       * ircd/channel.c: pass a buflen parameter to channel_modes() for
+       pbuf--we were using sizeof(pbuf), which would always be
+       sizeof(char*) before; change send_channel_modes() to pass extra
+       parameter to channel_modes()
+
+       * include/channel.h: pass a buflen parameter to channel_modes()
+       for pbuf
+
+       * include/patchlevel.h (PATCHLEVEL): bump patchlevel
+
+       * ircd/uping.c (uping_start): initialize some timers
+
+       * ircd/s_bsd.c (read_packet): use new t_onqueue() macro to figure
+       out when we need to re-add the process timer
+
+       * ircd/s_auth.c (make_auth_request): initialize a timer
+
+       * ircd/res.c (init_resolver): initialize some timers
+
+       * ircd/list.c (alloc_connection): initialize the client process
+       timer
+
+       * ircd/ircd_events.c: add a function, timer_init(), to initialize
+       a struct Timer; recast timer_add() to catch when adding a marked
+       timer and not re-enqueue it--but mark it for re-enqueuing; update
+       timer_del() to turn off the GEN_READD flag and to ignore reference
+       counts when destroying the timer--we're using GEN_MARKED as an
+       ersatz referance count; changed timer_run() to work with the new
+       way of doing things; add GEN_ACTIVE and GEN_READD to gen_flags()'s
+       map[]
+
+       * ircd/ircd.c: initialize some timers
+
+       * ircd/engine_select.c (engine_loop): initialize a timer
+
+       * ircd/engine_poll.c (engine_loop): initialize a timer
+
+       * ircd/engine_kqueue.c (engine_loop): initialize a timer
+
+       * ircd/engine_devpoll.c (engine_loop): initialize a timer
+
+       * ircd/IPcheck.c (IPcheck_init): initialize a timer
+
+       * include/ircd_events.h: add GEN_READD flag for timers to indicate
+       that a timer must be readded; add t_onqueue() macro to check to
+       see if a timer is on the queue (this is a hack, though); added
+       timer_init() to initialize a struct Timer--we're no longer doing
+       the initialization in timer_add()
+
+2002-01-11  Kevin L Mitchell  <klmitch@mit.edu>
+
+       * ircd/engine_devpoll.c (engine_loop): relocate an assertion to
+       prevent a core bug *in* the assertion
+
+       * doc/readme.features: document new POLLS_PER_LOOP feature; change
+       documentation to reflect that OPER_SET now defaults to FALSE
+
+       * doc/p10.html: documented the new ACCOUNT stuff
+
+       * doc/example.conf: document new POLLS_PER_LOOP default; change
+       default for OPER_SET
+
+       * RELEASE.NOTES: changed documentation to reflect the fact that
+       assertions are now enabled by default and do not cause memory
+       leaks
+
+       * ircd/res.c (make_cache): removed a bogus assertion we probably
+       never caught because assertions haven't been enabled on production
+       servers for any length of time before
+
+       * ircd/engine_devpoll.c (engine_loop): ditto for POLLS_PER_DEVPOLL
+
+       * ircd/engine_kqueue.c (engine_loop): stupid me forgot one
+       instance of POLLS_PER_KQUEUE
+
+       * include/patchlevel.h (PATCHLEVEL): bump patchlevel
+
+       * ircd/s_bsd.c (client_timer_callback): only clear the
+       FREEFLAG_TIMER flag when the timer is being destroyed
+
+       * ircd/ircd_features.c: create a new feature, POLLS_PER_LOOP, and
+       default it to 200; turn OPER_SET off by default
+
+       * ircd/engine_kqueue.c: dynamically allocate and reallocate the
+       array of events to obtain from the kernel
+
+       * ircd/engine_devpoll.c: dynamically allocate and reallocate the
+       array of events to obtain from the kernel
+
+       * include/ircd_features.h: add a new feature for tuning how many
+       events to get from the kernel, for engines that support that
+
+       * ircd/Makefile.in: re-run make depend to correct dependancies
+
+       * ircd/m_who.c: remove unneeded inclusion of list.h
+
+       * ircd/ircd_events.c: remove unneeded inclusion of list.h
+
+       * ircd/whocmds.c (do_who): hide server name in /who unless
+       requester is an operator; simplify hop count insertion
+
+       * ircd/s_misc.c (exit_one_client): make sure client's snomask is
+       cleared
+
+       * ircd/parse.c: use mo_version and mo_admin when opers do /version
+       or /admin
+
+       * ircd/m_whowas.c (m_whowas): use HEAD_IN_SAND_SERVERNAME instead
+       of the static string "*.undernet.org"
+
+       * ircd/m_version.c: only let ordinary users get version
+       information for the server they are on
+
+       * ircd/m_admin.c: only let ordinary users get admin information
+       for the server they are on
+
+       * ircd/channel.c (client_can_send_to_channel): check is_banned()
+       before letting the client speak on a channel s/he is not on
+
+       * include/supported.h: add NETWORK to feature list
+
+       * include/handlers.h: declare mo_admin() and mo_version()
+
+2002-01-10  Kevin L Mitchell  <klmitch@mit.edu>
+
+       * include/patchlevel.h (PATCHLEVEL): bump patchlevel
+
+       * ircd/s_debug.c (count_memory): conditionalize on MDEBUG instead
+       of !NDEBUG
+
+       * ircd/m_stats.c: conditionalize /stats M on MDEBUG instead of
+       !NDEBUG
+
+       * ircd/ircd_alloc.c: conditionalize on MDEBUG instead of on
+       !NDEBUG
+
+       * ircd/fda.c: conditionalize on MDEBUG instead of on !NDEBUG
+
+       * ircd/Makefile.in: run make depend on chkconf.c as well
+
+       * include/ircd_alloc.h: instead of conditionalizing on !NDEBUG,
+       conditionalize on MDEBUG
+
+       * include/fda.h: instead of conditionalizing on !NDEBUG,
+       conditionalize on MDEBUG
+
+       * configure: rebuild configure script
+
+       * configure.in: enable assertion checking by default, since we
+       have now decoupled memory debugging from the NDEBUG macro
+
+       * ircd/s_user.c (set_nick_name): remove calls to
+       verify_client_list()
+
+       * ircd/s_misc.c (exit_one_client): remove calls to
+       verify_client_list()
+
+       * ircd/s_conf.c (rehash): remove calls to verify_client_list()
+
+       * ircd/m_who.c (m_who): remove calls to verify_client_list()
+
+       * ircd/list.c: remove calls to verify_client_list(); keep
+       verify_client_list() around just in case we ever need it again,
+       but never compile it in
+
+       * ircd/ircd_events.c (event_execute): remove calls to
+       verify_client_list()
+
+       * ircd/client.c (client_get_ping): remove calls to
+       verify_client_list()
+
+       * include/list.h (send_listinfo): remove temporary debugging
+       function verify_client_list()
+
+       * ircd/uping.c: don't die if the event type is ET_ERROR in socket
+       callback functions
+
+       * ircd/res.c (res_callback): don't die if the event type is
+       ET_ERROR
+
+       * ircd/listener.c (accept_connection): don't die if the event type
+       is ET_ERROR
+
+2002-01-09  Kevin L Mitchell  <klmitch@mit.edu>
+
+       * ircd/s_user.c (set_nick_name): bracket call to
+       add_client_to_list() with calls to verify_client_list()
+
+       * include/patchlevel.h (PATCHLEVEL): bump patchlevel (again)
+
+       * ircd/list.c (verify_client_list): add a probabilistic loop
+       detector: for every client added, there is a 2% probability that
+       it will be used to replace the value of sentinel; if at any time,
+       sentinel is found again, we know we're in a loop
+
+       * ircd/ircd_events.c (event_execute): add verify_client_list()
+       calls wrapping event_execute; at the very least, I'll figure out
+       what event the corruption occurred in
+
+       * ircd/list.c: moved verify_client_list() to try to keep it from
+       being inlined
+
+       * ircd/Makefile.in (version.c): version.c wasn't dependant on
+       version.h and patchlevel.h, like it was supposed to be
+
+       * include/patchlevel.h (PATCHLEVEL): bump patchlevel
+
+       * ircd/s_auth.c (destroy_auth_request): overload send_reports
+       argument to also indicate whether or not to call
+       release_auth_client() and thereby enter the client into the linked
+       list
+
+       * ircd/engine_devpoll.c (engine_loop): remove bogus assertion
+
+       * include/patchlevel.h (PATCHLEVEL): bump patchlevel
+
+       * ircd/list.c (free_client): verify that destroy_auth_request()
+       didn't automagically re-add us to the list; we might have to think
+       about this interaction more carefully, actually
+
+       * ircd/s_auth.c (auth_kill_client): zero the auth pointer before
+       calling free_client(); otherwise, free_client() will try to free
+       the auth by calling destroy_auth_request(), which will call
+       add_client_to_list()
+
+       * ircd/s_misc.c (exit_one_client): liberally sprinkle calls to
+       verify_client_list() around to catch any corruption that might
+       occur here
+
+       * ircd/s_conf.c (rehash): liberally sprinkle calls to
+       verify_client_list() here, since this is about the only routine I
+       can think of that could cause the "core on kill -HUP" bug
+
+       * ircd/m_who.c: sprinkle calls to verify_client_list() around
+       liberally, since we've seen crashes here; temporarily include the
+       otherwise unneeded list.h header
+
+       * ircd/list.c: sprinkle calls to verify_client_list() around quite
+       liberally; add debugging asserts to list manipulation functions to
+       catch strange settings for next and prev pointers; define
+       verify_client_list(), which walks the client list and verifies
+       that everything is as it's supposed to be
+
+       * ircd/client.c: wrap client_get_ping with calls to
+       verify_client_list() to see if that's where we're dying
+
+       * include/patchlevel.h (PATCHLEVEL): bump to 03
+
+       * include/list.h: declare verify_client_list() if DEBUGMODE
+       enabled; otherwise, define it to be empty
+
+2002-01-08  Kevin L Mitchell  <klmitch@mit.edu>
+
+       * ircd/m_quit.c (m_quit): remove an unused variable
+
+       * include/patchlevel.h (PATCHLEVEL): bump PATCHLEVEL to 2
+
+       * ircd/s_user.c: when building the user mode to send to the user,
+       don't include +r; add an extra set of parens to squelch a warning
+
+       * ircd/m_quit.c (m_quit): use exit_client_msg()
+
+       * include/patchlevel.h (PATCHLEVEL): bump patch level, so we can
+       keep track of who's running what version
+
+       * ircd/m_squit.c (ms_squit): remove debugging calls to
+       protocol_violation()
+
+       * Makefile.in: change MAKEFILES to IRCD_MAKEFILES to work around a
+       new gmake "feature" (pull-up from trunk)
+
+       * ircd/m_quit.c (m_quit): prefix user quits with "Quit:" (pull-up
+       from trunk)
+
+2002-01-07  Kevin L Mitchell  <klmitch@mit.edu>
+
+       * ircd/s_user.c: add FLAGS_ACCOUNT, represented as 'r', to the
+       list of user modes; process account name as part of user mode in
+       NICK decoding (set_nick_name()); add account name to usermode when
+       building the usermode to incorporate in outgoing NICK messages
+
+       * ircd/s_err.c: add RPL_WHOISACCOUNT for reporting what account a
+       user is logged in to
+
+       * ircd/parse.c: define the new ACCOUNT command, usable only by
+       servers and ignored by everything else
+
+       * ircd/m_whois.c: report what account name is associated with a
+       user, if any
+
+       * ircd/m_account.c: implement the ACCOUNT command
+
+       * ircd/Makefile.in: add m_account.c to the list of sources; ran
+       make depend
+
+       * include/struct.h: add an account field to struct User
+
+       * include/numeric.h: add a reply, RPL_WHOISACCOUNT, for reporting
+       what username a user is logged in under
+
+       * include/msg.h: add ACCOUNT command and token (AC)
+
+       * include/ircd_defs.h: define ACCOUNTLEN to be 12--this matches
+       the maximum length of a username for X
+
+       * include/handlers.h: add declaration for ms_account()
+
+       * include/client.h: add FLAGS_ACCOUNT to flag when a user account
+       name has been set; added FLAGS_ACCOUNT to SEND_UMODES; added
+       IsAccount() and SetAccount() to manipulate the flag
+
+       * ircd/m_squit.c (ms_squit): if we call FindNServer() on a server
+       name like "Amsterdam2.NL.EU.undernet.org", we get the struct
+       Client for the server with numeric "Am", which happens to be
+       stockholm!  To fix this, we look up the full name *first*; if that
+       doesn't get it, *then* we look up by numeric.
+
+2001-12-24  Perry Lorier <isomer@coders.net>
+       * ircd/m_server.c: cleanups, maybe this will make the bug easier
+       to find.
+
+       * ircd/m_stats.c: display maximum number of connects in an I:
+
+2001-11-22  Perry Lorier  <isomer@coders.net>
+       * ircd/m_squit.c: Bug fix in squit
+
+2001-11-03  Greg Sikorski <gte@atomicrevs.demon.co.uk>
+       * ircd/parse.c, include/handlers.h: Give remote whois the correct
+       handler.
+       
+2001-11-01  Kevin L Mitchell  <klmitch@mit.edu>
+
+       * ircd/send.c: some minor white-space fiddling; recast selector
+       test in sendwallto_group_butone() to remove a warning regarding
+       putting & within parentheses
+
+       * ircd/m_create.c (ms_create): use time_t instead of int as a
+       declaration for rate
+
+       * ircd/ircd_reply.c (protocol_violation): it's supposed to be
+       WALL_DESYNCH, not CMD_DESYNCH, if I understand things right--no
+       wonder we weren't seeing any protocol violations!
+
+       * include/send.h: include time.h for time_t; move WALL_* closer to
+       the function they're used in; some white-space fiddling; add
+       declaration of sendto_opmask_butone_ratelimited()
+
+       * ircd/m_squit.c (ms_squit): add protocol_violation() calls in the
+       cases where we ignore a squit, so we aren't taken by surprise, at
+       least...
+
+       * ircd/m_create.c (ms_create): Display origin server, not origin
+       user
+
+       * ircd/m_create.c (ms_create): Fix "Timestamp drift" server notice
+
+2001-10-31  Perry Lorier  <isomer@coders.net>
+       * include/m_ping.c: Forward port ping bug
+
+2001-10-31  Perry Lorier  <isomer@coders.net>
+       * include/patchlevel.h: We're beta now
+
+2001-10-31  Perry Lorier  <isomer@coders.net>
+       * ircd/s_user.c: fixed hunt_server
+
+2001-09-21  Perry Lorier  <isomer@coders.net>
+       * ircd/send.c and various: replace sendcmdto_flag_butone with
+       sendwallto_group_butone
+
+2001-09-21  Vampire-  <unknown>
+       * ircd/ircd_string.c: unique_name_vector round II.
+
+2001-09-21  mbuna  <mbuna@undernet.org>
+       * configure.in: Add support for darwin
+
+2001-09-21  Perry Lorier  <isomer@coders.net>
+       * ircd/s_user.c I'm stupid, s/acptr/from/, Hektik pointed it out
+
+2001-09-20  Perry Lorier  <isomer@coders.net>
+
+       * Pullups from 2.10.10.pl16
+       * Added some warnings, and the concept of rate limited snotices
+
+2001-08-31  Kevin L Mitchell  <klmitch@mit.edu>
+
+       * ircd/channel.c: use "%u" to format limit arguments; use
+       strtoul() to process limit arguments in a /mode command--note:
+       most clients seem to truncate the integer, probably because
+       they're using atoi, and perhaps signed ints
+
+2001-08-17  Kevin L Mitchell  <klmitch@mit.edu>
+
+       * ircd/numnicks.c: include stdlib.h for exit()
+
+       * ircd/ircd_log.c: include stdlib.h for exit()
+
+       * ircd/ircd_events.c: include stdlib.h for exit()
+
+       * ircd/s_stats.c: remove description of /stats v, since it's gone
+
+       * ircd/m_wallops.c (mo_wallops): add "*" to the beginning of
+       /wallops to distinguish wallops from wallusers
+
+       * ircd/m_error.c (mr_error): ignore ERROR from clients that aren't
+       in the "handshake" or "connecting" states--I think the latter will
+       never happen, but...
+
+       * doc/Authors: apply delete's Authors patch
+
+       * RELEASE.NOTES: rewrite RELEASE.NOTES, basing it a little on
+       Braden's version
+
+       * README: rewrite README
+
+2001-07-31  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/s_serv.c (server_estab): remove unused variable split
+
+       * ircd/parse.c: add mr_error to the parse table
+
+       * ircd/m_error.c (mr_error): add mr_error() to handle ERRORs from
+       unregistered connections--if IsUserPort() is true, the ERROR is
+       ignored, otherwise, the message is saved
+
+2001-07-28  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/m_kill.c (ms_kill): another minor typo *sigh*
+
+       * ircd/s_user.c (send_supported): oops, minor typo...
+
+       * ircd/s_user.c: implement send_supported() to send two ISUPPORT
+       messages containing our feature buffers; make register_user() use
+       send_supported()
+
+       * ircd/s_misc.c (exit_client): make sure not to give away a remote
+       server in the ERROR message sent to the client; if the killer is a
+       server, we substitute our name in its place
+
+       * ircd/m_version.c (m_version): use send_supported() to send the
+       ISUPPORT values to the user
+
+       * ircd/m_nick.c: shave nick collision kills here a bit, too, for
+       the same reasons as for m_kill.c
+
+       * ircd/m_kill.c: shave kills a bit so that the results look
+       exactly the same no matter where you are; if we didn't do this, it
+       would be possible to map the network by looking at the differences
+       between kills originating under various circumstances
+
+       * include/supported.h: split the features into two, so as to not
+       bust the parameter count when sending the features list
+
+       * include/s_user.h: declare new send_supported() function to send
+       the ISUPPORT information
+
+2001-07-27  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/s_bsd.c: disable IP (*not* TCP) options to prevent
+       source-routed spoofing attacks; this is only available under
+       u2.10.11, so don't even bother, since no one but testers are using
+       the source base
+
+2001-07-25  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * include/ircd_policy.h: enable HEAD_IN_SAND_REMOTE by default
+
+       * ircd/s_err.c: put in a . for reporting link version on /trace,
+       to match what /version does
+
+2001-07-21  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/s_misc.c (exit_client): servers don't understand what the
+       numeric nick ERROR is supposed to mean, so they ignore error
+       messages, resulting in not knowing why we were rejected; use
+       sendcmdto_one for servers and sendrawto_one for clients
+
+2001-07-17  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/m_burst.c (ms_burst): in the case of a modeless channel and
+       a nick collide, a bare BURST may be propagated; adjust the
+       enforced parameter count to accept the bare BURST
+
+2001-07-12  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/s_bsd.c: mark a client as having been IP checked
+
+       * ircd/IPcheck.c (ip_registry_check_remote): remove unneeded
+       second call to SetIPChecked()
+
+2001-07-11  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/engine_poll.c: deal with POLLHUP properly (hopefully)
+
+       * ircd/engine_devpoll.c: deal with POLLHUP properly (hopefully)
+
+2001-07-09  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/os_bsd.c (os_get_rusage): move buf into the two ifdef'd
+       sections so that if neither is used, the declaration of buf will
+       not elicit an "unused variable" warning under NetBSD
+
+       * ircd/m_map.c: include string.h to declare strcpy (fix warnings
+       on alpha)
+
+       * ircd/m_away.c: include string.h to declare strcpy/strlen (fix
+       warnings on alpha)
+
+       * ircd/ircd_log.c: include string.h to declare strcpy/strlen (fix
+       warnings on alpha)
+
+       * ircd/client.c: include string.h to declare memset (fix warnings
+       on alpha)
+
+       * ircd/channel.c: remove unused functions next_overlapped_ban,
+       del_banid, and is_deopped (fix warnings under -O1)
+
+       * ircd/IPcheck.c: include string.h to declare memset/memcpy (fix
+       warnings on alpha)
+
+2001-06-29  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/s_user.c (set_user_mode): clear the snomask if the user
+       isn't supposed to receive server notices anymore
+
+       * ircd/ircd_features.c: change CONFIG_OPERCMDS to default to FALSE
+
+       * configure.in: use AC_MSG_CHECKING/AC_MSG_RESULT when checking
+       installation prefix; default devpoll and kqueue to on (they get
+       turned off if the required headers aren't present)
+
+       * ircd/whocmds.c (do_who): use ircd_snprintf() instead of
+       sprintf_irc(); it's a bit hackish, but it'll do for now
+
+       * ircd/support.c: remove unused #include
+
+       * ircd/send.c: remove unused #include
+
+       * ircd/s_user.c: use ircd_snprintf() instead of sprintf_irc()
+
+       * ircd/s_serv.c: remove unused #include
+
+       * ircd/s_misc.c: use ircd_snprintf() and friends instead of
+       sprintf_irc() and friends
+
+       * ircd/s_err.c: moved atoi_tab[] from ircd/sprintf_irc.c to
+       ircd/s_err.c, which is the only other file to refer to it
+
+       * ircd/s_conf.c (conf_add_deny): use ircd_snprintf() instead of
+       sprintf_irc()
+
+       * ircd/s_bsd.c (connect_server): use ircd_snprintf() instead of
+       sprintf_irc()
+
+       * ircd/s_auth.c: use ircd_snprintf() instead of sprintf_irc()
+
+       * ircd/res.c: use ircd_snprintf() instead of sprintf_irc()
+
+       * ircd/m_version.c: use ircd_snprintf() instead of sprintf_irc()
+
+       * ircd/m_kill.c: use ircd_snprintf() instead of sprintf_irc()
+
+       * ircd/listener.c: use ircd_snprintf() instead of sprintf_irc()
+
+       * ircd/gline.c: use ircd_snprintf() instead of sprintf_irc()
+
+       * ircd/channel.c: don't include sprintf_irc.h; use ircd_snprintf()
+       instead of sprintf_irc()
+
+       * ircd/Makefile.in: remove sprintf_irc.c from sources list; run
+       make depend
+
+       * include/ircd_string.h: remove declaration of sprintf_irc() (what
+       was it doing here anyway?)
+
+       * include/sprintf_irc.h: removed unneeded source file
+
+       * ircd/sprintf_irc.c: removed unneeded source file
+
+       * ircd/s_debug.c (count_memory): remove some dead code
+
+       * ircd/s_auth.c: remove some dead code
+
+       * ircd/res.c (update_list): remove some dead code
+
+       * ircd/m_whowas.c: remove some dead code
+
+       * ircd/m_whois.c: remove some dead code
+
+       * ircd/m_who.c: remove some dead code
+
+       * ircd/m_wallusers.c: remove some dead code
+
+       * ircd/m_wallops.c: remove some dead code
+
+       * ircd/m_wallchops.c: remove some dead code
+
+       * ircd/m_version.c: remove some dead code
+
+       * ircd/m_userip.c: remove some dead code
+
+       * ircd/m_userhost.c: remove some dead code
+
+       * ircd/m_uping.c: remove some dead code
+
+       * ircd/m_trace.c: remove some dead code
+
+       * ircd/m_topic.c: remove some dead code
+
+       * ircd/m_tmpl.c: remove some dead code
+
+       * ircd/m_time.c: remove some dead code
+
+       * ircd/m_squit.c: remove some dead code
+
+       * ircd/m_silence.c: remove some dead code
+
+       * ircd/m_settime.c: remove some dead code
+
+       * ircd/m_set.c: remove some dead code
+
+       * ircd/m_server.c: remove some dead code
+
+       * ircd/m_rpong.c: remove some dead code
+
+       * ircd/m_rping.c: remove some dead code
+
+       * ircd/m_restart.c: remove some dead code
+
+       * ircd/m_reset.c: remove some dead code
+
+       * ircd/m_rehash.c: remove some dead code
+
+       * ircd/m_quit.c: remove some dead code
+
+       * ircd/m_proto.c: remove some dead code
+
+       * ircd/m_privs.c: remove some dead code
+
+       * ircd/m_privmsg.c: remove some dead code
+
+       * ircd/m_pong.c: remove some dead code
+
+       * ircd/m_ping.c: remove some dead code
+
+       * ircd/m_pass.c: remove some dead code
+
+       * ircd/m_part.c: remove some dead code
+
+       * ircd/m_opmode.c: remove some dead code
+
+       * ircd/m_oper.c: remove some dead code
+
+       * ircd/m_notice.c: remove some dead code
+
+       * ircd/m_nick.c: remove some dead code
+
+       * ircd/m_map.c: remove some dead code
+
+       * ircd/m_lusers.c: remove some dead code
+
+       * ircd/m_list.c: remove some dead code
+
+       * ircd/m_links.c: remove some dead code
+
+       * ircd/m_kill.c: remove some dead code
+
+       * ircd/m_kick.c: remove some dead code
+
+       * ircd/m_jupe.c: remove some dead code
+
+       * ircd/m_join.c: remove some dead code
+
+       * ircd/m_ison.c: remove some dead code
+
+       * ircd/m_invite.c: remove some dead code
+
+       * ircd/m_info.c: remove some dead code
+
+       * ircd/m_help.c: remove some dead code
+
+       * ircd/m_gline.c: remove some dead code
+
+       * ircd/m_get.c: remove some dead code
+
+       * ircd/m_error.c: remove some dead code
+
+       * ircd/m_endburst.c: remove some dead code
+
+       * ircd/m_die.c: remove some dead code
+
+       * ircd/m_desynch.c: remove some dead code
+
+       * ircd/m_destruct.c: remove some dead code
+
+       * ircd/m_defaults.c: remove some dead code
+
+       * ircd/m_create.c: remove some dead code, along with an #if 1
+
+       * ircd/m_cprivmsg.c: remove some dead code
+
+       * ircd/m_connect.c: remove some dead code
+
+       * ircd/m_close.c: remove some dead code
+
+       * ircd/m_clearmode.c: remove some dead code
+
+       * ircd/m_burst.c: remove some dead code
+
+       * ircd/m_away.c: remove some dead code
+
+       * ircd/m_admin.c: remove some dead code
+
+       * ircd/listener.c (accept_connection): remove some dead code
+
+       * ircd/ircd_reply.c (need_more_params): remove some dead code
+
+       * ircd/channel.c (add_banid): remove some dead code
+
+       * include/support.h: remove some dead code
+
+       * include/querycmds.h: remove some dead code
+
+       * doc/readme.chroot: document how to do chroot operation
+
+2001-06-28  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/Makefile.in: tune for VPATH builds/installs; add a rule to
+       force bin directory to be created if necessary prior to
+       installation; run make depend
+
+       * doc/Makefile.in (install): tune for VPATH installs by cd'ing to
+       the ${srcdir}
+
+       * Makefile.in: tune to detect Makefile.in changes in
+       subdirectories and to create installation directory indicated by
+       ${prefix}
+
+       * ircd/whocmds.c (count_users): routine to count the number of
+       users matching a given user@host mask
+
+       * ircd/s_err.c: add error messages for ERR_LONGMASK,
+       ERR_TOOMANYUSERS, and ERR_MASKTOOWIDE
+
+       * ircd/m_gline.c: look for and advance past '!' flag on G-lines
+       from operators; only set GLINE_OPERFORCE flag if oper has the
+       PRIV_WIDE_GLINE privilege
+
+       * ircd/ircd_features.c: add GLINEMAXUSERCOUNT, which is the
+       maximum number of users a G-line can impact before it has to be
+       forced; OPER_WIDE_GLINE, to allow operators to use ! to force a
+       wide G-line to be set; and LOCOP_WIDE_GLINE, to allow local
+       operators to use ! to force a wide G-line to be set
+
+       * ircd/gline.c: make make_gline() be called with separate user and
+       host arguments, and not call canon_userhost() directly; implement
+       gline_checkmask() to verify that a host mask is acceptable; move
+       BADCHAN check up in gline_add(), and check passed-in mask under
+       certain circumstances for acceptability; fix call to
+       sendto_opmask_butone() to handle separation of userhost into user
+       and host in gline_add(); update call to make_gline()
+
+       * ircd/client.c: use FEAT_OPER_WIDE_GLINE and
+       FEAT_LOCOP_WIDE_GLINE to set PRIV_WIDE_GLINE for an operator; add
+       PRIV_WIDE_GLINE to privtab[] for client_report_privs()
+
+       * include/whocmds.h (count_users): declare routine to count users
+       matching a given user@host mask
+
+       * include/numeric.h: added three new error returns: ERR_LONGMASK
+       -- mask can't be formatted into a buffer; ERR_TOOMANYUSERS -- too
+       many users would be impacted by the mask; ERR_MASKTOOWIDE -- mask
+       contains wildcards in the wrong places
+
+       * include/ircd_features.h: add FEAT_GLINEMAXUSERCOUNT,
+       FEAT_OPER_WIDE_GLINE, and FEAT_LOCOP_WIDE_GLINE
+
+       * include/gline.h (GLINE_OPERFORCE): provides a way for m_gline()
+       to signal to gline_add() that the operator attempted to force the
+       G-line to be set
+
+       * include/client.h (PRIV_WIDE_GLINE): new privilege for operators
+
+       * doc/readme.gline: update to document new "!" prefix to a G-line
+       user@host mask
+
+       * doc/readme.features: document GLINEMAXUSERCOUNT,
+       OPER_WIDE_GLINE, and LOCOP_WIDE_GLINE
+
+       * doc/example.conf: update to mention new features along with
+       their defaults
+
+2001-06-27  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * doc/example.conf: updated example.conf from Braden
+       <dbtem@yahoo.com>
+
+       * include/supported.h: forward-port from pl15
+
+2001-06-25  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/whocmds.c: include ircd_policy.h and implement
+       HEAD_IN_SAND_WHO_OPCOUNT--forward-port from pl15
+
+       * ircd/m_whois.c: forward-port of the idle-time hiding code from
+       pl15; this also required passing parc into do_whois(), which also
+       meant passing parc into do_wilds()--*sigh*
+
+       * include/ircd_policy.h: add a couple more HEAD_IN_SAND
+       #define's--WHOIS_IDLETIME and WHO_HOPCOUNT
+
+2001-06-22  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * tools/wrapper.c: add a wrapper program that can be used to
+       adjust file descriptor limits and root directories; program must
+       be run as root--NOT SETUID!--and given appropriate -u arguments
+
+       * doc/readme.log: documentation of how to configure logging
+
+       * doc/readme.features: documentation of each feature (except for
+       logging)
+
+2001-06-21  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * Makefile.in (config): add a deprecation notice with a pointer to
+       tools/transition
+
+       * tools/transition: shell script to convert old compile-time
+       options into new compile-time options and appropriate F-lines
+
+       * tools/mkchroot: shell-script to prepare the chroot area by
+       copying over all the necessary libraries so they can be found
+
+2001-06-20  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * INSTALL: partial update of INSTALL for u2.10.11 release...
+
+2001-06-14  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/table_gen.c (makeTables): finally got tired of the
+       "overflow in implicit conversion" warning, so just got rid of it
+       by explicitly casting UCHAR_MAX to a (default) char; diffs show no
+       differences in the tables generated
+
+2001-06-11  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/send.c (sendcmdto_match_butone): don't let the server crash
+       if a client is in the STAT_CONNECTING status
+
+2001-06-10  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/send.c: remove unused vsendcmdto_one(), consolidating it
+       into sendcmdto_one(); define new sendcmdto_prio_one(), which
+       places the message into the priority queue
+
+       * ircd/s_user.c (hunt_server_prio_cmd): definition of
+       hunt_server_prio_cmd(), which simply calls sendcmdto_prio_one()
+       instead of sendcmdto_one()
+
+       * ircd/m_settime.c: use sendcmdto_prio_one() and
+       hunt_server_prio_cmd() to send SETTIME
+
+       * ircd/m_server.c: use sendcmdto_prio_one() to send SETTIME
+
+       * include/send.h: removed declaration for unused vsendcmdto_one();
+       added a declaration for sendcmdto_prio_one()
+
+       * include/s_user.h: declare hunt_server_prio_cmd(), which calls
+       sendcmdto_prio_one()
+
+       * ircd/send.c (sendcmdto_flag_butone): oops; /wallops should be
+       put in the server's priority queue, too...
+
+       * ircd/ircd.c: don't check LPATH for accessibility at all
+
+2001-06-08  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/s_serv.c (server_estab): send a +h flag in our SERVER
+       command if we're configured as a hub; send individual server flags
+       in SERVER commands
+
+       * ircd/s_bsd.c (completed_connection): send a +h flag in our
+       SERVER command if we're configured as a hub
+
+       * ircd/m_server.c: implement parv[7] as a mode-like string; +h
+       sets the FLAGS_HUB flag for a server; +s sets the FLAGS_SERVICE
+       flag for a server; +hs sets both flags; also modify CMD_SERVER
+       format string to send the flags
+
+       * include/client.h: define two new flags, FLAGS_HUB and
+       FLAGS_SERVICE to mark services and hubs as such; define testing
+       macros, setting macros
+
+       * ircd/s_user.c: remove deprecated struct Gline* argument to
+       register_user(); remove GLINE rebroadcast; do not send GLINE
+       acknowledgement parameter to NICK; do not look for GLINE
+       acknowledgement parameter to NICK while parsing
+
+       * ircd/s_serv.c (server_estab): remove deprecated struct Jupe*
+       argument to server_estab(); do not send JUPE/GLINE acknowledgement
+       parameters for SERVER or NICK
+
+       * ircd/m_user.c (m_user): remove deprecated argument to
+       register_user()
+
+       * ircd/m_server.c: remove deprecated argument to server_estab();
+       remove documentation comment regarding JUPE acknowledgement
+       parameter to SERVER; remove JUPE rebroadcast
+
+       * ircd/m_pong.c (mr_pong): remove deprecated argument to
+       register_user()
+
+       * ircd/m_nick.c: remove documentation comment regarding GLINE
+       acknowledgement parameter to NICK
+
+       * ircd/jupe.c: use user's real name in JUPE server notices if
+       HEAD_IN_SAND_SNOTICES is defined
+
+       * ircd/ircd.c: remove deprecated chroot() code; remove deprecated
+       setuid code; correct ancient DEBUG vs DEBUGMODE typo
+
+       * ircd/gline.c: use user's real name in GLINE server notices if
+       HEAD_IN_SAND_SNOTICES is defined
+
+       * ircd/channel.c (modebuf_flush_int): make apparent source be
+       local server, not oper's server; use user's real name in hack
+       notices and DESYNC notices if HEAD_IN_SAND_SNOTICES is defined
+
+       * include/s_user.h: remove struct Gline pre-declaration; remove
+       deprecated struct Gline argument from register_user()
+
+       * include/s_serv.h: remove struct Jupe pre-declaration; remove
+       deprecated struct Jupe argument from server_estab()
+
+2001-06-07  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/s_stats.c (hunt_stats): forward-port from pl15 of all the
+       changes required to control remote stats
+
+       * ircd/s_numeric.c (do_numeric): rewrite numeric origins if
+       recipient is not an operator and HEAD_IN_SAND_REWRITE is defined
+       [forward-port from pl15]
+
+       * ircd/m_whowas.c (m_whowas): report server name only if requester
+       is an operator [forward-port from pl15]
+
+       * ircd/m_whois.c (do_whois): /whois <mynick> now correctly reports
+       my server; if HEAD_IN_SAND_REMOTE is 1, ignore the middle argument
+       and obtain the report from the user's server [forward-port from
+       pl15]
+
+       * ircd/m_who.c: add missing include for ircd_policy.h
+       [forward-port from pl15]
+
+       * ircd/m_version.c (m_version): require oper access for remote
+       /version if HEAD_IN_SAND_REMOTE is 1 [forward-port from pl15]
+
+       * ircd/m_time.c (m_time): require oper access for remote /time if
+       HEAD_IN_SAND_REMOTE is 1 [forward-port from pl15]
+
+       * ircd/m_stats.c: pass extra argument to hunt_stats(); correct
+       missing semicolon [forward-port from pl15]
+
+       * ircd/m_nick.c (ms_nick): hide the origin of certain collision
+       kills [forward-port from pl15]
+
+       * ircd/m_motd.c (m_motd): require oper access for remote /motd if
+       HEAD_IN_SAND_REMOTE is 1 [forward-port from pl15]
+
+       * ircd/m_lusers.c (m_lusers): require oper access for remote
+       /lusers if HEAD_IN_SAND_REMOTE is 1 [forward-port from pl15]
+
+       * ircd/m_burst.c (ms_burst): server-added bans are stored using
+       local server name, to hide remote server names; modes also are to
+       originate from the local server [forward-port from pl15]
+
+       * ircd/m_admin.c (m_admin): require oper access for remote /admin
+       if HEAD_IN_SAND_REMOTE is 1 [forward-port from pl15]
+
+       * ircd/channel.c (add_banid): if a server is adding a ban, use my
+       server name to hide the remote server's name [forward-port from
+       pl15]
+
+       * ircd/Makefile.in: ran make depend
+
+       * include/s_stats.h: hunt_stats() has to have an extra argument to
+       support the forward-port from pl15
+
+       * include/ircd_policy.h: #define HEAD_IN_SAND_STATS_P; add
+       HEAD_IN_SAND_{BANWHO,REWRITE,REMOTE} [forward-port from pl15]
+
+       * ircd/engine_poll.c (engine_loop): remove bogus assert that I
+       forgot to check in the events branch
+
+2001-06-06  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/res.c (init_resolver): don't start DNS expires with a 0
+       relative timeout--if the server starts slow, timeouts could be
+       messy...there's probably a better solution, but this'll do for now
+
+       * ircd/os_solaris.c: _XOPEN_SOURCE doesn't get along with Solaris
+       headers very well; include stropts.h; define an os_set_tos()
+
+       * ircd/os_generic.c (os_set_tos): added an os_set_tos() for
+       os_generic.c
+
+       * ircd/ircd.c: if there are no C-lines, we don't want to have a
+       timer that expires at the absolute time of 0--it kinda blocks all
+       the other timers!
+
+       * ircd/engine_devpoll.c: some includes for open(); declare errcode
+       and codesize in engine_loop()
+
+       * ircd/list.c (free_client): remove bogus check on timer active
+       flag
+
+       * ircd/s_auth.c: pull out destruction code in
+       auth_timeout_request() into an externally-visible
+       destroy_auth_request(); manage cli_auth pointer in client
+       structure; use it for an extra assertion check
+
+       * ircd/list.c: include s_auth.h for destroy_auth_request(); add
+       debugging notices to show flow when deallocating
+       connections/clients; call destroy_auth_request() when free'ing a
+       client that has an auth outstanding; don't free the connection if
+       the process timer is unmarked but still active
+
+       * ircd/ircd_events.c: set GEN_ACTIVE when initializing a generator
+       and reset it before calling the event handler for an ET_DESTROY
+       event
+
+       * include/s_auth.h (destroy_auth_request): declare
+       destroy_auth_request(), which can be used to destroy an
+       outstanding auth request if a client socket goes away before the
+       auth exchange is completed
+
+       * include/ircd_events.h: add an active flag to keep track of
+       whether or not particular generators are active, for the
+       convenience of functions using the API
+
+       * include/client.h: add a pointer for auth requests to struct
+       Connection so we can kill outstanding auth requests if a client
+       socket closes unexpectedly
+
+       * ircd/s_bsd.c: cli_connect() could become 0 during the course of
+       the sock or timer callback; take that into account in the assert
+
+       * ircd/list.c: add magic number checking and setting--magic
+       numbers are zero'd on frees to detect double-frees; add back
+       setting of cli_from() to 0 to break the back-link from the struct
+       Connection (duh)
+
+       * ircd/ircd.c: set me's magic number correctly
+
+       * include/client.h: define magic numbers and accessor/verifier
+       macros
+
+       * ircd/list.c: assert that dealloc_client() is called with
+       cli_connect(cptr) == 0; set cli_connect(cptr) to 0 before calling
+       dealloc_client(); don't mess with cli_from(cptr)
+
+       * ircd/s_bsd.c: only attempt to dealloc a connection if the
+       associated client has already been destroyed, or at least delinked
+
+2001-06-05  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/list.c (free_client): only try to delete the socket when
+       the fd hasn't already been closed, avoiding a double-free
+
+       * ircd/list.c (free_connection): make sure the client is really
+       gone before doing away with the connection
+
+       * ircd/s_bsd.c: record that socket has been added in con_freeflag
+       field; queue a socket_del() as soon as the socket is close()'d;
+       use con_freeflag & FREEFLAG_TIMER instead of con_timer; clear
+       FREEFLAG_SOCKET on ET_DESTROY event in client_sock_callback(),
+       then dealloc the connection if safe; mark socket as dead when
+       there's a read error or EOF; clear FREEFLAG_TIMER flag upon entry
+       to client_timer_callback(); dealloc connection if safe upon
+       ET_DESTROY event in client_timer_callback()
+
+       * ircd/list.c: use con_freeflag instead of con_timer; only dealloc
+       the connection if both socket and timer have been destroyed;
+       destroy both socket and timer explicitly and carefully
+
+       * include/client.h: replace the con_timer field with a
+       con_freeflag field, to indicate what still needs freeing; define
+       the freeflags
+
+       * ircd/engine_select.c (engine_loop): duh...sockList[i] could
+       become 0
+
+       * ircd/engine_devpoll.c (engine_loop): duh...sockList[i] could
+       become 0
+
+       * ircd/s_bsd.c: add some extra assertions to try to track down a
+       corruption problem
+
+       * ircd/engine_select.c (engine_loop): add an extra assert to try
+       to track down a corruption problem
+
+       * ircd/engine_poll.c (engine_loop): add an extra assert to try to
+       track down a corruption problem
+
+       * ircd/engine_kqueue.c (engine_loop): add an extra assert to try
+       to track down a corruption problem
+
+       * ircd/engine_devpoll.c (engine_loop): skip slots that have become
+       empty during processing; add an extra assert to try to track down
+       a corruption problem
+
+       * ircd/engine_kqueue.c (engine_delete): make sure to zero deleted
+       entries
+
+2001-06-04  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/s_bsd.c (client_sock_callback): client is no longer
+       blocked, so we must mark it as unblocked
+
+       * ircd/engine_select.c: add Debug() calls galore; add handling for
+       SS_NOTSOCK; use a dummy sock variable to keep things from
+       disappearing on us; correct timeout calculation; update nfds for
+       efficiency
+
+       * ircd/engine_poll.c: use new debugging level (DEBUG_ENGINE);
+       remove a spurious "if (sock)" which will always be true; update
+       nfds for efficiency
+
+       * ircd/engine_kqueue.c: add Debug() calls galore; add handling for
+       SS_NOTSOCK (just in case); correct timeout calculation
+
+       * ircd/engine_devpoll.c: add Debug() calls galore; add handling
+       for SS_NOTSOCK; correct timeout calculation; add EAGAIN handling
+
+       * include/s_debug.h (DEBUG_ENGINE): add new debugging level;
+       pretty-indent numbers
+
+       * ircd/engine_poll.c (engine_loop): break out SS_NOTSOCK
+       case--it's not a socket; the check for writability is most likely
+       not needed, but present for completeness
+
+2001-05-24  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/s_bsd.c: add Debug messages; call read_packet() even if the
+       no newline flag is set; call read_packet() when the timer expires,
+       regardless of what's in the buffer--read_packet() should be able
+       to deal properly
+
+       * ircd/IPcheck.c (ip_registry_connect_succeeded): correct a NOTICE
+       sent to clients to include the client nickname (duh)
+
+       * ircd/ircd_events.c: don't destroy a timer if it's already marked
+       for destruction; replace a missing ! in socket_del()
+
+       * ircd/engine_poll.c (engine_loop): reference a temporary variable
+       so we don't have to worry about sockList[i] going away
+
+       * ircd/s_bsd.c (client_sock_callback): add Debug messages
+
+       * ircd/s_auth.c: add Debug messages all over the place
+
+       * ircd/ircd_events.c: add and edit some Debug messages; add a list
+       of routines to convert some of the enums and flags from numbers
+       into human-readable strings for the Debug messages
+
+       * ircd/engine_poll.c: hack some Debug messages to use the new name
+       conversion routines in ircd_events.c; add an extra assert for a
+       condition that shouldn't ever happen; apparently recv() can return
+       EAGAIN when poll() returns readable--I wonder why...
+
+       * include/ircd_events.h: declare some helper routines under
+       DEBUGMODE
+
+2001-05-23  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/s_bsd.c (client_sock_callback): add an extra assertion
+       check
+
+       * ircd/s_auth.c: add more Debug messages
+
+       * ircd/list.c (make_client): add an extra assertion check
+
+       * ircd/ircd_events.c (socket_events): don't call the engine events
+       changer if we haven't actually made any changes to the event mask
+
+       * ircd/uping.c: add some Debug messages
+
+       * ircd/s_stats.c: document new /STATS e
+
+       * ircd/s_err.c: add RPL_STATSENGINE to report the engine name
+
+       * ircd/s_bsd.c: remove static client_timer variable; in
+       read_packet(), if there's still data in the client's recvQ after
+       parsing, add a 2 second timer (con_proc); fix the ET_DESTROY case
+       of client_sock_callback to handle destroying the timer properly;
+       rewrote client_timer_callback from scratch to be called on an
+       individual client
+
+       * ircd/m_stats.c: add /STATS e to report the engine name
+
+       * ircd/list.c: deal with con_timer field in struct Connection
+       properly; correct a core-level bug in remove_client_from_list--if
+       the client is the only one in the list, we try to update
+       GlobalClientList's cli_prev pointer--not good
+
+       * ircd/ircd.c: remove call to init_client_timer()
+
+       * ircd/engine_poll.c: made Debug messages more uniform by
+       prepending "poll:" to them all; corrected an off-by-one error that
+       caused poll_count to be 1 less than the actual count and removed
+       my work-around; added Debug messages to indicate which socket is
+       being checked and what the results are
+
+       * ircd/Makefile.in: ran a make depend
+
+       * include/s_bsd.h: remove init_client_timer(), since we're doing
+       it differently now
+
+       * include/numeric.h (RPL_STATSENGINE): a stats reply to report the
+       engine name
+
+       * include/ircd_policy.h (HEAD_IN_SAND_STATS_E): turn off /stats e
+       reports for non-opers
+
+       * include/client.h: add con_timer and con_proc fields to struct
+       Connection and define accessor macros--con_timer marks that
+       con_proc contains a valid timer, and con_proc is used to pace user
+       data
+
+       * ircd/s_bsd.c (close_connection): let free_client() destroy the
+       socket
+
+       * ircd/s_auth.c (start_auth): add a Debug call to indicate when
+       auth has begun on a client
+
+       * ircd/ircd_events.c: ensure that event_execute() is called with a
+       non-NULL event; modify event_add() macro to properly zero list
+       bits; modify gen_dequeue() to not try to clip it out of a list
+       it's already been clipped out of; change signal socket
+       initialization to use state SS_NOTSOCK; permit timeout values of
+       0 in add_timer(); add many Debug calls; change socket_del() and
+       timer_del() to always set the GEN_DESTROY flag; use GEN_MARKED in
+       timer_run() instead of GEN_DESTROY so that event_generate() will
+       pass on the events; remove the switch and replace with a simpler
+       if-then-else tree in timer_run(); don't allow destroyed sockets to
+       be destroyed again, nor their states or event masks to be changed
+
+       * ircd/ircd.c: initialize "running" to 1
+
+       * ircd/engine_poll.c: deal with SS_NOTSOCK "sockets"; add Debug
+       messages all over the place; fix a counting problem in
+       engine_add(); turn wait into a signed integer and set it to -1
+       only if timer_next() returns 0; adjust wait time to be relative;
+       don't call gen_ref_dec() if socket disappeared while we were
+       processing it
+
+       * include/ircd_events.h: the pipe for signals is not a socket, so
+       we must mark it as such--added SS_NOTSOCK for that special socket;
+       events won't be generated if GEN_DESTROY is on, so add GEN_MARKED
+       for the benefit of timer_run()
+
+       * configure.in: add --enable-pedantic and --enable-warnings to
+       turn on (and off) -Wall -pedantic in CFLAGS
+
+2001-05-21  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/s_conf.c: change "s_addr" element accesses to "address"
+       element accesses
+
+       * include/s_conf.h: on some systems, "s_addr" is a macro; use
+       "address" instead
+
+2001-05-18  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/engine_kqueue.c: include ircd_alloc.h; set_or_clear returns
+       void in this file; add a missing semi-colon; declare errcode,
+       codesize
+
+       * ircd/uping.c (uping_sender_callback): it's pptr, not uping
+
+       * ircd/s_user.c (register_user): comment out spurious reference to
+       nextping
+
+       * ircd/s_serv.c (server_estab): comment out spurious reference to
+       nextping
+
+       * ircd/s_conf.c (read_configuration_file): comment out spurious
+       reference to nextping and nextconnect
+
+       * ircd/s_bsd.c: comment out some spurious references to formerly
+       global (now non-existant) variables; correct a couple of typos
+
+       * ircd/s_auth.c: pre-declare some functions referenced in the
+       callback; correct a typo
+
+       * ircd/res.c (start_resolver): pass errno value of ENFILE
+
+       * ircd/listener.c (accept_connection): you know your API is messed
+       up when...variables that shouldn't have been global crop up in
+       other files
+
+       * ircd/list.c (free_client): substitution of == for =
+
+       * ircd/ircd_signal.c: include assert.h for assertion checking;
+       check ev_data() to find out what signal generated event
+
+       * ircd/ircd_events.c: some references to the variable "timer"
+       should have been references to the variable "ptr"
+
+       * ircd/engine_select.c: it's struct fd_set, not struct fdset;
+       ev_timer(ev) is already a timer pointer; declare codesize as a
+       size_t to correct signedness issue; use timer_next(), not
+       time_next()
+
+       * ircd/engine_poll.c: ev_timer(ev) is already a timer pointer;
+       select fd out of struct pollfd in assertion checking; declare
+       errcode and codesize; use timer_next(), not time_next()
+
+       * ircd/engine_kqueue.c: ev_timer(ev) is already a timer pointer;
+       use function timer_next(), not time_next()
+
+       * ircd/engine_devpoll.c: ev_timer(ev) is already a timer pointer;
+       use function timer_next(), not time_next()
+
+       * ircd/Makefile.in (IRCD_SRC): add ircd_events.c to the list of
+       compiled sources; do make depend
+
+       * include/list.h: pre-declare struct Connection
+
+       * include/ircd_events.h (gen_ref_inc): cast to the right structure
+       name
+
+       * include/s_auth.h: duh; missing */
+
+2001-05-10  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/send.c: update write events status after sending data or
+       accumulating data to be sent
+
+       * ircd/m_list.c (m_list): update write events status after
+       canceling a running /list
+
+       * ircd/channel.c (list_next_channels): update write events status
+       after listing a few channels
+
+       * ircd/s_bsd.c: extensive changes to update to new events model;
+       remove on_write_unblocked() and the two implementations of
+       read_message(), which have been deprecated by this change
+
+       * ircd/s_auth.c: set the socket events we're interested in for
+       clients; simplify some logic that does the connect_nonb followed
+       by the socket_add
+
+       * ircd/list.c: define free_connection() to free a connection
+       that's become freeable once the struct Socket has been
+       deallocated; fix up free_client() to take this new behavior into
+       account
+
+       * ircd/ircd.c: call init_client_timer()
+
+       * include/s_bsd.h: declare new REGISTER_ERROR_MESSAGE when unable
+       to register connect-in-progress with events system; declare
+       init_client_timer() (HACK!) to preserve rate-limiting behavior
+
+       * include/list.h: declare new free_connection()
+
+       * include/client.h: add a struct Socket to struct Connection
+
+2001-05-09  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/ircd_signal.c: massage the handlers for SIGHUP, SIGINT, and
+       SIGTERM into event callbacks; perform the actions in the
+       callbacks, since they're not called in the context of the signal;
+       set up the signal callbacks in the event engine
+
+       * ircd/ircd_events.c (signal_callback): we're supposed to look for
+       a specific signal; don't generate an event if there is no signal
+       structure for it
+
+       * ircd/ircd.c: nuke nextconnect and nextping and replace them with
+       connect_timer and ping_timer; massage try_connections() and
+       check_pings() into timer callbacks that re-add themselves at the
+       right time; remove ircd.c's "event_loop()"; initialize the event
+       system and the connect_timer and ping_timer
+
+       * ircd/uping.c: correct a couple more typos
+
+       * ircd/s_auth.c: rework to use new events system
+
+       * ircd/os_solaris.c (os_connect_nonb): update to new interface
+
+       * ircd/os_openbsd.c (os_connect_nonb): update to new interface
+
+       * ircd/os_linux.c (os_connect_nonb): update to new interface
+
+       * ircd/os_generic.c (os_connect_nonb): update to new interface
+
+       * ircd/os_bsd.c (os_connect_nonb): update to new interface
+
+       * include/s_auth.h: remove deprecated members of struct
+       AuthRequest, replacing them with struct Socket and struct Timer
+       structures; add flags to indicate when these structures have been
+       released by the event system; remove the deprecated
+       timeout_auth_queries()
+
+       * include/ircd_osdep.h (os_connect_nonb): connect could complete
+       immediately, so change the interface to handle that possibility
+
+       * ircd/uping.c (uping_server): noticed and corrected a typo
+
+       * ircd/listener.c: set up to use ircd_event's struct Socket by
+       adding an socket_add() call to inetport(), replacing
+       free_listener() with socket_del() in close_listener(), and
+       reworking accept_connection to be called as the callback
+
+       * ircd/ircd.c: add a call to IPcheck_init()
+
+       * ircd/IPcheck.c: remove IPcheck_expire(); rework
+       ip_registry_expire() to be called from a timer; write
+       IPcheck_init() to set up the expiration timer (hard-coded for a
+       60-second expiration time)
+
+       * include/listener.h: add a struct Socket to the struct Listener;
+       remove accept_connection()
+
+       * include/IPcheck.h: add IPcheck_init(), remove IPcheck_expire()
+
+2001-05-08  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/ircd_events.c: include config.h; use USE_KQUEUE and
+       USE_DEVPOLL instead of HAVE_KQUEUE and HAVE_DEVPOLL_H
+
+       * ircd/engine_select.c: include config.h; set FD_SETSIZE to
+       MAXCONNECTIONS, not IRCD_FD_SETSIZE...
+
+       * ircd/engine_poll.c: include config.h
+
+       * ircd/engine_kqueue.c: include config.h
+
+       * ircd/engine_devpoll.c: include config.h
+
+       * ircd/Makefile.in: include engine sources in compilation and make
+       depend steps
+
+       * configure.in: add checks for enabling the /dev/poll- and
+       kqueue-based engines
+
+       * acconfig.h: add lines for USE_DEVPOLL and USE_KQUEUE
+
+       * ircd/Makefile.in: work in the engine sources
+
+2001-05-07  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/m_settime.c: include ircd_snprintf.h
+
+       * ircd/ircd_relay.c: stomp a couple of gcc warnings suggesting
+       parens around a construct that had both || and &&
+
+       * ircd/chkconf.c: #include "config.h" to get some important
+       definitions
+
+       * ircd/Makefile.in: revamp ircd makefile for new build system
+
+       * doc/Makefile.in: revamp doc makefile for new build system
+
+       * config/*: Removed old build system files
+
+       * stamp-h.in: a stamp file
+
+       * install-sh: install-sh for new build system
+
+       * configure.in: configure.in for new build system
+
+       * configure: configure script for new build system (built by
+       autoconf)
+
+       * config.sub: config.sub for new build system
+
+       * config.h.in: config.h.in for new build system (built by
+       autoheader)
+
+       * config.guess: config.guess for new build system
+
+       * aclocal.m4: aclocal.m4 for new build system (built by aclocal
+       1.4)
+
+       * acinclude.m4: aclocal.m4 macros for new build system
+
+       * acconfig.h: config.h skeleton for new build system
+
+       * Makefile.in: modify for new build system
+
+2001-05-01  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/s_err.c: get rid of the last vestiges of TIME_T_FMT
+
+       * ircd/m_settime.c: get rid of the last vestiges of TIME_T_FMT
+
+       * ircd/m_server.c: get rid of the last vestiges of TIME_T_FMT
+
+2001-05-01  Perry Lorier       <Isomer@coders.net>
+       * doc/iauth.doc: Protocol for iauth server. (from hybrid).
+       * doc/linux-poll.patch: Patch to make Linux under 2.2 not deadlock
+               when you have far far too many sockets in use.
+       * {include,ircd}/iauth.c: A start on iauth support.
+
+2001-05-01  Perry Lorier       <Isomer@coders.net>
+       * ircd/s_err.c: Suggested wording change.
+       * ircd/s_user.c: Users aren't target limited against +k users.
+       * ircd/chkconf.c: Made it compile again, who knows if it works, but
+               now I can at least make install
+        * various: Cleanups on m_*.c files.
+
+
+2001-04-23  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/s_misc.c (exit_client): make netsplit server notice say the
+       right thing
+
+       * ircd/m_links.c (m_links_redirect): forward-port RPL_ENDOFLINKS
+       change to make Khaled happy...
+
+       * ircd/m_whois.c (do_whois): pull-up of m_whois() fix
+       (do_whois): duh...
+
+2001-04-21  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/msgq.c: finally remove the msgq_integrity() hack, as it's
+       turned up no more bugs
+
+       * ircd/ircd.c: use /* */ comments instead of // comments--all the
+       world's not gcc :(
+
+       * ircd/s_conf.c (conf_add_server): use /* */ comments instead of
+       // comments--all the world's not gcc :(
+
+       * ircd/runmalloc.c: finally garbage-collect unused file
+
+       * include/runmalloc.h: finally garbage-collect unused file
+
+       * ircd/<multiple files>: addition of '#include "config.h"' before
+       all other includes in most .c files
+
+       * include/<multiple files>: remove includes of config.h, which are
+       now going into the raw .c files
+
+2001-04-20  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/m_whois.c (do_whois): display proper server name if the
+       user is looking up himself
+
+       * ircd/m_who.c (m_who): disable match by servername or display of
+       server names by non-opers
+
+       * include/ircd_policy.h: add define for
+       HEAD_IN_SAND_WHO_SERVERNAME to cover full intent of sub-motion 15
+       of CFV 165
+
+2001-04-18  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/s_conf.c: keep the $R in memory so we can see it clearly
+       when we do a /stats k
+
+       * ircd/s_user.c (set_user_mode): pull-up of changes to prevent
+       users from turning on +s and +g
+
+       * ircd/s_misc.c (exit_client): pull-up of changes to turn off
+       net.split notice
+
+       * ircd/parse.c: pull-up of changes to disable /trace, /links, and
+       /map for users
+
+       * ircd/m_whois.c (do_whois): pull-up of server name masking for
+       /whois
+
+       * ircd/m_user.c (m_user): removal of umode and snomask defaulting
+       functions, pull-up
+
+       * ircd/m_stats.c (m_stats): pull-up of stats-disabling stuff
+
+       * ircd/m_map.c (m_map_redirect): pull-up of m_map_redirect()
+
+       * ircd/m_links.c (m_links_redirect): pull-up of m_links_redirect()
+
+       * ircd/channel.c (channel_modes): pull-up of channel key display
+       as *
+
+       * include/ircd_policy.h: pull-up of ircd_policy.h
+
+       * include/client.h: pull-up of Set/ClearServNotice()
+
+       * ircd/gline.c (do_gline): report client name in G-line message
+       (pull-up)
+
+       * ircd/s_user.c (register_user): pull-up--show IP address in some
+       server notices dealing only with users; report which connection
+       class has filled up
+
+       * ircd/s_stats.c (report_deny_list): use conf->flags &
+       DENY_FLAGS_IP insteaf of conf->ip_kill
+
+       * ircd/m_stats.c (report_klines): use conf->flags & DENY_FLAGS_IP
+       insteaf of conf->ip_kill
+
+       * ircd/s_conf.c: use flags field in struct DenyConf; pull-up of
+       K-line by real name
+
+       * include/s_conf.h: use a flags field in struct DenyConf; define
+       DENY_FLAGS_FILE, DENY_FLAGS_IP, and DENY_FLAGS_REALNAME for
+       pull-up of K-line by real name
+
+       * ircd/m_trace.c: pull-up of IP show for user connections
+
+       * doc/example.conf: pull-up of the realname K-line documentation
+
+       * ircd/ircd.c: forward port of pid file advisory locking mechanism
+
+2001-04-16  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/send.c (sendcmdto_flag_butone): recast to just broadcast to
+       all servers, rather than to only servers that have +w/+g/whatever
+       users on them; among other things, this removes that atrocity
+       known as sentalong[] from this function
+
+       * ircd/m_admin.c: must include ircd.h to declare "me"; must
+       include hash.h to declare FindUser()
+
+       * ircd/m_wallusers.c: implementation of WALLUSERS
+
+       * ircd/m_desynch.c (ms_desynch): only send DESYNCHs to opers
+
+       * ircd/m_wallops.c: only send WALLOPS to opers
+
+       * ircd/parse.c: add WALLUSERS command to parser table
+
+       * include/handlers.h: declare wallusers handlers
+
+       * include/msg.h: add WALLUSERS command
+
+       * ircd/send.c (sendcmdto_flag_butone): if FLAGS_OPER is or'd with
+       flag, send only to appropriate opers
+
+2001-04-13  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/uping.c: refit to use the new events interface
+
+       * ircd/res.c: refit to use the new events interface
+
+       * ircd/ircd_events.c: create timer_chg(), which permits a
+       (non-periodic) timer's expire time to be modified; change the
+       logic in timer_run() so that timers that were re-added while the
+       event was being processed will not be destroyed prematurely
+
+       * include/uping.h: include the events header, declare some extra
+       fields in struct UPing, remove timeout value, and define some
+       flags for marking which cleanup items have yet to be done
+
+       * include/ircd_events.h: add a prototype for timer_chg() to change
+       the expire time of a running timer
+
+2001-03-13 Joseph Bongaarts <foxxe@wtfs.net>
+       * ircd/os_openbsd.c: Tweaked the openbsd hack a bit.
+       
+2001-03-07  Joseph Bongaarts  <foxxe@wtfs.net>
+
+       * config/configure.in: Add check for OpenBSD
+
+       * ircd/os_openbsd.c: Add seperate os dep file for openbsd which
+       differs from generic BSD, particularly in its handling of
+       _XOPEN_SOURCE.
+       
+2001-02-12  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/m_gline.c (ms_gline): propagate a G-line that happened to
+       have been added by a U-lined server, rather than going through the
+       activate/deactivate logic; propagate G-line removals by U-lined
+       servers as well
+
+       * ircd/gline.c: rename propagate_gline() to gline_propagate();
+       make gline_propagate() return an int 0 (convenience return); only
+       update lastmod in gline_activate() and gline_deactivate() if the
+       current lastmod is non-zero, since 0 lastmod is our flag of a
+       U-lined server having added a G-line
+
+       * include/gline.h (gline_propagate): exporting the G-line
+       propagation function
+
+       * ircd/m_list.c (m_list): duh; permit explicit channel name
+       specification only when /list gets two arguments ("Kev
+       #wasteland") rather than when /list gets more than two
+       arguments--nice braino
+
+2001-01-29  Thomas Helvey <twhelvey1@home.com>
+
+       * ircd/ircd_reply.c (need_more_params): fix bug that allowed
+       unregistered clients to spam opers with protocol violation
+       messages. Note: the bugfix may have eliminated some useful
+       protocol violation messages.
+       Please send protocol violation messages explicitly from the
+       functions they are discovered in, you have much better context
+       for the error there and it helps to document the behavior of the
+       server. This was also a design bug in that it violated the
+       "A function should do one thing" heuristic. Patching this one
+       would have resulted in a continuous spawning of other bugs over
+       the next 3 years, so I killed it. Check around for stuff this
+       broke and readd the calls to protocol_violation in the functions
+       that need to send the message.
+
+2001-01-29  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/channel.c (mode_parse_ban): stopper a tiny leak--if a ban
+       already existed, then the logic would (attempt to) skip it, but
+       would not free the ban string; now the ban string is free'd and
+       the ban count is decremented, releasing the ban for use
+
+       * ircd/s_user.c: make send_umode_out() take a prop argument
+       instead of testing for the PRIV_PROPAGATE privilege itself; fix
+       set_umode() to use this new argument, calculating it before
+       calculating the new privileges for a -o'd user
+
+       * ircd/m_oper.c (m_oper): pass the new prop argument to
+       send_umode_out()
+
+       * ircd/channel.c (mode_parse_ban): turn off MODE_ADD bit in bans
+       that we're not actually going to add because they already exist;
+       test that particular bit before adding to the linked list
+
+       * include/s_user.h: add a prop argument to send_umode_out() to
+       indicate whether or not to propagate the user mode
+
+2001-01-24  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/msgq.c: ircd_vsnprintf() returns the number of bytes that
+       it would have written; upper-bound the number to prevent overflows
+       by proxy; also, tune buffer size given to ircd_vsnprintf() to take
+       into account the fact that ircd_vsnprintf() already takes the
+       terminal \0 into account
+
+2001-01-22  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/msgq.c: add an incredibly ugly hack to attempt to track
+       down an apparent buffer overflow; remove msgq_map(), since it's no
+       longer used anywhere; slight tweaks to prevent off-by-one errors,
+       but these can't explain the problems we've seen
+
+       * include/msgq.h: remove msgq_map(), since it's no longer used
+       anywhere
+
+2001-01-18  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/s_user.c (set_nick_name): call client_set_privs() after
+       parsing user modes
+
+2001-01-17  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/s_bsd.c (read_message): fix a typo in the select version of
+       read_message()
+
+       * ircd/whowas.c (whowas_free): MyFree() is a macro that expects
+       its argument to be an lvalue, which means we can't use
+       whowas_clean()'s handy-dandy "return ww" feature
+
+       * ircd/ircd_features.c: default LOCOP_KILL to TRUE--oops...
+
+2001-01-16  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/ircd_events.c (timer_run): it's possible that the timer got
+       deleted during the callback processing, so don't go to the bother
+       of requeuing it if the destroy flag is set
+
+       * ircd/engine_select.c: define FD_SETSIZE to be IRCD_FD_SETSIZE
+       out of config.h if this is a *BSD; include errno.h (oops);
+       decrement error count after an hour using a timer; use FD_SETSIZE
+       constant instead of IRCD_FD_SETSIZE constant; fill in event
+       processing code
+
+       * ircd/engine_poll.c: include errno.h (oops); decrement error
+       count after an hour using a timer; fill in event processing code
+
+       * ircd/engine_kqueue.c: include errno.h (oops); decrement error
+       count after an hour using a timer; assert events filter is either
+       EVFILT_READ or EVFILT_WRITE; fill in event processing code
+
+       * ircd/engine_devpoll.c: include errno.h (oops); decrement error
+       count after an hour using a timer; fill in event processing code
+
+2001-01-15  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/client.c: fixed feattab; basically, when I changed features
+       to use small integers specifying bit positions, instead of the
+       bits themselves, I forgot to update feattab to not | these
+       privileges together; also fixed a bug in the antiprivs masking
+       loop in client_set_privs()--last index wouldn't get parsed
+
+2001-01-11  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/ircd_events.c: call event_generate() with new data
+       argument; make it set that field in struct Event; make
+       socket_add() return the value of the eng_add callback
+
+       * ircd/engine_select.c: make engine_add() return a
+       successful/unsuccessful status; add bounds-checking outside of an
+       assert; use accessor macros; use log_write(), not the deprecated
+       ircd_log(); add an assert to engine_loop() to double-check for
+       data structure corruption
+
+       * ircd/engine_poll.c: make engine_add() return a
+       successful/unsuccessful status; add bounds-checking outside of an
+       assert; use accessor macros; use log_write(), not the deprecated
+       ircd_log(); add an assert to engine_loop() to double-check for
+       data structure corruption
+
+       * ircd/engine_kqueue.c: implementation of an engine for kqueue()
+
+       * ircd/engine_devpoll.c: implementation of an engine for /dev/poll
+
+       * include/ircd_events.h: define some accessor macros; add ev_data
+       to struct Event for certain important data--errno values, for
+       instance; make EngineAdd callback tell us if it was successful or
+       not; add extra argument to event_generate(); make socket_add()
+       return the status from EngineAdd
+
+2001-01-10  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/ircd_events.c: pass initializer information about how many
+       total _filedescriptors_ may be opened at once
+
+       * ircd/ircd.c: use exported "running" instead of unexported
+       thisServer.running
+
+       * ircd/engine_select.c: implementation of an event engine based on
+       select()
+
+       * ircd/engine_poll.c: implementation of an event engine based on
+       poll()
+
+       * include/ircd_events.h: pass the engine initializer an integer
+       specifing how many _filedescriptors_ may be opened at once
+
+       * include/ircd.h: running has to be exported for the engine_*
+       event loops
+
+2001-01-09  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/ircd_events.c: include some needed headers; add some
+       comments; make evEngines[] const; bundle sig_sock and sig_fd into
+       a struct named sigInfo; rework struct evInfo to have a queue of
+       _generators_, and only when threaded; added a gen_init() function
+       to centralize generator initialization; fix various compile-time
+       errors; rework event_add() for new queueing scheme and checked for
+       compile-time errors; add casts where needed; spell evEngines[]
+       correctly; make engine_name() return const char*
+
+       * include/ircd_events.h: type EventCallBack depends on struct
+       Event, so pre-declare it; put _event_ queue into generators, and
+       only when threaded; give engine data a union to store both ints
+       and pointers; make engine name a const; fix gen_ref_dec() macro;
+       make engine_name() return a const char*
+
+       * ircd/ircd_events.c: gen_dequeue() is now exported, so move it
+       down with the non-static functions; modify event_execute() to use
+       the new gen_ref_dec() to simplify code; make sure event_generate()
+       does not generate new events for generators marked for destruction
+
+       * include/ircd_events.h: the engines, at least, may need to modify
+       reference counts to keep generators from going away while
+       something still points at them, so add reference counter
+       manipulators and export gen_dequeue() for them
+
+       * ircd/ircd_events.c: set up the list of engines to try; set up
+       the signal struct Socket; rename netInfo to evInfo; move static
+       functions near the beginning of the file; do away with
+       signal_signal() (since we no longer keep a signal count ourselves)
+       and call event_generate() directly from signal_callback--also
+       renamed some functions; allow signal_callback() to read up to
+       SIGS_PER_SOCK at once from the signal pipe; add event_init() to
+       initialize the entire event system; add event_loop() to call the
+       engine's event loop; initialize new struct GenHeader member,
+       gh_engdata; remove timer_next(); add socket_add() function to add
+       a socket; add socket_del() to mark a socket for deletion; add
+       socket_state() to transition a socket between states; add
+       socket_events() to set what events we're interested in on the
+       socket; add engine_name() to retrieve event engine's name
+
+       * include/ircd_events.h: add engine data field to struct
+       GenHeader; rename SOCK_ACTION_REMOVE to SOCK_ACTION_DEL; add a
+       note about states vs s_events; remove signal count; fold union
+       Generator back into struct Event; remove count members from struct
+       Generators; redefine engine callbacks to not take a struct
+       Engine*; add explanatory comments to callback definitions; add
+       some engine callbacks to handle operations; remove struct Engine
+       flag member--can detect single flag from eng_signal member; add
+       event_init(), event_loop(), engine_name(), and the socket_*()
+       functions; make timer_next() a macro to avoid a function call
+
+2001-01-08  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * include/ircd_events.h: rename to ircd_events.h, since it handles
+       events, not just networking stuff; add signal support; more
+       structural rearrangement
+
+       * ircd/ircd_events.c: rename to ircd_events.c, since it handles
+       events, not just networking stuff; add signal support; more
+       structural rearrangement
+
+2001-01-07  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/ircd_network.c: implement timer API; add reference counts
+       appropriately
+
+       * include/ircd_network.h: firm up some pieces of the interface;
+       split out members everything has into a separate structure; add
+       reference counts; add timer API
+
+2001-01-06  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/ircd_network.c: static data and event manipulation
+       functions for new event processing system
+
+       * include/ircd_network.h: data structures for new event processing
+       system
+
+2001-01-03  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/whowas.c: Completely re-did the old allocation scheme by
+       turning it into a linked list, permitting the
+       NICKNAMEHISTORYLENGTH feature to be changed on the fly
+
+       * ircd/s_debug.c (count_memory): use FEAT_NICKNAMEHISTORYLENGTH
+       feature instead of old #define
+
+       * ircd/ircd_features.c: add NICKNAMEHISTORYLENGTH feature as an
+       integer feature with a notify callback (whowas_realloc)
+
+       * ircd/client.c (client_set_privs): second memset was supposed to
+       be over antiprivs, not privs; thanks, Chris Behrens
+       <cbehrens@xo.com> for pointing that out...
+
+       * include/whowas.h: new elements for an extra linked list in
+       struct Whowas; a notify function for feature value changes
+
+       * include/ircd_features.h: new feature--FEAT_NICKNAMEHISTORYLENGTH
+
+       * config/config-sh.in: NICKNAMEHISTORYLENGTH is now a feature
+
+2001-01-02  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * config/config-sh.in: get rid of DEFAULT_LIST_PARAMETER
+       compile-time option--now in features subsystem
+
+       * ircd/motd.c (motd_init): rework motd_init() to be called as the
+       notify function for MPATH and RPATH features (should probably
+       split it up a bit, though...)
+
+       * ircd/m_privs.c (mo_privs): if called with no parameters, return
+       privs of the caller, rather than an error
+
+       * ircd/m_list.c: pull usage message into its own function; pull
+       list parameter processing into its own function that does not
+       modify the contents of the parameter; add list_set_default() to
+       set the default list parameter (uses the notify hook); rework
+       m_list() to make use of these functions; removed dead code
+
+       * ircd/ircd_log.c (log_feature_mark): make sure to return 0, since
+       we have no notify handler
+
+       * ircd/ircd_features.c: add notify callback for notification of
+       value changes; give mark callback an int return value to indicate
+       whether or not to call the notify callback; fix up feature macros
+       for new notify callback; add DEFAULT_LIST_PARAM feature; rewrite
+       string handling in feature_set() to deal with def_str being a null
+       pointer; wrote feature_init() to set up all defaults appropriately
+
+       * ircd/ircd.c (main): call feature_init() instead of
+       feature_mark(), to avoid calling notify functions while setting up
+       defaults
+
+       * ircd/client.c: updated to deal with new privileges structure
+
+       * ircd/class.c: updated so init_class() can be called should one
+       of PINGFREQUENCY, CONNECTFREQUENCY, MAXIMUM_LINKS, or
+       DEFAULTMAXSENDQLENGTH be changed
+
+       * include/ircd_log.h: log_feature_mark() updated to fit with new
+       API changes
+
+       * include/ircd_features.h: added DEFAULT_LIST_PARAM feature and
+       feature_init() function (found necessary since adding the notify
+       stuff and notifying motd.c during start-up...before we defined
+       RPATH!)
+
+       * include/client.h: move privs around to enable addition of more
+       bits if necessary; based on the FD_* macros
+
+       * include/channel.h: declare list_set_default (actually located in
+       m_list.c *blanche*)
+
+       * ircd/s_user.c: retrieve MAXSILES and MAXSILELENGTH (now
+       AVBANLEN*MAXSILES) from features subsystem
+
+       * ircd/s_debug.c (debug_serveropts): CMDLINE_CONFIG doesn't go to
+       anything anymore
+
+       * ircd/s_bsd.c: retrieve HANGONGOODLINK and HANGONRETRYDELAY from
+       the features subsystem
+
+       * ircd/s_auth.c (start_auth): NODNS migrated to the features
+       subsystem
+
+       * ircd/random.c: created random_seed_set() function to set seed
+       value, along with some stuff to make ircrandom() a little more
+       random--state preserving, xor of time instead of direct usage,
+       etc.; it's still a pseudo-random number generator, though, and
+       hopefully I haven't broken the randomness
+
+       * ircd/m_version.c: FEATUREVALUES makes use of feature_int() calls
+
+       * ircd/m_join.c: use features interface to retrieve
+       MAXCHANNELSPERUSER
+
+       * ircd/ircd_features.c: add NODISP flag for super-secret features;
+       add a whole bunch of new features migrated over from make config
+
+       * ircd/ircd.c: use features interface to retrieve PINGFREQUENCY,
+       CONNECTTIMEOUT, and TIMESEC
+
+       * ircd/client.c (client_get_ping): use features interface to
+       retrieve PINGFREQUENCY
+
+       * ircd/class.c: use features interface to retrieve PINGFREQUENCY,
+       CONNECTFREQUENCY, MAXIMUM_LINKS, and DEFAULTMAXSENDQLENGTH
+
+       * ircd/chkconf.c (DEFAULTMAXSENDQLENGTH): since it's now in the
+       features subsystem, we have to add something explicit
+
+       * ircd/channel.c: use features interface to retrieve
+       KILLCHASETIMELIMIT, MAXBANLENGTH, MAXBANS, and MAXCHANNELSPERUSER;
+       note that MAXBANLENGTH is now calculated dynamically from MAXBANS
+       and AVBANLEN
+
+       * ircd/Makefile.in: run make depend
+
+       * include/supported.h (FEATURESVALUES): update to reference
+       feature settings
+
+       * include/random.h: add prototype for random_seed_set
+
+       * include/ircd_features.h: add several more features
+
+       * include/channel.h: move MAXBANS and MAXBANLENGTH into feature
+       subsystem
+
+       * config/config-sh.in: feature-ized some more stuff
+
+       * include/motd.h: some new elements in motd.h for motd.c changes
+
+       * ircd/motd.c: motd_cache() now searches a list of already cached
+       MOTD files; saves us from having duplicate caches in memory if
+       there are two identical T-lines for two different sites...
+
+2001-01-02  Perry Lorier <isomer@coders.net>
+       * ircd/motd.c: don't core if the motd isn't found.  Bug found by
+       Amarande.
+
+2001-01-02  Perry Lorier <isomer@coders.net>
+       * ircd/s_err.c: Added third param to 004 - the channel modes that tage params.  Used by hybrid/epic.
+       * ircd/s_channels.c: Added fix for msg'ing a -n+m channel - thanks
+               to guppy for noticing, and hektik for providing the fix.
+       * misc others: Minor cleanups, added more protocol_violations, ripped
+               out more P09 stuffs, bit more protocol neg stuff.
+
+2000-12-19  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/m_ison.c (m_ison): Dianora says that ISON has to end with a
+       space (*sigh* stupid clients...)
+
+       * ircd/s_user.c: make WALLOPS_OPER_ONLY a feature managed through
+       ircd_features.[ch]
+
+       * ircd/s_err.c: get rid of GODMODE conditionals
+
+       * ircd/s_debug.c (debug_serveropts): switch to using appropriate
+       calls into the features subsystem for various serveropts
+       characters
+
+       * ircd/s_conf.c (find_conf_entry): get rid of USEONE conditional
+
+       * ircd/s_bsd.c: remove GODMODE conditional; use features subsystem
+       to get value of VIRTUAL_HOST and CLIENT_FLOOD; remove
+       NOFLOWCONTROL conditional
+
+       * ircd/s_auth.c: use features subsystem to determine value of
+       KILL_IPMISMATCH
+
+       * ircd/parse.c: get rid of NOOPER and GODMODE conditionals; use
+       features subsystem to determine the setting of IDLE_FROM_MSG
+
+       * ircd/numnicks.c: get rid of EXTENDED_NUMERICS conditionals
+
+       * ircd/motd.c: get value of NODEFAULTMOTD from features subsystem;
+       use features subsystem to get motd file names
+
+       * ircd/m_settime.c: get value of RELIABLE_CLOCK from features
+       subsystem
+
+       * ircd/m_server.c: get rid of CRYPT_LINK_PASSWORD, since it does
+       us no good; use features subsystem to figure out if we need to do
+       HUB-type stuff; make TESTNET debugging sendto_opmask_butone's use
+       the Debug(()) macro instead; get value of RELIABLE_CLOCK from
+       features subsystem
+
+       * ircd/m_privmsg.c: get IDLE_FROM_MSG from the features subsystem
+
+       * ircd/m_oper.c: get CRYPT_OPER_PASSWORD from the features
+       subsystem
+
+       * ircd/m_connect.c: get SERVER_PORT from the features subsystem
+
+       * ircd/ircd_log.c (log_set_file): fix a bug that kept log files
+       from getting marked if they were already set to something...
+
+       * ircd/ircd_features.c: add a flag to indicates read-only access;
+       add several new features that used to be compile-time selected
+
+       * ircd/ircd.c: grab pidfile out of feature subsystem; don't check
+       access to motd files (what the heck?); make sure to initialize the
+       feature subsystem before trying to write the config file
+
+       * ircd/dbuf.c: use feature_int() to retrieve BUFFERPOOL settings;
+       use feature_bool() to figure out if we're using the FERGUSON
+       flusher
+
+       * ircd/Makefile.in: MPATH and RPATH are now done differently, so
+       remove the clause that creates empty files of that name; also ran
+       make depend
+
+       * include/sys.h: CLIENT_FLOOD is now a feature; unfortunately,
+       there is no easy way to bounds-check it at present
+
+       * include/querycmds.h: make sure ircd_features.h is included; use
+       feature_str(FEAT_DOMAINNAME) in calls to match()
+
+       * include/ircd_features.h: many new features that used to be
+       compile-time selected
+
+       * config/config-sh.in: add * to DOMAINNAME; try also using first
+       argument to search in /etc/resolv.conf; removed many compile-time
+       options that now can be configured through the features system
+
+2000-12-18  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * doc/api/log.txt: how to use the logging API
+
+       * doc/api/features.txt: how to use the features API
+
+       * doc/api/api.txt: how to write API documentation
+
+       * include/ircd_features.h: rearranged a couple of features for
+       neatness purposes
+
+       * ircd/ircd_features.c: cleaned up the macros some; rearranged
+       some code to all go into the switch; rearranged a couple of
+       features for neatness purposes
+
+2000-12-16  Greg Sikorski <gte@atomicrevs.demon.co.uk>
+       * ircd/os_bsd.c: Added os_set_tos for BSD users.
+
+2000-12-16  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/ircd_features.c: Isomer almost got it right; you need to
+       use F_I(), since it's an integer value, not a boolean value.  The
+       asserts in feature_int would catch you out...  Also made the F_*
+       macros take flags
+
+       * ircd/s_err.c: define RPL_PRIVS reply
+
+       * ircd/parse.c: put new PRIVS command into command table
+
+       * ircd/m_privs.c (mo_privs): message handler to report operator
+       privileges
+
+       * ircd/ircd_features.c: declare new features OPER_SET and
+       LOCOP_SET; redo boolean testing routine to accept TRUE, YES, and
+       ON for boolean TRUE, and FALSE, NO, and OFF for boolean FALSE
+
+       * ircd/client.c: simplify client_set_privs() with a table that
+       defines what features to test for; add new client_report_privs()
+
+       * ircd/Makefile.in: compile new m_privs.c; run make depend
+
+       * include/numeric.h (RPL_PRIVS): new reply numeric for displaying
+       an operator's privileges
+
+       * include/msg.h: define new command: PRIVS
+
+       * include/ircd_features.h: create new features OPER_SET and
+       LOCOP_SET for controlling access to /set
+
+       * include/handlers.h (mo_privs): declare message handler for
+       reporting oper privileges
+
+       * include/client.h (client_report_privs): declare function to
+       report what privileges an oper has
+
+       * ircd/m_whois.c (do_whois): fix a bug that caused /whois to
+       report that a user is an oper if the oper doing the /whois had
+       PRIV_SEE_OPERS
+
+2000-12-17  Isomer <Isomer@coders.net>
+       * ircd/listener.c: added support for TOS twiddling as a 'feature'.
+
+2000-12-17  Isomer <Isomer@coders.net>
+       * ircd/os_linux.c: add TOS stuffs
+
+       * ircd/listener.c: add TOS stuffs
+
+2000-12-16  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/whocmds.c (do_who): use HasPriv to determine whether or not
+       to indicate a user is an oper
+
+       * ircd/s_user.c: clear privileges setting when deopping; don't
+       propagate +o unless user has PRIV_PROPAGATE privilege
+
+       * ircd/s_debug.c (debug_serveropts): created debug_serveropts()
+       function and replaced how the server option string is generated
+
+       * ircd/parse.c: remove conditional on CONFIG_OPERCMDS
+
+       * ircd/m_whois.c (do_whois): use HasPriv to determine whether or
+       not to indicate the user is an operator
+
+       * ircd/m_who.c: use HasPriv to determine whether or not a user
+       should be displayed in the list of opers
+
+       * ircd/m_version.c: call debug_serveropts() to get server option
+       string
+
+       * ircd/m_userip.c (userip_formatter): use HasPriv to determine
+       whether or not to show oper status
+
+       * ircd/m_userhost.c (userhost_formatter): use HasPriv to determine
+       whether or not to show oper status
+
+       * ircd/m_restart.c (mo_restart): replace ugly #ifdef conditional
+       checks with HasPriv check; remove dead code
+
+       * ircd/m_rehash.c (mo_rehash): replace ugly #ifdef conditional
+       checks with HasPriv check
+
+       * ircd/m_opmode.c (mo_opmode): use HasPriv to check permissions;
+       use feature_bool to check if disabled
+
+       * ircd/m_oper.c (m_oper): set oper priviliges
+
+       * ircd/m_mode.c (m_mode): replace #ifdef conditional with HasPriv
+       check
+
+       * ircd/m_kill.c (mo_kill): use HasPriv checks to determine if we
+       can kill
+
+       * ircd/m_kick.c (m_kick): replace #ifdef conditional with HasPriv
+       check
+
+       * ircd/m_jupe.c (mo_jupe): rework permissions checking structure;
+       use feature_bool to check if disabled
+
+       * ircd/m_join.c (m_join): remove BADCHAN conditional; replace
+       #ifdef conditional with a HasPriv check
+
+       * ircd/m_gline.c (mo_gline): rework permissions checking
+       structure; use feature_bool to check if any part is disabled
+
+       * ircd/m_die.c: replace ugly #ifdef conditionals with HasPriv
+       check; remove dead code
+
+       * ircd/m_clearmode.c: use feature_bool() to detect if we're
+       disabled; use HasPriv to figure out what we're permitted to do;
+       only allow clearmode on moded channels
+
+       * ircd/ircd_features.c: define various features; use HasPriv to
+       verify permissions to set/reset
+
+       * ircd/gline.c (gline_add): use HasPriv instead of #ifdef
+       conditionals
+
+       * ircd/client.c (client_set_privs): function to set an oper's
+       privileges
+
+       * ircd/channel.c: use HasPriv calls instead of #ifdef conditionals
+
+       * include/whocmds.h: deconditionalize several macros and
+       substitute appropriate calls to HasPriv()
+
+       * include/s_debug.h: get rid of global serveropts[]; define new
+       function debug_serveropts() to build that string on the fly
+
+       * include/ircd_features.h: define some features
+
+       * include/client.h: add privs member to struct Connection; define
+       various priviledges
+
+       * include/channel.h: no longer using IsOperOnLocalChannel; remove
+       conditional of MAGIC_OPER_OVERRIDE on OPER_WALK_THROUGH_LMODES
+
+       * doc/Configure.help: remove help information for deprecated
+       options
+
+       * config/config-sh.in: remove certain deprecated options having to
+       do with what opers can and cannot do--first stage in moving
+       compile-time constants into the .conf
+
+2000-12-16  Isomer <Isomer@coders.net>
+       * ircd/parse.c: detect if the prefix is missing and try and recover
+       instead of coring.
+
+2000-12-15  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/ircd_log.c: found and fixed some bugs in the debug logging
+       code that would sometimes result in the log file not being
+       reopened--which meant that a user could connect and get the
+       logging output--oops
+
+       * ircd/Makefile.in: run make depend...
+
+       * ircd/s_stats.c: get rid of report_feature_list()
+
+       * ircd/s_err.c: add the 'bad value' error message, shift error
+       messages over somewhat
+
+       * ircd/s_debug.c (debug_init): call log_debug_init with the
+       use_tty flag
+
+       * ircd/s_conf.c (read_configuration_file): unmark features before
+       reading the config file, then reset unmarked features after
+       reading the config file
+
+       * ircd/m_stats.c: use feature_report() instead of
+       report_feature_list()
+
+       * ircd/ircd_log.c: fix log_debug_file (bogus assertion); add
+       special 'mark' flags and use them; add the stuff needed by the
+       features API
+
+       * ircd/ircd_features.c: rework the features API and add gobs of
+       comments to try to explain what some of these complex functions
+       are actually doing
+
+       * include/s_stats.h: get rid of report_feature_list(); use
+       feature_report() instead
+
+       * include/numeric.h: added a new error message and shifted old
+       values over some--this is, after all, an alpha
+
+       * include/ircd_log.h: log_debug_init now takes an integer to tell
+       it if it should be using the tty; added a couple of functions
+       required by the features API
+
+       * include/ircd_features.h: add an enum and some more functions to
+       flesh out the feature API--it should now be possible to put all
+       those compile-time constants in the config file!
+
+       * ircd/send.c: got the direction of the assert incorrect...
+
+       * ircd/send.c: implement the efficiency of flush_connections by
+       creating a linked list of struct Connection's with queued data;
+       also get rid of flush_sendq_except and make sure to yank
+       connections out of the list when their sendQs become empty (notice
+       the assertion in flush_connections!)
+
+       * ircd/s_bsd.c (close_connection): must yank the Connection out of
+       the sendq list
+
+       * ircd/list.c (dealloc_connection): must yank the Connection out
+       of the sendq list
+
+       * ircd/dbuf.c (dbuf_put): call flush_connections instead of the
+       deprecated flush_sendq_except
+
+       * ircd/client.c: define a couple new helper functions for sendq
+       threading--this will make the flush_connections function in send.c
+       considerably more efficient by creating a linked list of
+       Connections that have queued data to send
+
+       * include/send.h: remove flush_sendq_except, as it's not used
+       anymore
+
+       * include/client.h: declare a couple new helper functions for the
+       sendq threading system
+
+2000-12-14  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/m_ison.c (m_ison): Apply Diane Bruce's patch to make ISON
+       parse all arguments
+
+       * ircd/s_debug.c (count_memory): modify to report for clients and
+       connections, not local clients and remote clients
+
+       * ircd/list.c: fiddle with the client-fiddling functions to take
+       into account the divorce of struct Connection from struct Client
+
+       * ircd/ircd.c: define a struct Connection for me, initialize it,
+       and link it into the right place (ewww, globals!)
+
+       * include/client.h: remove CLIENT_{LOCAL,REMOTE}_SIZE; split
+       struct Client into struct Client and struct Connection; redefine
+       local-portion accessor macros to go through struct Client to the
+       struct Connection; define struct Connection accessor macros
+
+2000-12-13  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/whowas.c: missed a couple of accesses to a struct Client
+
+       * ircd/uping.c: missed a couple of accesses to a struct Client
+
+       * ircd/send.c: missed a couple of accesses to a struct Client
+
+       * ircd/s_user.c: missed a couple of accesses to a struct Client
+
+       * ircd/s_misc.c: missed a couple of accesses to a struct Client
+
+       * ircd/s_conf.c: missed a couple of accesses to a struct Client
+
+       * ircd/s_bsd.c: missed a couple of accesses to a struct Client
+
+       * ircd/s_auth.c: missed a couple of accesses to a struct Client
+
+       * ircd/res.c: missed a couple of accesses to a struct Client
+
+       * ircd/parse.c: missed a couple of accesses to a struct Client
+
+       * ircd/m_whois.c: use new accessor macros for struct Client
+
+       * ircd/m_who.c: use new accessor macros for struct Client
+
+       * ircd/m_wallchops.c: use new accessor macros for struct Client
+
+       * ircd/m_version.c: use new accessor macros for struct Client
+
+       * ircd/m_userip.c: use new accessor macros for struct Client
+
+       * ircd/m_userhost.c: use new accessor macros for struct Client
+
+       * ircd/m_user.c: use new accessor macros for struct Client
+
+       * ircd/m_uping.c: use new accessor macros for struct Client
+
+       * ircd/m_trace.c: use new accessor macros for struct Client
+
+       * ircd/m_topic.c: use new accessor macros for struct Client
+
+       * ircd/m_time.c: use new accessor macros for struct Client
+
+       * ircd/m_stats.c: use new accessor macros for struct Client
+
+       * ircd/m_squit.c: use new accessor macros for struct Client
+
+       * ircd/m_silence.c: use new accessor macros for struct Client
+
+       * ircd/m_server.c: use new accessor macros for struct Client;
+       remove dead code
+
+       * ircd/m_rpong.c: use new accessor macros for struct Client
+
+       * ircd/m_rping.c: use new accessor macros for struct Client
+
+       * ircd/m_quit.c: use new accessor macros for struct Client
+
+       * ircd/m_privmsg.c: use new accessor macros for struct Client
+
+       * ircd/m_pong.c: use new accessor macros for struct Client; remove
+       dead code
+
+       * ircd/m_ping.c: use new accessor macros for struct Client
+
+       * ircd/m_pass.c: use new accessor macros for struct Client
+
+       * ircd/m_part.c: use new accessor macros for struct Client
+
+       * ircd/m_oper.c: use new accessor macros for struct Client
+
+       * ircd/m_notice.c: use new accessor macros for struct Client
+
+       * ircd/m_nick.c: use new accessor macros for struct Client
+
+       * ircd/m_names.c: use new accessor macros for struct Client
+
+       * ircd/m_mode.c: use new accessor macros for struct Client
+
+       * ircd/m_map.c: use new accessor macros for struct Client
+
+       * ircd/m_list.c: use new accessor macros for struct Client
+
+       * ircd/m_links.c: use new accessor macros for struct Client;
+       remove some dead code
+
+       * ircd/m_kill.c: use new accessor macros for struct Client; remove
+       some dead code
+
+       * ircd/m_kick.c: use new accessor macros for struct Client
+
+       * ircd/m_join.c: use new accessor macros for struct Client; remove
+       some dead code
+
+       * ircd/m_ison.c: use new accessor macros for struct Client
+
+       * ircd/m_invite.c: use new accessor macros for struct Client
+
+       * ircd/m_info.c: use new accessor macros for struct Client
+
+       * ircd/m_gline.c: use new accessor macros for struct Client
+
+       * ircd/m_error.c: use new accessor macros for struct Client
+
+       * ircd/m_create.c: use new accessor macros for struct Client
+
+       * ircd/m_connect.c: use new accessor macros for struct Client;
+       removed some dead code
+
+       * ircd/m_burst.c: use new accessor macros for struct Client
+
+       * ircd/m_away.c: use new accessor macros for struct Client
+
+       * ircd/m_admin.c: use new accessor macros for struct Client
+
+       * ircd/hash.c: missed a couple of accesses to a struct Client
+
+       * ircd/gline.c: missed a couple of accesses to a struct Client
+
+       * ircd/crule.c: missed a couple of accesses to a struct Client
+
+       * ircd/class.c: missed an access to a struct Client
+
+       * ircd/channel.c: missed a couple of accesses to a struct Client
+
+       * ircd/IPcheck.c: missed an access to a struct Client
+
+       * include/querycmds.h: fix a couple of stats macros to use
+       structure accessor macros
+
+       * include/client.h: change structure member names to highlight any
+       places in the code I've missed
+
+2000-12-12  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/whowas.c: use new struct Client accessor macros
+
+       * ircd/whocmds.c: use new struct Client accessor macros
+
+       * ircd/send.c: use new struct Client accessor macros
+
+       * ircd/s_user.c: use new struct Client accessor macros; removed
+       some dead code
+
+       * ircd/s_serv.c: use new struct Client accessor macros; removed
+       some dead code
+
+       * ircd/s_numeric.c: use new struct Client accessor macros
+
+       * ircd/s_misc.c: use new struct Client accessor macros
+
+       * ircd/s_debug.c: use new struct Client accessor macros
+
+       * ircd/s_conf.c: use new struct Client accessor macros
+
+       * ircd/s_bsd.c: use new struct Client accessor macros
+
+       * ircd/s_auth.c: use new struct Client accessor macros
+
+       * ircd/parse.c: use new struct Client accessor macros
+
+       * ircd/packet.c: use new struct Client accessor macros
+
+       * ircd/numnicks.c: use new struct Client accessor macros
+
+       * ircd/motd.c: use new struct Client accessor macros
+
+       * ircd/listener.c: use new struct Client accessor macros
+
+       * ircd/list.c: use new struct Client accessor macros
+
+       * ircd/jupe.c: use new struct Client accessor macros
+
+       * ircd/ircd_snprintf.c: use new struct Client accessor macros
+
+       * ircd/ircd_reply.c: use new struct Client accessor macros
+
+       * ircd/ircd_relay.c: use new struct Client accessor macros
+
+       * ircd/ircd.c: use new struct Client accessor macros
+
+       * ircd/gline.c: catch some instances of me.<stuff> I missed
+       previously
+
+       * ircd/client.c: use cli_ instead of con_
+
+       * ircd/class.c: use cli_ instead of con_
+
+       * ircd/channel.c: use cli_ instead of con_
+
+       * ircd/IPcheck.c: use cli_ instead of con_; catch some instances
+       of me.<stuff> I missed previously
+
+       * include/client.h: use cli_ instead of con_...seemed like a good
+       idea at the time *shrug*
+
+2000-12-11  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/hash.c: use struct Client accessor macros
+
+       * ircd/gline.c: use struct Client accessor macros
+
+       * ircd/crule.c: use struct Client accessor macros
+
+       * ircd/client.c: use struct Client accessor macros; remove some
+       dead code
+
+       * ircd/class.c: use struct Client accessor macros
+
+       * ircd/channel.c: use struct Client accessor macros; remove some
+       dead code
+
+       * ircd/IPcheck.c: use struct Client accessor macros
+
+       * include/numnicks.h: use struct Client accessor macros
+
+       * include/client.h: first step to divorcing struct Client and
+       struct Connection--define accessor macros and use them
+
+       * ircd/gline.c: When Uworld removed Uworld-set G-lines, only the
+       uplink would remove them.  This is because the removal protocol
+       message wasn't being sent to the uplinks.  This is fixed by fixing
+       propagate_gline() to send the proper number of arguments depending
+       on whether or not we're adding or deleting the Uworld gline, and
+       by having gline_deactivate() make sure to turn off the active bit
+       and call propagate_gline() if it's a Uworld gline
+
+2000-12-10  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/os_generic.c: make sure IOV_MAX gets defined, just in case
+
+       * ircd/os_bsd.c: apparently BSD doesn't have IOV_MAX defined
+       anywhere intelligent...
+
+2000-12-09  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/send.c (send_queued): call deliver_it with appropriate
+       arguments
+
+       * ircd/s_serv.c: reorder a couple of headers--cosmetic
+
+       * ircd/s_bsd.c (deliver_it): make deliver_it work with a struct
+       MsgQ
+
+       * ircd/os_solaris.c (os_sendv_nonb): function for calling writev
+       with appropriate iovec
+
+       * ircd/os_linux.c (os_sendv_nonb): function for calling writev
+       with appropriate iovec
+
+       * ircd/os_generic.c (os_sendv_nonb): function for calling writev
+       with appropriate iovec
+
+       * ircd/os_bsd.c (os_sendv_nonb): function for calling writev with
+       appropriate iovec
+
+       * ircd/msgq.c (msgq_mapiov): add a len_p argument for totalling up
+       exactly how much we're trying to write out to the fd
+
+       * include/s_bsd.h: make deliver_it take a struct MsgQ
+
+       * include/msgq.h: add a len_p argument to msgq_mapiov to help
+       detect short writes that indicate possible socket blocking
+
+       * include/ircd_osdep.h: declare os_sendv_nonb()
+
+       * ircd/channel.c (modebuf_mode): don't add empty modes...
+
+2000-12-08  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * include/send.h: add prio argument to send_buffer to select
+       between normal and priority queues
+
+       * ircd/s_user.c (send_user_info): add prio argument to send_buffer
+       call
+
+       * ircd/m_ison.c (m_ison): add prio argument to send_buffer call
+
+       * ircd/ircd_reply.c (send_reply): add prio argument to send_buffer
+       call
+
+       * ircd/channel.c (send_channel_modes): add prio argument to
+       send_buffer call
+
+       * ircd/send.c (send_buffer): add a prio argument to select the
+       priority queue; update send.c functions to use it
+
+       * ircd/msgq.c (msgq_add): remove msgq_prio; fold msgq_link and
+       msgq_add; add a prio argument to msgq_add to select the priority
+       queue
+
+       * include/msgq.h: remove msgq_prio; add a prio argument to
+       msgq_add
+
+       * ircd/send.c: remove sendbuf; remove GODMODE code; switch to
+       using msgq functions instead of dbuf functions; remove old, dead
+       sendto_* functions; redo send_buffer to take a struct MsgBuf;
+       rework sendcmdto_* functions to make use of the new struct MsgBuf
+
+       * ircd/s_user.c: remove hunt_server; restructure send_user_info to
+       make appropriate use of struct MsgBuf
+
+       * ircd/s_debug.c (count_memory): count memory used by the MsgQ
+       system and report it
+
+       * ircd/s_conf.c (read_configuration_file): use
+       sendto_opmask_butone instead of the now dead sendto_op_mask
+
+       * ircd/s_bsd.c: switch to using appropriate MsgQLength and other
+       calls on sendQ
+
+       * ircd/parse.c (parse_server): get rid of a piece of GODMODE code
+
+       * ircd/msgq.c: add msgq_append and msgq_bufleft; fix a bug in
+       msgq_clean
+
+       * ircd/m_version.c: fix spelling in comments marking dead code
+
+       * ircd/m_userip.c (userip_formatter): restructure to make use of
+       struct MsgBuf
+
+       * ircd/m_userhost.c (userhost_formatter): restructure to make use
+       of struct MsgBuf
+
+       * ircd/m_stats.c: use MsgQLength on a sendQ
+
+       * ircd/m_settime.c: use MsgQLength instead of DBufLength on a
+       sendQ; mark a piece of dead code
+
+       * ircd/m_names.c: use send_reply instead of sendto_one
+
+       * ircd/m_mode.c: use new mode; remove old dead code
+
+       * ircd/m_ison.c (m_ison): restructure to make use of struct MsgBuf
+
+       * ircd/m_burst.c: use BUFSIZE instead of IRC_BUFSIZE; remove old
+       dead code
+
+       * ircd/listener.c (accept_connection): use sendto_opmask_butone
+       instead of sendto_op_mask
+
+       * ircd/list.c (free_client): use MsgQClear to clear sendQ
+
+       * ircd/ircd_reply.c: remove send_error_to_client; restructure
+       send_reply to make use of struct MsgBuf
+
+       * ircd/dbuf.c (dbuf_put): remove argument to flush_sendq_except,
+       since its no longer used (at least currently)
+
+       * ircd/channel.c: restructure send_channel_modes to make use of
+       struct MsgBuf; remove set_mode, add_token_to_sendbuf, cancel_mode,
+       and send_hack_notice; use BUFSIZE instead of IRC_BUFSIZE
+
+       * ircd/Makefile.in: add msgq.c to list of sources; run make depend
+
+       * ircd/IPcheck.c: use sendcmdto_one instead of sendto_one
+
+       * include/send.h: send_buffer now takes a struct MsgBuf * instead
+       of a char *; flush_sendq_except now takes no arguments, as sendq
+       flushing currently only happens in dbuf.h and sendQ is a struct
+       MsgQ; remove prototypes for a lot of old sendto_* functions that
+       aren't used anymore; remove sendbuf and IRC_BUFSIZE--the former is
+       no longer needed, and the latter is identical to BUFSIZE in
+       ircd_defs.h
+
+       * include/s_user.h: make InfoFormatter take a struct MsgBuf*
+       instead of a char *; also make it return void, instead of char *
+
+       * include/msgq.h: add msgq_append and msgq_bufleft functions
+
+       * include/client.h: use a struct MsgQ instead of a struct DBuf for
+       sendq
+
+       * doc/Configure.help: Remove help for compile-time options that
+       have gone away
+
+       * config/config-sh.in: remove CONFIG_NEWMODE
+
+       * ircd/m_server.c (mr_server): don't send server IPs in any server
+       notices
+
+       * ircd/msgq.c (msgq_vmake): add \r\n to messages
+
+2000-12-07  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * include/msgq.h: declare the MsgQ API
+
+       * ircd/msgq.c: implementation of new MsgQ system
+
+2000-12-06  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/ircd_features.c: #include was supposed to be for
+         ircd_features.h, not features.h--missed when I had to do a
+         rename because of namespace collision
+
+2000-12-05  Greg Sikorski <gte@atomicrevs.demon.co.uk>
+       * ircd/m_topic.c: Added missing braces that caused all remote
+         topics to be ignored.
+
+2000-12-04  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/m_create.c: I'm tired of the exit_client warning :)
+       (ms_create): discovered that exit_client() was being called with
+       too few arguments
+
+       * ircd/s_misc.c (exit_client): remove all dependance on
+       FNAME_USERLOG, since that's now gone; log only to LS_USER
+
+       * ircd/s_debug.c: USE_SYSLOG no longer means anything
+
+       * ircd/m_oper.c (m_oper): no longer log to LS_OPERLOG--we already
+       log to LS_OPER
+
+       * ircd/m_kill.c: no longer conditionalize on SYSLOG_KILL
+
+       * ircd/ircd_log.c: remove LS_OPERLOG, LS_USERLOG
+
+       * include/ircd_log.h: remove LS_OPERLOG, LS_USERLOG--they serve
+       the same purpose as LS_USER and LS_OPER
+
+       * config/config-sh.in: remove no longer relevant log config
+       variables
+
+       * ircd/uping.c (uping_init): use log_write instead of ircd_log
+
+       * ircd/s_misc.c (exit_client): use log_write instead of ircd_log
+
+       * ircd/s_conf.c: use log_write instead of ircd_log
+
+       * ircd/s_bsd.c (report_error): use log_write instead of ircd_log
+
+       * ircd/s_auth.c (timeout_auth_queries): use log_write instead of
+       ircd_log
+
+       * ircd/res.c (send_res_msg): use log_write instead of ircd_log
+
+       * ircd/m_who.c: use log_write instead of write_log; no longer
+       conditionalize on WPATH; mark dead ircd_log calls
+
+       * ircd/m_uping.c: mark dead ircd_log call
+
+       * ircd/m_server.c (mr_server): use log_write instead of ircd_log
+
+       * ircd/m_restart.c: use log_write instead of ircd_log; mark dead
+       ircd_log calls
+
+       * ircd/m_rehash.c (mo_rehash): use log_write instead of ircd_log
+
+       * ircd/m_oper.c: use log_write instead of ircd_log; no longer
+       conditionalize on FNAME_OPERLOG; mark dead ircd_log calls
+
+       * ircd/m_kill.c: mark dead ircd_log calls
+
+       * ircd/m_connect.c: use log_write instead of ircd_log; mark dead
+       ircd_log
+
+       * ircd/m_clearmode.c: use log_write instead of write_log; no
+       longer conditionalize on OPATH
+
+       * ircd/jupe.c: use log_write instead of write_log; no longer
+       conditionalize on JPATH
+
+       * ircd/ircd_log.c: add USER subsystem; remove ircd_log() compat
+       function; fix a couple of bugs
+
+       * ircd/ircd_alloc.c: fixed a comment
+
+       * ircd/ircd.c: use log_write instead of ircd_log; fold server
+       notice generation in a couple of cases
+
+       * ircd/gline.c: use log_write instead of write_log; no longer
+       conditionalize on GPATH
+
+       * ircd/channel.c (modebuf_flush_int): use log_write instead of
+       write_log; no longer conditionalize on OPATH
+
+       * ircd/Makefile.in: run make depend, since dependencies have
+       changed
+
+       * doc/example.conf: add system USER to documentation
+
+       * include/ircd_log.h: add system USER; remove old ircd_log()
+       declarations
+
+2000-12-04  Isomer <isomer@coders.net>
+       * ircd/m_names.c: Add NAMES_EON to do_names to say add a
+       'end_of_names' reply when done.
+       * ircd/m_join.c: use NAMES_EON as mentioned above
+
+2000-12-01  net  <simms@LUCIDA.QC.CA>
+
+       * ircd/motd.c: add a freelist for struct Motds
+
+2000-11-30  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/s_stats.c (report_feature_list): report features--only
+       local opers can see logging configuration, since it doesn't really
+       mean anything to users
+
+       * ircd/s_err.c: add reply messages for new feature subsystem
+
+       * ircd/s_conf.c: add F lines to .conf
+
+       * ircd/parse.c: add the message descriptions for /set, /reset, and
+       /get
+
+       * ircd/m_stats.c: add /stats f
+
+       * ircd/m_set.c (mo_set): implement /set
+
+       * ircd/m_reset.c (mo_reset): implement /reset
+
+       * ircd/m_rehash.c: /rehash m now flushes MOTD cache, and /rehash l
+       reopens log files (for log file rotation)
+
+       * ircd/m_get.c (mo_get): implement /get
+
+       * ircd/ircd_log.c: use int instead of void return value; add
+       log_report_features() and log_canon(); fix a function that
+       disappears if DEBUGMODE not #define'd
+
+       * ircd/ircd_features.c: functions to manipulate feature settings
+       either from the config file or with the new /set, /reset, and /get
+       commands
+
+       * ircd/Makefile.in: add new .c files, run make depend
+
+       * include/s_stats.h: declare report_feature_list() (/stats f
+       handler)
+
+       * include/numeric.h: add RPL_STATSFLINE, RPL_FEATURE,
+       ERR_NOFEATURE, ERR_BADLOGTYPE, ERR_BADLOGSYS, and ERR_BADLOGVALUE
+       reply numerics
+
+       * include/msg.h: add defines for SET, RESET, and GET
+
+       * include/ircd_log.h: add a function to canonicalize subsystem
+       names; change some void return values to int
+
+       * include/ircd_features.h: new features subsystem handles all the
+       manipulation of special features, like log files
+
+       * include/handlers.h: declare new mo_{s,res,g}et message handlers
+       for fiddling with features run-time
+
+       * include/client.h (SNO_DEFAULT): don't set SNO_DEBUG by default;
+       seemed like a good idea at the time...
+
+       * doc/example.conf: document new F lines
+
+2000-11-29  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/s_debug.c: rewrite debug_init() and vdebug() in terms of
+       new logging functions, which have special support for the debug
+       log; added loop detection to vdebug(), so that I can
+       sendto_opmask_butone() from log_vwrite() without incurring another
+       call to vdebug()
+
+       * ircd/s_conf.c (rehash): call log_reopen() from rehash routine;
+       this allows log file rotations
+
+       * ircd/m_kill.c: call log_write_kill() instead of ircd_log_kill()
+
+       * ircd/ircd_log.c: much more work fleshing out the interface;
+       removed old interface; included backwards-compat ircd_log()
+       function that logs to subsystem LS_OLDLOG
+
+       * ircd/ircd.c: switch to new log_init()/log_close()/log_reopen()
+       functions
+
+       * include/ircd_log.h: include stdarg.h for va_list; move ordering
+       warning to top of file; fill out LogSys enum; declare new
+       log_debug_init(), log_vwrite(), log_write_kill(), and
+       log_[sg]et_*() functions; add flags argument to log_write();
+       defined flags to inhibit various logging actions
+
+       * include/client.h: added support for new SNO_DEBUG, enabled only
+       if DEBUGMODE is defined
+
+2000-11-28  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/ircd_log.c: make sure the various LOG_* constants are
+       defined (probably not needed, since #include <syslog.h> isn't
+       conditional); various static data needed for the new logging
+       functions; definitions of new logging functions
+
+       * include/ircd_log.h: new LogSys enum, declarations for part of
+       new logging API
+
+       * ircd/motd.c: we were setting type to MOTD_CLASS unconditionally,
+       which was of course stupid; switched to using switch/case in
+       initialization in motd_create(); zero the MotdList.other pointer
+       from motd_clear()
+
+       * ircd/ircd.c (main): motd_init() has to come before init_conf(),
+       or we overwrite init_conf()'s hard work with respect to T-lines
+
+2000-11-27  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/s_stats.c: comment out report_motd_list and include a
+       reference to motd_report()
+
+       * ircd/s_conf.c: rip out the old MOTD manipulation functions; call
+       motd_add() from the conf parser; call motd_clear() from the rehash
+       routine; remove the no longer needed memory clearing and reloading
+       stuff from the rehash service routine
+
+       * ircd/motd.c: loads new API, including static internal functions
+       to do allocation/deallocation, etc.
+
+       * ircd/m_stats.c: use new motd_report() instead of
+       report_motd_list()
+
+       * ircd/m_motd.c: use new syntax for motd_send()
+
+       * ircd/ircd.c: use new motd_init() function
+
+       * ircd/Makefile.in (SRC): forgot to add motd.c to SRC in
+       Makefile.(in); also ran make depend
+
+       * include/motd.h: don't need config.h, but now do need time.h;
+       define new structures and constants; redefine old API and define
+       new functions
+
+2000-11-22  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/s_user.c (register_user): use motd_signon() instead of
+       calling m_motd; much cleaner this way
+
+       * ircd/motd.c: write the new motd_* stuff to make MOTD handling
+       less of a crock
+
+       * ircd/m_motd.c: rewrite m{,s}_motd to call out to new motd_*
+       functions
+
+       * include/motd.h: define new MOTD API stuff
+
+2000-11-20  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/ircd_reply.c (protocol_violation): rewrite
+       protocol_violation so it'll actually work
+
+       oh, yeah, use %s -> cptr->name, instead of %c -> cptr, so we get
+       the client's real name in there.
+
+       * ircd/m_motd.c (m_motd): Iso's addition of get_client_class(sptr)
+       resulted in core dumps if NODEFAULTMOTD is defined, because m_motd
+       gets called from register_user with a NULL sptr.  This is probably
+       a design problem, but this bandaid will do for now...
+
+2000-11-19  Isomer <isomer@coders.net>
+       * ircd/ircd_reply.c: added 'protocol_violation', thus alerting us
+       to problems in the server<->server protocol.
+
+       * ircd/m_connect.c: allow remote connects with a port of '0'
+       meaning to use the port in the config file.
+
+       * ircd/m_create.c: Enable hacking protection, lets see how far we
+       get.
+
+       * ircd/m_error.c: The RFC says never accept ERROR from unreg'd
+       clients, so we don't any more.
+
+       * ircd/m_kill.c: The kill path is now made up of numnicks of servers,
+       and the user@host is displayed of the victim.
+
+       * ircd/m_map.c: reloaded 'dump_map'.
+
+       * ircd/m_trace.c: allow per class T:
+
+       * ircd/m_stats.c: allow local opers /remote stats anywhere on the 'net.
+
+2000-11-17  Isomer <isomer@coders.net>
+
+       * ircd/m_topic.c: Fixed bug where we'd only send to clients topics
+       that were the *same* instead of different.  Oh the embarrasment!
+
+       * ircd/IPcheck.c: Merged net's fix.
+
+2000-11-02  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/m_whois.c: remove compiler warning by adding a newline to
+       end of file
+
+       * ircd/m_names.c: moved the flags up to s_user.h
+
+       * ircd/m_join.c: call do_names instead of m_names; restructure
+       ms_join to never transmute a JOIN into a CREATE, but use the TS in
+       the JOIN (if present) to timestamp the channel
+
+       * ircd/channel.c: send JOINs individually, instead of grouping
+       them, so that we can send the channel's creation time
+
+       * include/s_user.h: declare do_names()
+
+2000-10-30  Isomer <isomer@coders.net>
+       * ircd/m_oper.c: Fixed warning
+
+2000-10-30  Isomer <isomer@coders.net>
+       * ircd/m_oper.c: Fixed over agressive cut and no paste
+
+2000-10-30  Isomer <isomer@coders.net>
+
+       * ircd/m_topic.c: Restructured, fixed bug where topics on local
+       channels are propergated (I forget who pointed this out to me, but
+       thanks anyway).  Also to save bandwidth don't send the topic to
+       users if the topic is already the same on the server (but still
+       propergate to other servers).  X/W's "autotopic" feature must
+       chew a lot of bandwidth, hopefully this will help reduce this.
+
+       * doc/rfc1459.rfc: Updated documentation on /topic.
+
+       * ircd/listener.c: snotice warnings about failed accept()'s
+       potentially warning admins that they're running out of fd's.
+
+       * ircd/stats.c, ircd/class.c: Removed /stats v, added number of
+       people in a class in /stats y
+
+       * ircd/m_create.c: Checks for timewarp hacking and squit's
+       evil servers. (currently disabled)
+       
+
+2000-10-30  net <simms@lucida.qc.ca>
+       
+       * ircd/gline.c: Fixed various bugs Isomer left behind.
+
+2000-10-26  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/m_join.c (m_join): reply on attempt to join a BADCHANed
+       channel is now ERR_BANNEDFROMCHAN instead of ERR_BADCHANNAME
+
+2000-10-24  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/channel.c: ok, now last mode rules; mode +ps will always
+       result in +s (and won't send a mode if the channel is already +s);
+       mode +sp will always result in +p; -n+n on a +n channel results in
+       no mode change; -n+n on a -n channel results in a +n mode change;
+       etc.
+
+2000-10-23  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/channel.c: add "add" and "del" elements to ParseState to
+       avoid not-too-pretty -p+s when +s is sufficient; fix a bug in
+       mode_parse_limit that caused it to clear all channel modes
+       prematurely; restructure mode_parse_mode to avoid calling
+       modebuf_mode too early (ties in with first mentioned change);
+       better logic for +p/+s mutual exclusivity; initialize "add" and
+       "del" elements in mode_parse; send simple modes down to
+       modebuf_mode after the loop in mode_parse
+
+2000-09-28  Greg Sikorski <gte@atomicrevs.demon.co.uk>
+       * ircd/m_names.c: Fixed a non-lethal logic error that 
+       triggers an assert() in find_member_link while debugging.
+       (Spotted by Maniac-).
+2000-09-19  Thomas Helvey <helveytw@home.com>
+       * ircd/s_conf.c: move K:lines to their own list and data
+       structures, add supporting code.
+       * ircd/m_stats.c: cleanup stats processing a bit move
+       kline listing code to a new function, haven't figured
+       out where it goes yet tho'
+       * ircd/s_stats.c: added K:line bulk lister
+       * include/s_conf.h: added new DenyConf struct
+       * *[ch]: fixeup code that depended on changes
+
+2000-09-17  Thomas Helvey <helveytw@home.com>
+       * ircd/class.c: encapsulate class list
+       * include/class.h: clean up classes
+       * * fixup code that depended on changes
+
+2000-09-17  Thomas Helvey <helveytw@home.com>
+       * ircd/s_conf.c: add me to local conf
+       * include/s_conf.h: move CONF_ME macro to chkconf.c
+       * ircd/s_bsd.c: cleanup initialization, allow virtual host
+       to be changed by rehash
+
+2000-09-17  Thomas Helvey <helveytw@home.com>
+       * include/class.h: add missing prototype
+       * ircd/class.c: make argument to get_conf_class const
+
+2000-09-17  Thomas Helvey <helveytw@home.com>
+       * ircd/*.c: merged in changes from 2.10.10.pl12, cleanup
+       merge conflicts.
+       * ircd/*.h: merged in changes from 2.10.10.pl12, cleanup
+       merge conflicts
+
+2000-09-16  Thomas Helvey <helveytw@home.com>
+       * ircd/s_conf.c: add code for server struct
+       * ircd/client.c: copy of class.c sort of, new file for client
+       specific operations, will move things here as appropriate,
+       currently only one function is exported from here.
+       * ircd/*.c: general logic cleanups, convert negatives to
+       positives in places.
+
+2000-09-16  Thomas Helvey <helveytw@home.com>
+       * ircd/s_conf.c: add code for new crule data structs, strip quotes
+       * ircd/crule.c: clean up scary casting a bit, type safety stuff
+       * include/s_conf.h: add CRuleConf struct and support, remove
+       unused constants
+       * include/crule.h: type safety cleanups
+       * ircd/*.c: fixup code that depended on stuff I changed
+
+2000-09-15  Thomas Helvey <helveytw@home.com>
+       * ircd/s_conf.c: start adding code for new conf data structs, changed
+       listeners, admin line, motd lines, class lines. Move validate_hostent
+       to resolver. General mayhem.
+       * include/s_conf.h: new data structs and accessors
+       * ircd/res.c: move validate_hostent here, rewrite, use regular
+       expression for validation.
+       * doc/example.conf: update docs for port
+
+2000-09-14  Thomas Helvey <helveytw@home.com>
+       * ircd/s_conf.c (conf_init): rewrite conf file parser, start to break
+       up conf_init into managable chunks.
+       * ircd/listener.c (set_listener_mask): fix logic bug core dump.
+       * include/s_conf.h: add new data struct for local info (unwinding the mess).
+
+2000-09-13  Thomas Helvey <helveytw@home.com>
+       * ircd/list.c: put Clients in free lists, pre-allocate MAXCONNECTIONS
+       local clients.
+       * ircd/list.c: put SLinks in free lists
+       * ircd/channel.c: put Memberships in free lists
+       * ircd/ircd.c: rearrange initializations a bit in main
+       Note: With these changes, ircd NEVER frees Clients, SLinks or
+       Memberships. It will also rarely need to allocate new
+       ones during net bursts and other disruptions. This should
+       cut down on memory fragmentation a bit as well.
+
+2000-08-30  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/m_names.c (do_names): pull-up from do_names fix in
+       u2.10.10.pl11
+
+2000-07-15  Perry Lorier       <Isomer@coders.net>
+       * various: IP only k:'s and G:'s now do bit tests instead of two(!) 
+                 match()'s.  Major Major cpu savings.  Also speed up the
+                 other case slightly.  As a side effect you can now
+                k/Gline *@10.0.0.0/8.  I'll do bans tomorrow, it's nearing
+                3am.
+
+2000-07-15  Perry Lorier       <Isomer@coders.net>
+       * various: Fixed warnings after compiling on an alpha.
+2000-07-09  Perry Lorier       <Isomer@coders.net>
+       * doc/ircd.8: Applied grammitical changes by Liandrin, applied
+                     changes suggested by various other people.
+       * ircd/IPcheck.c: More bug fixes.  Current problem appears to be
+                       that it gets a corrupt entry somehow.
+2000-07-09  Greg Sikorski <gte@atomicrevs.demon.co.uk>
+       * ircd/m_oper.c: Clean up compiler warning.
+
+2000-07-08  Perry Lorier       <Isomer@coders.net>
+       * doc/ircd.8: Updated the documentation, it was slightly out of date
+                     being updated around 1989.
+       * ircd/m_whois.c: Rewrote for clarity, and probably a bit more speed.
+                         fixed a few minor glitches.
+       * doc/rfc1459.unet: Updated.
+       * ircd/IPcheck.c: Fixed more bugs.
+       * ircd/s_bsd.c: We now keep track of servers we've conected.
+
+2000-07-02  Perry Lorier       <Isomer@coders.net>
+       * ircd/s_misc.c: Fixed remote IPcheck bug.  Ok, I'm a moron, so sue
+                       me.  Thanks to Hektik, thanks thanks thanks thanks
+                       thanks thanks thanks thanks thank thanks thank thanks
+
+2000-07-01  Perry Lorier       <Isomer@coders.net>
+       * ircd/s_conf.c: "Fixed" the "bug" where people would "evade" K:'s.
+       * ircd/s_conf.c, include/IPcheck.h: Fixed compile warnings.
+
+2000-06-22  Perry Lorier       <Isomer@coders.net>
+       * ircd/IPcheck.c: Large chunks redone.
+       * ircd/s_conf.c: Changes due to IPcheck - ONE nolonger supported,
+                       single AND double digit limits are allowed now.
+       * misc other: Changes to IPcheck.
+
+2000-06-30  Perry Lorier       <Isomer@coders.net>
+       * ircd/ircd.c: Fix command line parameter bugs.
+
+2000-06-30  Perry Lorier       <Isomer@coders.net>
+       * ircd/m_kill.c: Fixed bug with LOCAL_KILL_ONLY
+       * ircd/m_nick.c: Tidied things up.
+
+2000-06-12 Joseph Bongaarts <foxxe@trms.com>
+       * ircd/m_stats.c: Iso forgot mo_stats when he added /stats v
+       
+2000-05-29  Perry Lorier       <Isomer@coders.net>
+       * ircd/m_stats.c: add /stats v to do only the last part of the /trace
+       * ircd/IPcheck.c: Cosmetic change, if we meddle with it enough do
+                       you think it'll get bored and fix itself?
+
+2000-06-09  Greg Sikorski <gte@atomicrevs.demon.co.uk>
+
+       * ircd/m_names.c: Clean up compiler warnings.
+
+2000-06-09  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/channel.c (mode_parse_client): don't send warning if
+       there's not enough arguments for a +/-o/v; means the habit of
+       doing "/mode #channel +oooooo bob" doesn't result in a bunch of
+       error messages
+
+2000-06-04  Greg Sikorski <gte@atomicrevs.demon.co.uk>
+
+       * ircd/m_names.c: Re-factor code to remove unneccessary
+       GlobalChannelList iteration every time someone joins a channel.
+
+2000-06-02  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/s_user.c: add struct Gline * argument to register_user;
+       look up global glines and repropagate them if necessary; send
+       acknowledgement of gline to remote servers when registering users
+
+       * ircd/s_serv.c (server_estab): don't send acknowledgement of
+       local glines to remote servers; do send gline acknowledgement of
+       bursted users
+
+       * ircd/m_user.c (m_user): pass new struct Gline * argument to
+       register_user
+
+       * ircd/m_pong.c: pass new struct Gline * argument to register_user
+
+       * ircd/m_nick.c (ms_nick): document protocol change
+
+       * ircd/gline.c: support GLINE_LASTMOD
+
+       * include/s_user.h: add struct Gline * argument to register_user
+
+       * include/gline.h: add GLINE_LASTMOD to look up non-zero lastmods
+
+       * ircd/s_conf.c (find_kill): add unsigned int argument to
+       gline_lookup()
+
+       * ircd/gline.c: add GLINE_GLOBAL to lookup or find only global
+       glines; add unsigned int argument to gline_lookup()
+
+       * include/gline.h: add GLINE_GLOBAL flag; add unsigned int
+       argument to gline_lookup()
+
+       * ircd/m_server.c: Resend jupe only when there is no %<lastmod>
+       parameter, or when it falls out of bounds: see comments prior to
+       call to jupe_resend(); call server_estab with struct Jupe
+       parameter, so that we place the appropriate %<lastmod> in the
+       appropriate place.
+
+       * ircd/s_serv.c (server_estab): send %<lastmod> for introduced
+       server, as well as for servers when we're sending the BURST
+
+       * include/s_serv.h: add a struct Jupe * to the arguments for
+       server_estab() so that we can send the appropriate lastmod
+       parameter
+
+       * ircd/m_gline.c (ms_gline): actually, this should be the
+       slightest bit more efficient...
+
+       * ircd/m_jupe.c (ms_jupe): actually, this should be the slightest
+       bit more efficient...
+
+       * ircd/m_gline.c (ms_gline): inhibit GLINE processing resends
+       during netburst
+
+       * ircd/m_jupe.c (ms_jupe): inhibit JUPE processing resends during
+       netburst
+
+       * ircd/channel.c (joinbuf_join): really remove user from local
+       channels
+
+2000-05-29  Perry Lorier       <Isomer@coders.net>
+       * ircd/m_names.c: Removed redundant space. 
+       * ircd/s_bsd.c: Fixed incorrect syntax on ERROR line.
+
+2000-05-18  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/m_burst.c (ms_burst): er...that should have been a ",", not
+       a " "
+
+2000-05-04  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/channel.c: replace bogus assertions with returns, which is
+       logically correct; only wipe out limit/key if they were originally
+       set in the first place; remove user from channel when doing a
+       PARTALL; only send MODE +o for user CREATEing channel if user is
+       not MyUser--CREATE will only be used if the channel did not
+       originally exist, therefore we can assume no one local is on the
+       channel anyway, and we don't exactly need for the user to see an
+       explicit +o for themselves
+
+       * doc/readme.gline: describe the syntax of the GLINE command
+
+       * doc/readme.jupe: update to reflect a couple of changes to JUPE
+
+       * ircd/gline.c: don't propagate local changes
+
+       * ircd/jupe.c: don't propagate local changes
+
+       * ircd/m_gline.c (mo_gline): force local flag when deactivating
+       glines with 0 lastmod
+
+       * ircd/gline.c (gline_deactivate): G-lines with zero lastmod time
+       are now removed instead of being deactivated
+
+       * ircd/m_gline.c (ms_gline): make G-lines of the form "GLINE *
+       -<mask>" be accepted
+
+       * ircd/channel.c (send_channel_modes): deal with one of the last
+       vestiges of sendbuf
+
+       * ircd/m_burst.c (ms_burst): debugged ban processing; removed
+       debugging hooks
+
+       * ircd/channel.c (modebuf_extract): remove debugging
+       sendto_opmask_butone calls
+
+2000-05-03  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/channel.c: support a couple of new flags to support using
+       mode_parse; fix some bugs with 0 struct ModeBuf *; implementation
+       of modebuf_extract to extract added flags for use by ms_burst
+
+       * include/channel.h: a couple of new flags to support using
+       mode_parse inside ms_burst
+
+       * ircd/m_burst.c (ms_burst): brand new implementation of BURST
+
+       * ircd/m_endburst.c: add loop to processing of end_of_burst to
+       free empty channels after the BURST is over.
+
+       * ircd/m_server.c: convert to use new send.c functions--I wanted
+       to rewrite it from scratch, but the logic's pretty complex; I may
+       still rewrite it, though...
+
+2000-05-02  Thomas Helvey <tomh@inxpress.net>
+
+       * ircd/ircd.c: fix broken header include ordering
+
+2000-05-02  Thomas Helvey <tomh@inxpress.net>
+       
+       * ircd/IPcheck.c: cleanups for ZenShadow's cleanups
+        review emailed privately
+
+       * include/IPcheck.h: removed unneeded include
+
+2000-05-02  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/s_user.c (hunt_server): throw in a comment so I know what
+       the sendto_one is for
+
+       * include/querycmds.h (Count_unknownbecomesclient): convert to
+       sendto_opmask_butone
+
+       * ircd/send.c: start removing dead code
+
+       * include/send.h: start removing dead code
+
+       * ircd/m_rping.c: convert to sendcmdto_one / send_reply /
+       hunt_server_cmd
+
+       * ircd/m_rpong.c: convert to sendcmdto_one / send_reply
+
+2000-05-01  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/m_stats.c: convert to sendcmdto_one / send_reply
+
+       * ircd/m_kick.c: Completely reimplement m_kick
+
+       * ircd/channel.c: send_user_joins removed; it was dead code,
+       anyway...
+
+2000-05-01  Perry Lorier <isomer@coders.net>
+       * ircd/m_invite.c: Fix for the rest of m_invite.c, and again.
+       * ircd/channels.c: My fix for the part problem.  Untested, probably
+               won't work.  Can't be much worse than the current problem.
+               it'll either work or core, take your pick.
+
+
+2000-04-30  Perry Lorier <isomer@coders.net>
+       * config/config-sh.in: Fix for CONNEXIT
+       * ircd/s_{user,misc}.c: Fix for CONNEXIT
+       * ircd/m_invite.c: Fix for incorrectly numnickified invite.
+                       (Kev: Want to come talk to me about this?)
+
+2000-04-30  Steven M. Doyle <steven@doyle.net>
+       * ircd/ircd.c
+         - general cleanups and readability enhancements
+         - rewrite of setuid/chroot code.
+         - server will no longer run as root
+         - -DPROFIL compile option removed
+         - Fixed IPcheck API calls
+       * config/config-sh.in
+         - Fixed up chroot compile options
+         - Added options for debug and profile compiles
+       * config/gen.ircd.Makefile
+         - Support for new debug/profile options
+       * ircd/Makefile.in
+         - Support for new debug/profile options
+       * ircd/ircd_signal.c
+         - Removed -DPROFIL
+
+       * include/IPcheck.h
+         - Removed old API prototypes, added new ones
+       
+       * ircd/IPcheck.c
+         - Readability cleanups (well, I -think-...)
+         - Changed IPRegistryEntry.last_connect to a time_t.  The previously
+           used unsigned short was probably causing interesting things after
+           a client had been connected longer than about 65,535 seconds...
+         - Removed old API functions.
+
+       * ircd/whocmds.c
+         - Removed IPcheck.h include
+       
+       * Additionally modified IPcheck API calls in:
+         - ircd/m_nick.c
+         - ircd/m_auth.c
+         - ircd/s_bsd.c
+         - ircd/s_conf.c
+         - ircd/s_misc.c
+         - ircd/s_serv.c
+         - ircd/s_user.c
+       
+       
+2000-04-30  Perry Lorier <isomer@coders.net>
+       * ircd/s_bsd.c: Sigh. :)
+        * ircd/m_mode.c: fix for modeless channels by poptix.
+
+2000-04-29  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/m_join.c: reimplement JOIN in terms of struct JoinBuf
+
+       * ircd/channel.c (clean_channelname): make clean_channelname also
+       truncate long channel names
+
+2000-04-28  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/m_create.c: reimplement CREATE in terms of struct JoinBuf
+
+       * ircd/channel.c: implemented joinbuf_init, joinbuf_join,
+       joinbuf_flush
+
+       * include/channel.h: definitions and declarations for the struct
+       JoinBuf abstraction
+
+2000-04-29  Perry Lorier <isomer@coders.net>
+       * ircd/s_bsd.c: Ok, so I thought I compiled and tested this...
+
+2000-04-29  Perry Lorier <isomer@coders.net>
+       * ircd/s_bsd.c: Add debugging code to IPcheck
+
+2000-04-28  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * include/ircd_reply.h (SND_EXPLICIT): use instead of RPL_EXPLICIT
+
+       * ircd/ircd_reply.c (send_reply): use SND_EXPLICIT instead of
+       RPL_EXPLICIT
+
+       * ircd/m_userhost.c (m_userhost): add a dead code comment
+
+       * ircd/m_desynch.c: forgot one...
+
+       * ircd/m_rehash.c (mo_rehash): er, duplicates :)
+
+       * ircd/m_proto.c (proto_send_supported): just change a comment so
+       it doesn't show up in my scans
+
+       * ircd/ircd_reply.c (send_reply): fix a slight bug...
+
+       * ircd/s_numeric.c (do_numeric): use new sendcmdto_* functions,
+       kinda hackish...
+
+       * ircd/parse.c (parse_server): argument wrangling to make
+       processing in do_numeric a little easier to deal with
+
+       * ircd/s_serv.c (server_estab): SERVER should come from
+       acptr->serv->up, not &me
+
+       * ircd/m_lusers.c: accidentally left out sptr for a %C
+
+       * ircd/send.c: hack to support doing wallchops...
+
+       * ircd/m_whowas.c: convert to new send functions
+
+       * ircd/m_whois.c: convert to new send functions
+
+       * ircd/m_who.c: convert to new send functions
+
+       * ircd/m_wallops.c: convert to new send functions
+
+       * ircd/m_wallchops.c: convert to new send functions
+
+       * ircd/m_version.c: convert to new send functions
+
+       * ircd/m_userip.c: convert to new send functions
+
+       * ircd/m_userhost.c: convert to new send functions
+
+       * ircd/m_uping.c: convert to new send functions
+
+       * ircd/m_trace.c: convert to new send functions
+
+       * ircd/m_topic.c: convert to new send functions
+
+       * ircd/m_time.c: convert to new send functions
+
+       * ircd/m_squit.c: convert to new send functions
+
+       * ircd/m_silence.c: convert to new send functions
+
+       * ircd/m_settime.c: convert to new send functions
+
+       * ircd/m_restart.c: convert to new send functions
+
+       * ircd/m_rehash.c: convert to new send functions
+
+       * ircd/m_privmsg.c: convert to new send functions
+
+       * ircd/m_pong.c: convert to new send functions
+
+       * ircd/m_ping.c: convert to new send functions
+
+       * ircd/m_pass.c: convert to new send functions
+
+       * ircd/m_opmode.c: convert to new send functions
+
+       * ircd/m_oper.c: convert to new send functions
+
+       * ircd/m_notice.c: convert to new send functions
+
+       * ircd/m_nick.c: convert to new send functions
+
+       * ircd/m_names.c: convert to new send functions
+
+       * ircd/m_motd.c: convert to new send functions
+
+       * ircd/m_mode.c: convert to new send functions
+
+       * ircd/m_map.c: convert to new send functions
+
+       * ircd/m_lusers.c: convert to new send functions
+
+       * ircd/m_list.c: convert to new send functions
+
+       * ircd/m_links.c: convert to new send functions
+
+       * ircd/m_kill.c: convert to new send functions
+
+       * ircd/m_jupe.c: convert to new send functions
+
+       * ircd/m_invite.c: convert to new send functions
+
+       * ircd/m_info.c: convert to new send functions
+
+       * ircd/m_help.c: convert to new send functions
+
+       * ircd/m_gline.c: convert to new send functions
+
+       * ircd/m_error.c: convert to new send functions
+
+       * ircd/m_endburst.c: convert to new send functions
+
+       * ircd/m_die.c: convert to new send functions
+
+       * ircd/m_destruct.c: convert to new send functions
+
+       * ircd/m_defaults.c: convert to new send functions
+
+       * ircd/m_connect.c: convert to new send functions
+
+2000-04-28  Perry Lorier <isomer@coders.net>
+       * RELEASE.NOTES: Describe a few more undocumented features.
+       * config/config-sh.in: change the default paths for logging
+       and the recommended number of channels.
+       * include/supported.h: Rearrange slightly, added CHANTYPE's
+
+2000-04-27  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/m_close.c: convert to send_reply
+
+       * ircd/m_clearmode.c: convert to send_reply, sendcmdto_serv_butone
+
+       * ircd/m_away.c: convert to send_reply and sendcmdto_serv_butone
+
+       * ircd/m_admin.c: convert to send_reply and hunt_server_cmd
+
+       * ircd/s_user.c (hunt_server_cmd): new hunt_server replacement
+       that takes cmd and tok arguments, etc.  NOTE: THIS IMPLEMENTATION
+       HAS A MAJOR HACK!!!  The whole hunt_server architecture should be
+       carefully rethought...
+
+       * ircd/s_stats.c (hunt_stats): use new hunt_server_cmd
+
+       * include/s_user.h: hunt_server_cmd -- replacement for hunt_server
+
+       * ircd/s_misc.c: *sigh* 2.10.10 doesn't support squitting by
+       numeric nick; therefore, we have to use the server name
+
+       * ircd/m_squit.c (ms_squit): allow to squit by server numeric nick
+
+       * ircd/send.c: fix minor bugs
+
+       * ircd/s_user.c (check_target_limit): mark dead code so I filter
+       it when I grep
+
+       * ircd/s_serv.c (exit_new_server): mark dead code so I filter it
+       when I grep
+
+       * ircd/parse.c: mark dead code so I filter it when I grep
+
+       * ircd/map.c: mark dead code so I filter it when I grep
+
+       * ircd/ircd.c: mark dead code so I filter it when I grep
+
+       * ircd/ircd_relay.c: convert over to new sendcmdto_*, send_reply
+       functions
+
+       * ircd/channel.c: mark dead code so I filter it when I grep
+
+       * ircd/s_stats.c: use send_reply instead of sendto_one w/rpl_str;
+       hope I'm not stepping on toes...
+
+       * ircd/s_conf.c: more sendto_opmask_butone / send_reply
+       conversions; use ircd_snprintf in a couple of cases to negate the
+       possibility of buffer overflow
+
+2000-04-26  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/channel.c: convert as much as possible to new send
+       semantics
+
+       * ircd/send.c (sendcmdto_common_channels): fix a subtle bug --
+       test member->user->from->fd, not from->fd
+
+       * ircd/gline.c (gline_add): go ahead and add badchans; we just
+       won't look for them in m_gline; this way, they always work...
+
+       * ircd/jupe.c: use ircd_vsnprintf conversion specifiers
+
+       * ircd/gline.c: since write_log now uses ircd_vsnprintf, use
+       ircd_vsnprintf conversion specifiers
+
+       * ircd/support.c (write_log): use ircd_vsnprintf for write_log, so
+       I have my conversion specifiers
+
+       * ircd/gline.c (do_gline): use send_reply for ERR_YOUREBANNEDCREEP
+
+       * ircd/send.c (sendcmdto_flag_butone): explicitly send WALLOPS to
+       local users
+
+       * ircd/s_serv.c (exit_new_server): rewrite exit_new_server to be a
+       little less brain-dead
+
+       * ircd/s_misc.c: use sendcmdto_one, sendrawto_one, and send_reply
+
+       * ircd/s_debug.c: use send_reply with RPL_EXPLICIT for
+       RPL_STATSDEBUG
+
+       * ircd/res.c (cres_mem): use send_reply with RPL_EXPLICIT for
+       RPL_STATSDEBUG
+
+       * ircd/list.c (send_listinfo): use send_reply with RPL_EXPLICIT
+       for RPL_STATSDEBUG
+
+       * ircd/m_pong.c: use RPL_EXPLICIT for ERR_BADPING
+
+       * ircd/ircd.c: use RPL_EXPLICIT for ERR_BADPING
+
+       * ircd/s_user.c (register_user): use RPL_EXPLICIT for
+       ERR_INVALIDUSERNAME
+
+       * ircd/ircd_reply.c (send_reply): support RPL_EXPLICIT
+
+       * include/ircd_reply.h (RPL_EXPLICIT): somewhat of a hack to mark
+       a numeric as needing to use an explicit pattern, which will be the
+       first argument in the variable argument list
+
+       * ircd/s_user.c: use sendrawto_one instead of sendto_one to send
+       non-prefixed nospoof PING
+
+       * ircd/s_bsd.c: use sendrawto_one instead of sendto_one to send
+       non-prefixed SERVER login
+
+       * ircd/ircd.c (check_pings): fix last sendto_one calls (except for
+       a numeric usage further up)
+
+       * include/send.h: declare sendrawto_one
+
+       * ircd/send.c (sendrawto_one): new function to use ONLY for
+       non-prefixed commands, like PING to client, or PASS/SERVER on
+       server registration
+
+2000-04-25  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/ircd_snprintf.c (doprintf): implement %H for possible
+       future expansion (channel numerics?)
+
+       * include/ircd_snprintf.h: added documentation to # to explain use
+       with %C; added documentation for : to explain use with %C; added
+       documentation for %H for channels
+
+       * ircd/whocmds.c: use send_reply
+
+       * ircd/userload.c: use sendcmdto_one
+
+       * ircd/uping.c: use sendcmdto_one
+
+       * ircd/send.c: use new flags to %C format string; ':' prefixes
+       client name with a colon for local connects, '#' uses
+       nick!user@host form for local connects
+
+       * ircd/s_user.c: use send_reply, sendto_opmask_butone,
+       sendcmdto_one, sendcmdto_serv_butone, sendcmdto_flag_butone
+
+       * ircd/s_serv.c: use sendcmdto_one, sendto_opmask_butone
+
+       * ircd/s_bsd.c: use sendto_opmask_butone, send_reply,
+       sendcmdto_one
+
+       * ircd/s_auth.c: use sendto_opmask_butone
+
+       * ircd/res.c: use sendcmdto_one
+
+       * ircd/ircd_snprintf.c (doprintf): minor bug fixes and some
+       debugging assertions
+
+2000-04-24  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/support.c: dumpcore is no longer used, so get rid of it
+
+       * ircd/parse.c: use send_reply, sendcmdto_one
+
+       * ircd/map.c: use send_reply
+
+       * ircd/listener.c: use send_reply
+
+       * ircd/jupe.c: use sendto_opmask_butone, send_reply
+
+       * ircd/ircd_reply.c: use send_reply
+
+       * ircd/ircd.c: use sendto_opmask_butone
+
+       * ircd/gline.c: use sendto_opmask_butone, send_reply
+
+       * ircd/ircd_snprintf.c (doprintf): make it deal with incompletely
+       registered clients; make FLAG_ALT print nick!user@host; make
+       FLAG_COLON print :blah
+
+       * ircd/class.c (report_classes): use send_reply instead of
+       sendto_one
+
+       * ircd/hash.c (m_hash): replace sendto_one with sendcmdto_one
+
+       * ircd/IPcheck.c (ip_registry_connect_succeeded): replace
+       sendto_one with sendcmdto_one
+
+2000-04-21  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/send.c: clean up logic in sendcmdto_channel_butone; use
+       MyConnect() instead of IsServer() in sendcmdto_flag_butone; define
+       sendcmdto_match_butone
+
+       * include/send.h: declare sendcmdto_match_butone
+
+2000-04-20  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/jupe.c: update to use send_reply()
+
+       * ircd/gline.c: update to use send_reply()
+
+       * include/ircd_reply.h: declare send_reply
+
+       * ircd/ircd_reply.c (send_reply): send_error_to_client, but for
+       replies; uses ircd_snprintf
+
+       * ircd/send.c: added comments to redirect searchers to appropriate
+       sendcmdto_* function; moved new functions to end of file; added
+       explanatory comments; reordered arguments; defined new functions
+       mentioned below
+
+       * ircd/m_jupe.c: reorder arguments to sendcmdto_* functions
+
+       * ircd/m_gline.c: reorder arguments to sendcmdto_* functions
+
+       * ircd/jupe.c: reorder arguments to sendcmdto_* functions
+
+       * ircd/gline.c: reorder arguments to sendcmdto_* functions
+
+       * include/send.h: reorder arguments, add explanatory comments,
+       declare new functions sendcmdto_flag_butone, sendto_opmask_butone,
+       and vsendto_opmask_butone
+
+2000-04-19  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/send.c: define sendcmdto_channel_butone, wrote a simplified
+       vsendto_op_mask that uses '*' instead of the receiving client
+       nickname
+
+       * include/send.h: declare sendcmdto_channel_butone; takes a skip
+       argument that allows you to skip (or not to skip) deaf users,
+       users behind bursting servers, and non channel operators
+
+2000-04-17  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/send.c: new sendcmdto_channel_butserv -- note that old
+       sendto_channel_butserv has a subtle bug; also wrote
+       sendcmdto_common_channels.
+
+       * include/send.h: declare new sendcmdto_* functions
+
+       * ircd/jupe.c: support local deactivations of jupes
+
+       * ircd/gline.c: support local deactivations of glines
+
+       * include/jupe.h: JUPE_LDEACT allows jupes to be locally
+       deactivated; if they aren't locally deactivated, then it slaves to
+       the net-wide activation status; JupeIsRemActive() tests only
+       whether the jupe is active everywhere else
+
+       * include/gline.h: GLINE_LDEACT allows glines to be locally
+       deactivated; if they aren't locally deactivated, then it slaves to
+       the net-wide activation status; GlineIsRemActive() tests only
+       whether the gline is active everywhere else
+
+       * ircd/gline.c: detect overlapping G-lines; if an existing, wider
+       gline expires after the new one will, we drop the new one,
+       otherwise we add the G-line after that one (so the wide one will
+       apply first); if the new one contains an existing G-line and if it
+       will expire after the existing one, we drop the existing one to
+       save memory
+
+       * ircd/m_gline.c (mo_gline): opers could issue remote local
+       glines when CONFIG_OPERCMDS was off; fixed
+
+2000-04-16  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/m_jupe.c (mo_jupe): allow target argument to be dropped if
+       this is a local JUPE
+
+       * ircd/gline.c: add flags argument to gline_activate and
+       gline_deactivate for future expansion
+
+       * ircd/m_gline.c: pass flags to gline_activate and
+       gline_deactivate
+
+       * include/gline.h: add flags argument to gline_activate and
+       gline_deactivate
+
+       * ircd/jupe.c: add flags argument to jupe_activate and
+       jupe_deactivate for future expansion
+
+       * include/jupe.h: add flags argument to jupe_activate and
+       jupe_deactivate
+
+       * ircd/m_jupe.c: pass a flags argument to jupe_add instead of
+       local, active; pass flags to jupe_activate and jupe_deactivate
+
+       * include/gline.h: remove dead code
+
+       * ircd/gline.c: make gline expire times relative to CurrentTime,
+       since that should be monotonically increasing, instead of
+       TStime(), which can be set backwards, and which can therefore
+       cause an expire time to increase; make local glines be removed
+       instead of just deactivated; don't let gline_find() look for
+       user@host glines if the mask being looked up is a channel mask
+
+       * ircd/send.c (vsendcmdto_one): forgot to account for the case
+       where origin is a server and destination is a user
+
+       * ircd/jupe.c: make jupe expire times relative to CurrentTime,
+       since that should be monotonically increasing, instead of
+       TStime(), which can be set backwards, and which can therefore
+       cause an expire time to increase; make local jupes be removed
+       instead of just deactivated
+
+       * ircd/ircd_snprintf.c: d'oh, thanks for catching that; short for
+       limit is fine.  any other warnings I should know about?
+
+2000-04-15  Thomas Helvey <tomh@inxpress.net>
+
+       * ircd/*.c: const correctness and type safety cleanups to
+       get code to compile with C++ compiler. Still has
+       signed/unsigned comparison warnings.
+
+2000-04-15  Greg Sikorski <gte@atomicrevs.demon.co.uk>
+
+       * ircd/userload.c: change <sys/time.h> include to <time.h> for
+         portability.
+
+2000-04-14  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/m_gline.c (mo_gline): d'oh, target isn't a numeric; use %C
+       and convert acptr...
+
+       * ircd/s_user.c: move gline_lookup function call into
+       register_user, where it'll have a username to lookup!
+
+       * ircd/m_gline.c: modify to utilize new sendcmdto_* series of
+       functions; also stuff send_error_to_client into return clauses
+
+       * ircd/m_jupe.c: modify to utilize new sendcmdto_* series of
+       functions; also use send_error_to_client where that makes sense
+
+       * ircd/jupe.c: modify to utilize new sendcmdto_* series of
+       functions; also use send_error_to_client where that makes sense
+
+       * ircd/gline.c: modify to utilize new sendcmdto_* series of
+       functions; also fix gline_lookup() to deal properly with remote
+       clients--boy, do struct Client and struct User need to be cleaned
+       up!
+
+       * ircd/ircd_snprintf.c (doprintf): a dest of &me is a server,
+       too...
+
+       * ircd/send.c: wrote sendcmdto_one(), vsendcmdto_one(), and
+       sendcmdto_serv_butone(), all utilizing the %v conversion of
+       ircd_snprintf()
+
+       * include/send.h: define IRC_BUFSIZE, max size of a message;
+       declare sendcmdto_one(), vsendcmdto_one(), and
+       sendcmdto_serv_butone()
+
+       * include/msg.h: define all the CMD_* constants needed to utilize
+       the new sendcmdto_* series of functions
+
+       * ircd/Makefile.in (SRC): list ircd_snprintf.c; run make depend
+
+       * ircd/gline.c: remove old, dead code.
+
+       * ircd/m_gline.c (mo_gline): disallow setting of global G-lines
+       unless CONFIG_OPERCMDS is enabled; disallow listing of all G-lines
+       (don't advertise proxies); remove dead code
+
+       * ircd/parse.c: oper handler for JUPE only lists jupes unless
+       CONFIG_OPERCMDS is enabled
+
+       * ircd/m_jupe.c (mo_jupe): don't compile mo_jupe() if
+       CONFIG_OPERCMDS is not enabled; we'll disable it in parse.c
+
+       * ircd/m_opmode.c (mo_opmode): if CONFIG_OPERCMDS is not enabled,
+       always return ERR_DISABLED
+
+       * ircd/m_clearmode.c (mo_clearmode): if CONFIG_OPERCMDS is not
+       enabled, always return ERR_DISABLED
+
+       * ircd/s_err.c: add error message to indicate disabled commands
+
+       * include/numeric.h (ERR_DISABLED): to indicate disabled commands
+
+       * doc/Configure.help: add documentation for CONFIG_OPERCMDS
+
+       * config/config-sh.in: add CONFIG_OPERCMDS, default both it and
+       CONFIG_NEW_MODE to 'y' for now
+
+       * ircd/gline.c (gline_list): fix a minor formatting bogon
+
+       * BUGS: since I fixed that bug, might as well mark it fixed.
+
+       * ircd/m_join.c: look up badchans with GLINE_EXACT
+
+       * ircd/m_gline.c: fix parc count problems; look up existing
+       G-lines with GLINE_EXACT; only set new lastmod when
+       activating/deactivating existing glines if old lastmod was not 0
+
+       * ircd/gline.c: forgot to copy the gline reason over; don't
+       propagate a gline with 0 lastmod if origin is user; add
+       GLINE_EXACT to force exact matching of gline mask
+
+       * ircd/ircd_snprintf.c (doprintf): forgot to deal with the zero
+       flag properly
+
+       * ircd/s_conf.c (find_kill): gline_find() takes a char *userhost,
+       but gline_lookup() actually takes a client--d'oh.
+
+2000-04-13  Thomas Helvey <tomh@inxpress.net>
+       * ircd/IPcheck.c: Back port BLMet's bugfix from 2.10.10
+
+2000-04-13  Greg Sikorski <gte@atomicrevs.demon.co.uk>
+
+       * ircd/whocmds.c: Don't make idle flag default in /who, to prevent:
+         "/who * x"
+         "Gte3 H*iwg Gte@212.49.240.217 :1 :0 I am the one that was."
+         (Found by Plexus).
+
+       * ircd/whocmds.c: Change idle time calc from socket idle to user
+         idle.
+
+2000-04-13  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * config/aclocal.m4 (unet_CHECK_TYPE_SIZES): check size of void *,
+       too, for ircd_snprintf.c
+
+       * include/ircd_snprintf.h: documentation for ircd_(v)snprintf, in
+       comments; mostly descended from the Linux manpage for printf, but
+       also documenting the extensions.
+
+       * ircd/ircd_snprintf.c: NULL dest is equivalent to going to a
+       client; make 'q' be the same as 'L'; remove __inline__; only
+       define EXTENSION if HAVE_LONG_LONG is defined
+
+       * include/handlers.h: declare m_gline()
+
+       * ircd/parse.c: gline can be called by users, but it only lists
+       the glines.
+
+       * ircd/s_user.c (set_nick_name): resend gline if a remote server
+       introduces a glined client
+
+       * ircd/s_serv.c (server_estab): burst glines, too
+
+       * ircd/gline.c: fix up all the expire times to be offsets;
+       simplify gline_resend()
+
+       * ircd/m_gline.c: begin coding replacements for ms_gline(),
+       mo_gline(), and m_gline()
+
+       * ircd/gline.c (gline_add): allow *@#channel to work correctly;
+       also, prohibit local BADCHANs if LOCAL_BADCHAN not defined
+
+2000-04-13  Greg Sikorski <gte@atomicrevs.demon.co.uk>
+
+       * tools/Bouncer/*: Add comments/documentation/tags.
+       * tools/Bouncer/*: Add debug defines, make task fork().
+
+2000-04-12  Thomas Helvey <tomh@inxpress.net>
+       * ircd/s_err.c: Cleanup s_err.c make one table so we
+       don't have to do anything tricky to get an error string.
+
+2000-04-12  Greg Sikorski <gte@atomicrevs.demon.co.uk>
+       * Add port bouncer for http (x/w)
+
+2000-04-12  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/s_conf.c (find_kill): replaced call to find_gline() with a
+       call to gline_find(); also used GlineReason() instead of direct
+       reference to structure member
+
+       * ircd/m_join.c (m_join): replace bad_channel() calls with calls
+       to gline_find(name, GLINE_BADCHAN), and also check to see if gline
+       is active
+
+       * ircd/channel.c: nothing seems to be called anywhere...
+
+       * ircd/s_err.c: update a couple of replies to dovetail with new
+       semantics
+
+       * ircd/gline.c: begin complete re-implementation of gline.c along
+       the lines of the final design of jupe.c
+
+       * include/gline.h: begin complete re-implementation of gline.c
+       along the lines of the final design of jupe.c
+
+       * ircd/channel.c (mode_process_clients): fix "Deop of +k user on
+       %s by %s" message...
+
+       * ircd/ircd_snprintf.c: my new snprintf()-like functions
+
+       * include/ircd_snprintf.h: my new snprintf()-like functions
+
+2000-04-11  Thomas Helvey <tomh@inxpress.net>
+       * ircd/IPcheck.c: removed old dead code
+       * ircd/s_user.c (send_user_info): removed non-standard
+          user not found message for userhost/userip
+
+2000-04-11  Greg Sikorski <gte@atomicrevs.demon.co.uk>
+
+       * ircd/s_err.c: Added missing quotes to ERR_DONTCHEAT numeric.
+       * doc/p10.html: Work on chapter 4.
+
+2000-04-10  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/channel.c (mode_parse_client): fix coredump on /mode
+       #foobar +o nosuchnick
+
+2000-04-10  Perry Lorier  <Isomer@coders.net>
+       * BUGS: Added bug.
+
+2000-04-09  Thomas Helvey <tomh@inxpress.net>
+       * include/IPcheck.h: fix prototype
+       * ircd/s_user.c: fix usage of IPcheck_remote_connect
+       * ircd/IPcheck.c: removed unused args
+
+2000-04-09  Thomas Helvey <tomh@inxpress.net>
+       * include/IPcheck.h: add proto for IPcheck_expire
+
+       * ircd/IPcheck.c: Rewrote
+
+       * ircd/ircd.c: Add IPcheck_expire to main message loop
+
+       * ircd/s_user.c: Redo target hashing, refactor target code
+
+       * include/numeric.h: Cleaned up numerics, added which ones are
+       in use by other networks and what they are in use for.
+
+       * ircd/channel.c: cleaned can_join(), allow anyone through anything
+       if /invited, simplified the function.  Opers overusing OPEROVERRIDE
+       will get a message explaining to them not to cheat.
+
+       * ircd/m_join.c: cleaned up the various join functions, should be
+       a lot more efficient.  Still needs work.  Now assumes that s<->s
+       won't send it a JOIN 0.  Service coders - note this and tread with
+       care.
+
+       * ircd/m_stats.c: added Gte-'s stats doc patch.
+
+       * ircd/m_version.c: /version now returns the 005 numeric as well.
+       as requested by Liandrin.
+
+
+2000-04-07  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/m_clearmode.c: add include for support.h for write_log()
+
+       * configure: move ircd/crypt/* to tools/*
+
+2000-04-06  Thomas Helvey <tomh@inxpress.net>
+       * ircd/s_auth.c: Shorten auth connect timeout to 60 seconds
+          set client host to server alias if connection from localhost
+
+2000-04-06  Perry Lorier <isomer@coders.net>
+       * ircd/ircd.c: Fix core during pinging (oops)
+       
+2000-04-06  Perry Lorier <isomer@coders.net>
+       * ircd/send.c: fixed wrong ident being sent to channels bug.
+       * include/numerics.h: Updated some of the numerics from other
+       networks.  Flagged some as 'unused' by undernet.
+
+2000-03-30  Perry Lorier <isomer@coders.net>
+       * ircd/ircd.c: Lets see if this helps the ping problem at all.
+       * ircd/whocmds.c, /doc/readme.who: Added %l specifier to get idle
+       time for local clients. (as requested), extended who now returns all
+       the flags (@+!) so you can tell the complete state of a client.
+
+2000-03-30  Thomas Helvey <tomh@inxpress.net>
+       * m_rping.c m_rpong.c: add Gte's rping/rpong fixes
+
+2000-03-30  Perry Lorier <isomer@coders.net>
+       * ircd/parse.c: oops, missed opers.
+
+2000-03-30  Perry Lorier <isomer@coders.net>
+       * ircd/parse.c: fixed mystifying ping bug thats been plaguing us
+       for so long.  Remember: m_ping MUST be in the parse array. :)
+
+2000-03-30  Perry Lorier <isomer@coders.net>
+       * ircd/ircd.c: test in check_pings was wrong.  I move that we
+       disallow cvs commit after 10pm localtime....
+
+2000-03-30  Perry Lorier <isomer@coders.net>
+       * ircd/m_pong.c: Fix it for servers too.
+
+2000-03-30  Perry Lorier <isomer@coders.net>
+       * ircd/m_pong.c: Fix ping timeout bugs
+
+2000-03-30  Perry Lorier <isomer@coders.net>
+       * ircd/channel.c: Bans had CurrentTime in their when field instead
+       of TStime()
+
+2000-03-31  Thomas Helvey <tomh@ixpress.net>
+       * ircd/numnicks.c (SetXYYCapacity): fix for extended
+       numerics.
+
+2000-03-30  Perry Lorier <isomer@coders.net>
+       * ircd/m_nick.c: send kills both ways so when we add nick change
+       on collision we don't desync the network.
+
+       * ircd/map.c: Fixup the map a bit more.
+
+2000-03-31  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/m_clearmode.c (do_clearmode): Log the CLEARMODE to OPATH
+
+       * ircd/m_opmode.c: Log the mode changes to OPATH
+
+       * ircd/channel.c (modebuf_flush_int): Log the mode changes to
+       OPATH
+
+       * include/channel.h (MODEBUF_DEST_LOG): Log the mode changes to
+       OPATH
+
+       * doc/Configure.help: help text for CONFIG_LOG_OPMODE / OPATH
+
+       * config/config-sh.in: added OPATH for opmode log file
+
+       * ircd/m_clearmode.c (do_clearmode): updated uses of
+       modebuf_mode_string() for the new usage
+
+       * ircd/channel.c: added flag MODE_FREE and an int argument to
+       modebuf_mode_string() to indicate that the string must be free'd;
+       updated calls to modebuf_mode_string() for the new usage; called
+       collapse(pretty_mask()) on the ban string and use allocated memory
+       for it; added ban list length accounting; fixed a number of small
+       bugs in ban processing
+
+       * include/channel.h: added flag MODE_FREE and an int argument to
+       modebuf_mode_string() to indicate that the string must be free'd
+
+       * ircd/m_clearmode.c (do_clearmode): made sure clearmode removed
+       keys and limits that are set
+
+2000-03-30  Perry Lorier <isomer@coders.net>
+       * ircd/ircd.c: rewrote check_pings() for maintainability
+       and speed.  Also changed quit msg's so they don't have
+       redundant nick[host] info in them.
+
+       * ircd/send.c: Changed write errors to report what error
+       occured (if possible).
+
+       * ircd/gline.c: added gline comment to the quit.
+
+       * ircd/m_server.c: Added suggestions to server quits mentioning
+       what went wrong so the admin can fix it earlier instead of asking
+       questions...
+
+       * ircd/map.c: Changed m_map() to hide numerics, show a * beside
+       servers that aren't fully burst yet.  And show '(--s)' for servers
+       where its not sure.
+
+       * doc/example.conf: Fixed wrapped U:
+
+2000-03-30  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/m_mode.c (ms_mode): implemented a new m_mode in terms of
+       mode_parse() (version selectable at compile time)
+
+       * ircd/m_clearmode.c (mo_clearmode): clean_channelname(parv[1])
+
+       * ircd/m_opmode.c (mo_opmode): clean_channelname(parv[1])
+
+       * config/config-sh.in: add new config option to enable new m_mode
+       implementation
+
+       * doc/Configure.help: add documentation for new config option
+       CONFIG_NEW_MODE
+
+       * ircd/channel.c (mode_parse_client): /opmode #foobar -o -- 461
+       MODE -v : Not enough parameters
+
+       * ircd/m_clearmode.c (do_clearmode): do_clearmode() would remove
+       +k and +l even if they weren't set...
+
+       * ircd/m_opmode.c: implement the OPMODE command using mode_parse()
+
+       * ircd/channel.c: make mode_process_clients() clear the DEOPPED
+       flag; fix +s+p exclusivity; add MODE_ADD/MODE_DEL to flag list
+       for; test the 0-th member, not the i-th member, of the client
+       change state stuff
+
+       * ircd/m_clearmode.c (do_clearmode): use the new
+       mode_invite_clear() function
+
+       * ircd/channel.c: cleared up all the compile-time warnings and
+       errors
+
+       * include/channel.h: added declarations for mode_ban_invalidate()
+       and mode_invite_clear()
+
+       * ircd/channel.c: finished mode_parse(), then broke it up into a
+       dozen or so helper functions to make the code easier to read
+
+2000-03-29  Thomas Helvey <tomh@inxpress.net>
+       * ircd/ircd.c: refactor server initialization a bit, use
+       getopt for parsing command line, refactor init_sys, main,
+       and other bits.
+
+       * ircd/s_bsd.c: add functions for initialization to clean
+       up logic a bit and remove duplicated code.
+
+       * include/ircd.h: add struct for server process related
+       variables.
+
+2000-03-29  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/channel.c: initial definition of mode_parse(); flags to
+       prevent doing the same thing multiple times; helper method
+       send_notoper() to send a "Not oper"/"Not on channel" notice
+
+       * include/channel.h: declare mode_parse() and helper flags
+
+       * ircd/channel.c (modebuf_flush_int): fiddled with timestamp
+       sending to match the current action of set_mode() closely enough
+       that hopefully there won't be major conflicts
+
+       * ircd/channel.c (modebuf_flush_int): consolidated the mode string
+       building logic, reversed the order of the arguments to mode
+       commands to have '-' preceed '+'
+
+2000-03-29  Thomas Helvey <tomh@inxpress.net>
+       * ircd/s_bsd.c (add_connection): don't disable socket options
+       let OS tune itself and allow important performance tweaks to 
+       work.
+
+2000-03-28  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/channel.c (modebuf_flush_int): use %d, not %-15d; I got
+       confused by set_mode, which is doing some really weird logic;
+       guess what I'm going to rewrite next?  ;)
+
+2000-03-28  Kevin L. Mitchell  <klmitch@emc.com>
+
+       * include/channel.h: added MODE_SAVE for the bounds checking stuff
+       in modebuf_flush
+
+       * ircd/channel.c: make modebuf_flush into modebuf_flush_int and
+       make it do bounds checking on the buffer; all modes are sent only
+       if the all parameter is 1; modebuf_flush is the exported wrapper
+
+       * include/channel.h: add BOUNCE, renumber flags to get a little
+       more space
+
+       * ircd/channel.c (modebuf_flush): don't overload HACK2, add
+       BOUNCE; send DESYNCH message
+
+2000-03-27  Kevin L. Mitchell  <klmitch@emc.com>
+
+       * ircd/m_clearmode.c (do_clearmode): only mark the modes the
+       channel actually has in effect for deletion
+
+       * ircd/channel.c: added explanatory comments to all added
+       functions; made flushing take place at the correct place even if
+       the MODEBUF_DEST_DEOP flag is set; rewrote build_string() helper
+       to bash some stupid bugs; made modebuf_flush() return if ModeBuf
+       is empty, fixed the apparent source, removed some bogus string
+       termination code, properly terminate the mode strings, add support
+       for HACK2 and HACK3, made limit strings not be sent if the limit
+       is being removed, changed where '+' and '-' come from in sent
+       strings, added support for DEOP flag, set up bouncing code for
+       HACK2
+
+       * ircd/Makefile.in: ran make depend
+
+       * include/channel.h: added new defines for future functionality,
+       made modebuf_flush() return int so I can use tail recursion
+
+       * ircd/m_clearmode.c: add msg.h to includes; other misc cleanups
+       to make it all compile
+
+       * ircd/m_opmode.c: add msg.h to includes...
+
+       * ircd/m_clearmode.c: implemented mo_clearchan()/ms_clearchan()
+
+       * ircd/channel.c (modebuf_flush): realized I forgot to
+       nul-terminate addbuf/rembuf properly...
+
+       * ircd/m_clearmode.c (do_clearmode): wrote do_clearmode()...
+
+       * ircd/channel.c (modebuf_flush): correct sendto_server_butone to
+       sendto_serv_butone--blah^2
+
+       * ircd/send.c (sendto_serv_butone): stupid comments confused me
+
+       * ircd/channel.c (modebuf_flush): if there are no mode changes to
+       propagate, we're done...
+
+       * ircd/channel.c (modebuf_flush): duh; it's sendto_server_butone,
+       not sendto_all_butone
+
+       * ircd/m_clearmode.c: define skeleton for m{o,s}_clearmode
+
+       * ircd/m_opmode.c: define skeleton for m{o,s}_opmode
+
+       * ircd/Makefile.in (SRC): added m_opmode() and m_clearmode() to
+       the list
+
+       * ircd/parse.c: added messages for opmode and clearmode
+
+       * include/handlers.h: added declarations for mo_opmode(),
+       ms_opmode(), mo_clearmode(), and ms_clearmode()
+
+       * include/msg.h: define MSG_OPMODE, TOK_OPMODE, MSG_CLEARMODE, and
+       TOK_CLEARMODE
+
+       * include/channel.h (MODEBUF_DEST_OPMODE): Define the
+       MODEBUF_DEST_OPMODE flag
+
+       * ircd/channel.c (modebuf_flush): added new flag,
+       MODEBUF_DEST_OPMODE; causes channel MODE/HACK(4) notice to appear
+       to originate from source's server (or source itself, if
+       IsServer(source)); also causes a server-level MODE to be sent as
+       OPMODE instead
+
+       * include/channel.h: defined MODEBUF_DEST_SERVER,
+       MODEBUF_DEST_HACK4
+
+       * ircd/channel.c: Add another argument to build_string() to handle
+       numeric nicks; implemented MODEBUF_DEST_SERVER to send MODEs to
+       servers; implemented MODEBUF_DEST_HACK4 to cause HACK(4) notices
+       to be sent out
+
+2000-03-27  Perry Lorier <isomer@coders.net>
+
+       * ircd/s_bsd.c: fixed missing 'u' typo.
+
+2000-03-26  Kevin L. Mitchell  <klmitch@emc.com>
+
+       * ircd/channel.c: implement modebuf_init(), _mode(), _mode_uint(),
+       _mode_string(), _mode_client(), _flush(); also implemented a
+       simple build_string()
+
+       * include/channel.h: added definition of ModeBuf, modebuf_*
+       manipulation functions, and a couple of helper macros
+
diff --git a/ChangeLog.11 b/ChangeLog.11
new file mode 100644 (file)
index 0000000..cc8a9ca
--- /dev/null
@@ -0,0 +1,4169 @@
+2002-01-08  Perry Lorier  <isomer@coders.net>
+       * Fixed the build system -- MAKEFILES is *not* a variable you can
+       just use in a makefile :)
+       * Added "Quit: " prefix to quit messages.
+
+2001-10-14  Perry Lorier  <isomer@coders.net>
+       * Minor fixes to the below
+
+2001-09-21  Perry Lorier  <isomer@coders.net>
+       * ircd/send.c and various: replace sendcmdto_flag_butone with
+       sendwallto_group_butone
+
+2001-09-21  Vampire-  <unknown>
+       * ircd/ircd_string.c: unique_name_vector round II.
+
+2001-09-21  mbuna  <mbuna@undernet.org>
+       * configure.in: Add support for darwin
+
+2001-09-21  Perry Lorier  <isomer@coders.net>
+       * ircd/s_user.c I'm stupid, s/acptr/from/, Hektik pointed it out
+
+2001-09-20  Perry Lorier  <isomer@coders.net>
+
+       * Pullups from 2.10.10.pl16
+       * Added some warnings, and the concept of rate limited snotices
+
+2001-08-31  Kevin L Mitchell  <klmitch@mit.edu>
+
+       * ircd/channel.c: use "%u" to format limit arguments; use
+       strtoul() to process limit arguments in a /mode command--note:
+       most clients seem to truncate the integer, probably because
+       they're using atoi, and perhaps signed ints
+
+2001-08-17  Kevin L Mitchell  <klmitch@mit.edu>
+
+       * ircd/numnicks.c: include stdlib.h for exit()
+
+       * ircd/ircd_log.c: include stdlib.h for exit()
+
+       * ircd/ircd_events.c: include stdlib.h for exit()
+
+       * ircd/s_stats.c: remove description of /stats v, since it's gone
+
+       * ircd/m_wallops.c (mo_wallops): add "*" to the beginning of
+       /wallops to distinguish wallops from wallusers
+
+       * ircd/m_error.c (mr_error): ignore ERROR from clients that aren't
+       in the "handshake" or "connecting" states--I think the latter will
+       never happen, but...
+
+       * doc/Authors: apply delete's Authors patch
+
+       * RELEASE.NOTES: rewrite RELEASE.NOTES, basing it a little on
+       Braden's version
+
+       * README: rewrite README
+
+2001-07-31  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/s_serv.c (server_estab): remove unused variable split
+
+       * ircd/parse.c: add mr_error to the parse table
+
+       * ircd/m_error.c (mr_error): add mr_error() to handle ERRORs from
+       unregistered connections--if IsUserPort() is true, the ERROR is
+       ignored, otherwise, the message is saved
+
+2001-07-28  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/m_kill.c (ms_kill): another minor typo *sigh*
+
+       * ircd/s_user.c (send_supported): oops, minor typo...
+
+       * ircd/s_user.c: implement send_supported() to send two ISUPPORT
+       messages containing our feature buffers; make register_user() use
+       send_supported()
+
+       * ircd/s_misc.c (exit_client): make sure not to give away a remote
+       server in the ERROR message sent to the client; if the killer is a
+       server, we substitute our name in its place
+
+       * ircd/m_version.c (m_version): use send_supported() to send the
+       ISUPPORT values to the user
+
+       * ircd/m_nick.c: shave nick collision kills here a bit, too, for
+       the same reasons as for m_kill.c
+
+       * ircd/m_kill.c: shave kills a bit so that the results look
+       exactly the same no matter where you are; if we didn't do this, it
+       would be possible to map the network by looking at the differences
+       between kills originating under various circumstances
+
+       * include/supported.h: split the features into two, so as to not
+       bust the parameter count when sending the features list
+
+       * include/s_user.h: declare new send_supported() function to send
+       the ISUPPORT information
+
+2001-07-27  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/s_bsd.c: disable IP (*not* TCP) options to prevent
+       source-routed spoofing attacks; this is only available under
+       u2.10.11, so don't even bother, since no one but testers are using
+       the source base
+
+2001-07-25  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * include/ircd_policy.h: enable HEAD_IN_SAND_REMOTE by default
+
+       * ircd/s_err.c: put in a . for reporting link version on /trace,
+       to match what /version does
+
+2001-07-21  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/s_misc.c (exit_client): servers don't understand what the
+       numeric nick ERROR is supposed to mean, so they ignore error
+       messages, resulting in not knowing why we were rejected; use
+       sendcmdto_one for servers and sendrawto_one for clients
+
+2001-07-17  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/m_burst.c (ms_burst): in the case of a modeless channel and
+       a nick collide, a bare BURST may be propagated; adjust the
+       enforced parameter count to accept the bare BURST
+
+2001-07-12  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/s_bsd.c: mark a client as having been IP checked
+
+       * ircd/IPcheck.c (ip_registry_check_remote): remove unneeded
+       second call to SetIPChecked()
+
+2001-07-11  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/engine_poll.c: deal with POLLHUP properly (hopefully)
+
+       * ircd/engine_devpoll.c: deal with POLLHUP properly (hopefully)
+
+2001-07-09  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/os_bsd.c (os_get_rusage): move buf into the two ifdef'd
+       sections so that if neither is used, the declaration of buf will
+       not elicit an "unused variable" warning under NetBSD
+
+       * ircd/m_map.c: include string.h to declare strcpy (fix warnings
+       on alpha)
+
+       * ircd/m_away.c: include string.h to declare strcpy/strlen (fix
+       warnings on alpha)
+
+       * ircd/ircd_log.c: include string.h to declare strcpy/strlen (fix
+       warnings on alpha)
+
+       * ircd/client.c: include string.h to declare memset (fix warnings
+       on alpha)
+
+       * ircd/channel.c: remove unused functions next_overlapped_ban,
+       del_banid, and is_deopped (fix warnings under -O1)
+
+       * ircd/IPcheck.c: include string.h to declare memset/memcpy (fix
+       warnings on alpha)
+
+2001-06-29  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/s_user.c (set_user_mode): clear the snomask if the user
+       isn't supposed to receive server notices anymore
+
+       * ircd/ircd_features.c: change CONFIG_OPERCMDS to default to FALSE
+
+       * configure.in: use AC_MSG_CHECKING/AC_MSG_RESULT when checking
+       installation prefix; default devpoll and kqueue to on (they get
+       turned off if the required headers aren't present)
+
+       * ircd/whocmds.c (do_who): use ircd_snprintf() instead of
+       sprintf_irc(); it's a bit hackish, but it'll do for now
+
+       * ircd/support.c: remove unused #include
+
+       * ircd/send.c: remove unused #include
+
+       * ircd/s_user.c: use ircd_snprintf() instead of sprintf_irc()
+
+       * ircd/s_serv.c: remove unused #include
+
+       * ircd/s_misc.c: use ircd_snprintf() and friends instead of
+       sprintf_irc() and friends
+
+       * ircd/s_err.c: moved atoi_tab[] from ircd/sprintf_irc.c to
+       ircd/s_err.c, which is the only other file to refer to it
+
+       * ircd/s_conf.c (conf_add_deny): use ircd_snprintf() instead of
+       sprintf_irc()
+
+       * ircd/s_bsd.c (connect_server): use ircd_snprintf() instead of
+       sprintf_irc()
+
+       * ircd/s_auth.c: use ircd_snprintf() instead of sprintf_irc()
+
+       * ircd/res.c: use ircd_snprintf() instead of sprintf_irc()
+
+       * ircd/m_version.c: use ircd_snprintf() instead of sprintf_irc()
+
+       * ircd/m_kill.c: use ircd_snprintf() instead of sprintf_irc()
+
+       * ircd/listener.c: use ircd_snprintf() instead of sprintf_irc()
+
+       * ircd/gline.c: use ircd_snprintf() instead of sprintf_irc()
+
+       * ircd/channel.c: don't include sprintf_irc.h; use ircd_snprintf()
+       instead of sprintf_irc()
+
+       * ircd/Makefile.in: remove sprintf_irc.c from sources list; run
+       make depend
+
+       * include/ircd_string.h: remove declaration of sprintf_irc() (what
+       was it doing here anyway?)
+
+       * include/sprintf_irc.h: removed unneeded source file
+
+       * ircd/sprintf_irc.c: removed unneeded source file
+
+       * ircd/s_debug.c (count_memory): remove some dead code
+
+       * ircd/s_auth.c: remove some dead code
+
+       * ircd/res.c (update_list): remove some dead code
+
+       * ircd/m_whowas.c: remove some dead code
+
+       * ircd/m_whois.c: remove some dead code
+
+       * ircd/m_who.c: remove some dead code
+
+       * ircd/m_wallusers.c: remove some dead code
+
+       * ircd/m_wallops.c: remove some dead code
+
+       * ircd/m_wallchops.c: remove some dead code
+
+       * ircd/m_version.c: remove some dead code
+
+       * ircd/m_userip.c: remove some dead code
+
+       * ircd/m_userhost.c: remove some dead code
+
+       * ircd/m_uping.c: remove some dead code
+
+       * ircd/m_trace.c: remove some dead code
+
+       * ircd/m_topic.c: remove some dead code
+
+       * ircd/m_tmpl.c: remove some dead code
+
+       * ircd/m_time.c: remove some dead code
+
+       * ircd/m_squit.c: remove some dead code
+
+       * ircd/m_silence.c: remove some dead code
+
+       * ircd/m_settime.c: remove some dead code
+
+       * ircd/m_set.c: remove some dead code
+
+       * ircd/m_server.c: remove some dead code
+
+       * ircd/m_rpong.c: remove some dead code
+
+       * ircd/m_rping.c: remove some dead code
+
+       * ircd/m_restart.c: remove some dead code
+
+       * ircd/m_reset.c: remove some dead code
+
+       * ircd/m_rehash.c: remove some dead code
+
+       * ircd/m_quit.c: remove some dead code
+
+       * ircd/m_proto.c: remove some dead code
+
+       * ircd/m_privs.c: remove some dead code
+
+       * ircd/m_privmsg.c: remove some dead code
+
+       * ircd/m_pong.c: remove some dead code
+
+       * ircd/m_ping.c: remove some dead code
+
+       * ircd/m_pass.c: remove some dead code
+
+       * ircd/m_part.c: remove some dead code
+
+       * ircd/m_opmode.c: remove some dead code
+
+       * ircd/m_oper.c: remove some dead code
+
+       * ircd/m_notice.c: remove some dead code
+
+       * ircd/m_nick.c: remove some dead code
+
+       * ircd/m_map.c: remove some dead code
+
+       * ircd/m_lusers.c: remove some dead code
+
+       * ircd/m_list.c: remove some dead code
+
+       * ircd/m_links.c: remove some dead code
+
+       * ircd/m_kill.c: remove some dead code
+
+       * ircd/m_kick.c: remove some dead code
+
+       * ircd/m_jupe.c: remove some dead code
+
+       * ircd/m_join.c: remove some dead code
+
+       * ircd/m_ison.c: remove some dead code
+
+       * ircd/m_invite.c: remove some dead code
+
+       * ircd/m_info.c: remove some dead code
+
+       * ircd/m_help.c: remove some dead code
+
+       * ircd/m_gline.c: remove some dead code
+
+       * ircd/m_get.c: remove some dead code
+
+       * ircd/m_error.c: remove some dead code
+
+       * ircd/m_endburst.c: remove some dead code
+
+       * ircd/m_die.c: remove some dead code
+
+       * ircd/m_desynch.c: remove some dead code
+
+       * ircd/m_destruct.c: remove some dead code
+
+       * ircd/m_defaults.c: remove some dead code
+
+       * ircd/m_create.c: remove some dead code, along with an #if 1
+
+       * ircd/m_cprivmsg.c: remove some dead code
+
+       * ircd/m_connect.c: remove some dead code
+
+       * ircd/m_close.c: remove some dead code
+
+       * ircd/m_clearmode.c: remove some dead code
+
+       * ircd/m_burst.c: remove some dead code
+
+       * ircd/m_away.c: remove some dead code
+
+       * ircd/m_admin.c: remove some dead code
+
+       * ircd/listener.c (accept_connection): remove some dead code
+
+       * ircd/ircd_reply.c (need_more_params): remove some dead code
+
+       * ircd/channel.c (add_banid): remove some dead code
+
+       * include/support.h: remove some dead code
+
+       * include/querycmds.h: remove some dead code
+
+       * doc/readme.chroot: document how to do chroot operation
+
+2001-06-28  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/Makefile.in: tune for VPATH builds/installs; add a rule to
+       force bin directory to be created if necessary prior to
+       installation; run make depend
+
+       * doc/Makefile.in (install): tune for VPATH installs by cd'ing to
+       the ${srcdir}
+
+       * Makefile.in: tune to detect Makefile.in changes in
+       subdirectories and to create installation directory indicated by
+       ${prefix}
+
+       * ircd/whocmds.c (count_users): routine to count the number of
+       users matching a given user@host mask
+
+       * ircd/s_err.c: add error messages for ERR_LONGMASK,
+       ERR_TOOMANYUSERS, and ERR_MASKTOOWIDE
+
+       * ircd/m_gline.c: look for and advance past '!' flag on G-lines
+       from operators; only set GLINE_OPERFORCE flag if oper has the
+       PRIV_WIDE_GLINE privilege
+
+       * ircd/ircd_features.c: add GLINEMAXUSERCOUNT, which is the
+       maximum number of users a G-line can impact before it has to be
+       forced; OPER_WIDE_GLINE, to allow operators to use ! to force a
+       wide G-line to be set; and LOCOP_WIDE_GLINE, to allow local
+       operators to use ! to force a wide G-line to be set
+
+       * ircd/gline.c: make make_gline() be called with separate user and
+       host arguments, and not call canon_userhost() directly; implement
+       gline_checkmask() to verify that a host mask is acceptable; move
+       BADCHAN check up in gline_add(), and check passed-in mask under
+       certain circumstances for acceptability; fix call to
+       sendto_opmask_butone() to handle separation of userhost into user
+       and host in gline_add(); update call to make_gline()
+
+       * ircd/client.c: use FEAT_OPER_WIDE_GLINE and
+       FEAT_LOCOP_WIDE_GLINE to set PRIV_WIDE_GLINE for an operator; add
+       PRIV_WIDE_GLINE to privtab[] for client_report_privs()
+
+       * include/whocmds.h (count_users): declare routine to count users
+       matching a given user@host mask
+
+       * include/numeric.h: added three new error returns: ERR_LONGMASK
+       -- mask can't be formatted into a buffer; ERR_TOOMANYUSERS -- too
+       many users would be impacted by the mask; ERR_MASKTOOWIDE -- mask
+       contains wildcards in the wrong places
+
+       * include/ircd_features.h: add FEAT_GLINEMAXUSERCOUNT,
+       FEAT_OPER_WIDE_GLINE, and FEAT_LOCOP_WIDE_GLINE
+
+       * include/gline.h (GLINE_OPERFORCE): provides a way for m_gline()
+       to signal to gline_add() that the operator attempted to force the
+       G-line to be set
+
+       * include/client.h (PRIV_WIDE_GLINE): new privilege for operators
+
+       * doc/readme.gline: update to document new "!" prefix to a G-line
+       user@host mask
+
+       * doc/readme.features: document GLINEMAXUSERCOUNT,
+       OPER_WIDE_GLINE, and LOCOP_WIDE_GLINE
+
+       * doc/example.conf: update to mention new features along with
+       their defaults
+
+2001-06-27  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * doc/example.conf: updated example.conf from Braden
+       <dbtem@yahoo.com>
+
+       * include/supported.h: forward-port from pl15
+
+2001-06-25  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/whocmds.c: include ircd_policy.h and implement
+       HEAD_IN_SAND_WHO_OPCOUNT--forward-port from pl15
+
+       * ircd/m_whois.c: forward-port of the idle-time hiding code from
+       pl15; this also required passing parc into do_whois(), which also
+       meant passing parc into do_wilds()--*sigh*
+
+       * include/ircd_policy.h: add a couple more HEAD_IN_SAND
+       #define's--WHOIS_IDLETIME and WHO_HOPCOUNT
+
+2001-06-22  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * tools/wrapper.c: add a wrapper program that can be used to
+       adjust file descriptor limits and root directories; program must
+       be run as root--NOT SETUID!--and given appropriate -u arguments
+
+       * doc/readme.log: documentation of how to configure logging
+
+       * doc/readme.features: documentation of each feature (except for
+       logging)
+
+2001-06-21  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * Makefile.in (config): add a deprecation notice with a pointer to
+       tools/transition
+
+       * tools/transition: shell script to convert old compile-time
+       options into new compile-time options and appropriate F-lines
+
+       * tools/mkchroot: shell-script to prepare the chroot area by
+       copying over all the necessary libraries so they can be found
+
+2001-06-20  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * INSTALL: partial update of INSTALL for u2.10.11 release...
+
+2001-06-14  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/table_gen.c (makeTables): finally got tired of the
+       "overflow in implicit conversion" warning, so just got rid of it
+       by explicitly casting UCHAR_MAX to a (default) char; diffs show no
+       differences in the tables generated
+
+2001-06-11  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/send.c (sendcmdto_match_butone): don't let the server crash
+       if a client is in the STAT_CONNECTING status
+
+2001-06-10  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/send.c: remove unused vsendcmdto_one(), consolidating it
+       into sendcmdto_one(); define new sendcmdto_prio_one(), which
+       places the message into the priority queue
+
+       * ircd/s_user.c (hunt_server_prio_cmd): definition of
+       hunt_server_prio_cmd(), which simply calls sendcmdto_prio_one()
+       instead of sendcmdto_one()
+
+       * ircd/m_settime.c: use sendcmdto_prio_one() and
+       hunt_server_prio_cmd() to send SETTIME
+
+       * ircd/m_server.c: use sendcmdto_prio_one() to send SETTIME
+
+       * include/send.h: removed declaration for unused vsendcmdto_one();
+       added a declaration for sendcmdto_prio_one()
+
+       * include/s_user.h: declare hunt_server_prio_cmd(), which calls
+       sendcmdto_prio_one()
+
+       * ircd/send.c (sendcmdto_flag_butone): oops; /wallops should be
+       put in the server's priority queue, too...
+
+       * ircd/ircd.c: don't check LPATH for accessibility at all
+
+2001-06-08  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/s_serv.c (server_estab): send a +h flag in our SERVER
+       command if we're configured as a hub; send individual server flags
+       in SERVER commands
+
+       * ircd/s_bsd.c (completed_connection): send a +h flag in our
+       SERVER command if we're configured as a hub
+
+       * ircd/m_server.c: implement parv[7] as a mode-like string; +h
+       sets the FLAGS_HUB flag for a server; +s sets the FLAGS_SERVICE
+       flag for a server; +hs sets both flags; also modify CMD_SERVER
+       format string to send the flags
+
+       * include/client.h: define two new flags, FLAGS_HUB and
+       FLAGS_SERVICE to mark services and hubs as such; define testing
+       macros, setting macros
+
+       * ircd/s_user.c: remove deprecated struct Gline* argument to
+       register_user(); remove GLINE rebroadcast; do not send GLINE
+       acknowledgement parameter to NICK; do not look for GLINE
+       acknowledgement parameter to NICK while parsing
+
+       * ircd/s_serv.c (server_estab): remove deprecated struct Jupe*
+       argument to server_estab(); do not send JUPE/GLINE acknowledgement
+       parameters for SERVER or NICK
+
+       * ircd/m_user.c (m_user): remove deprecated argument to
+       register_user()
+
+       * ircd/m_server.c: remove deprecated argument to server_estab();
+       remove documentation comment regarding JUPE acknowledgement
+       parameter to SERVER; remove JUPE rebroadcast
+
+       * ircd/m_pong.c (mr_pong): remove deprecated argument to
+       register_user()
+
+       * ircd/m_nick.c: remove documentation comment regarding GLINE
+       acknowledgement parameter to NICK
+
+       * ircd/jupe.c: use user's real name in JUPE server notices if
+       HEAD_IN_SAND_SNOTICES is defined
+
+       * ircd/ircd.c: remove deprecated chroot() code; remove deprecated
+       setuid code; correct ancient DEBUG vs DEBUGMODE typo
+
+       * ircd/gline.c: use user's real name in GLINE server notices if
+       HEAD_IN_SAND_SNOTICES is defined
+
+       * ircd/channel.c (modebuf_flush_int): make apparent source be
+       local server, not oper's server; use user's real name in hack
+       notices and DESYNC notices if HEAD_IN_SAND_SNOTICES is defined
+
+       * include/s_user.h: remove struct Gline pre-declaration; remove
+       deprecated struct Gline argument from register_user()
+
+       * include/s_serv.h: remove struct Jupe pre-declaration; remove
+       deprecated struct Jupe argument from server_estab()
+
+2001-06-07  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/s_stats.c (hunt_stats): forward-port from pl15 of all the
+       changes required to control remote stats
+
+       * ircd/s_numeric.c (do_numeric): rewrite numeric origins if
+       recipient is not an operator and HEAD_IN_SAND_REWRITE is defined
+       [forward-port from pl15]
+
+       * ircd/m_whowas.c (m_whowas): report server name only if requester
+       is an operator [forward-port from pl15]
+
+       * ircd/m_whois.c (do_whois): /whois <mynick> now correctly reports
+       my server; if HEAD_IN_SAND_REMOTE is 1, ignore the middle argument
+       and obtain the report from the user's server [forward-port from
+       pl15]
+
+       * ircd/m_who.c: add missing include for ircd_policy.h
+       [forward-port from pl15]
+
+       * ircd/m_version.c (m_version): require oper access for remote
+       /version if HEAD_IN_SAND_REMOTE is 1 [forward-port from pl15]
+
+       * ircd/m_time.c (m_time): require oper access for remote /time if
+       HEAD_IN_SAND_REMOTE is 1 [forward-port from pl15]
+
+       * ircd/m_stats.c: pass extra argument to hunt_stats(); correct
+       missing semicolon [forward-port from pl15]
+
+       * ircd/m_nick.c (ms_nick): hide the origin of certain collision
+       kills [forward-port from pl15]
+
+       * ircd/m_motd.c (m_motd): require oper access for remote /motd if
+       HEAD_IN_SAND_REMOTE is 1 [forward-port from pl15]
+
+       * ircd/m_lusers.c (m_lusers): require oper access for remote
+       /lusers if HEAD_IN_SAND_REMOTE is 1 [forward-port from pl15]
+
+       * ircd/m_burst.c (ms_burst): server-added bans are stored using
+       local server name, to hide remote server names; modes also are to
+       originate from the local server [forward-port from pl15]
+
+       * ircd/m_admin.c (m_admin): require oper access for remote /admin
+       if HEAD_IN_SAND_REMOTE is 1 [forward-port from pl15]
+
+       * ircd/channel.c (add_banid): if a server is adding a ban, use my
+       server name to hide the remote server's name [forward-port from
+       pl15]
+
+       * ircd/Makefile.in: ran make depend
+
+       * include/s_stats.h: hunt_stats() has to have an extra argument to
+       support the forward-port from pl15
+
+       * include/ircd_policy.h: #define HEAD_IN_SAND_STATS_P; add
+       HEAD_IN_SAND_{BANWHO,REWRITE,REMOTE} [forward-port from pl15]
+
+       * ircd/engine_poll.c (engine_loop): remove bogus assert that I
+       forgot to check in the events branch
+
+2001-06-06  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/res.c (init_resolver): don't start DNS expires with a 0
+       relative timeout--if the server starts slow, timeouts could be
+       messy...there's probably a better solution, but this'll do for now
+
+       * ircd/os_solaris.c: _XOPEN_SOURCE doesn't get along with Solaris
+       headers very well; include stropts.h; define an os_set_tos()
+
+       * ircd/os_generic.c (os_set_tos): added an os_set_tos() for
+       os_generic.c
+
+       * ircd/ircd.c: if there are no C-lines, we don't want to have a
+       timer that expires at the absolute time of 0--it kinda blocks all
+       the other timers!
+
+       * ircd/engine_devpoll.c: some includes for open(); declare errcode
+       and codesize in engine_loop()
+
+       * ircd/list.c (free_client): remove bogus check on timer active
+       flag
+
+       * ircd/s_auth.c: pull out destruction code in
+       auth_timeout_request() into an externally-visible
+       destroy_auth_request(); manage cli_auth pointer in client
+       structure; use it for an extra assertion check
+
+       * ircd/list.c: include s_auth.h for destroy_auth_request(); add
+       debugging notices to show flow when deallocating
+       connections/clients; call destroy_auth_request() when free'ing a
+       client that has an auth outstanding; don't free the connection if
+       the process timer is unmarked but still active
+
+       * ircd/ircd_events.c: set GEN_ACTIVE when initializing a generator
+       and reset it before calling the event handler for an ET_DESTROY
+       event
+
+       * include/s_auth.h (destroy_auth_request): declare
+       destroy_auth_request(), which can be used to destroy an
+       outstanding auth request if a client socket goes away before the
+       auth exchange is completed
+
+       * include/ircd_events.h: add an active flag to keep track of
+       whether or not particular generators are active, for the
+       convenience of functions using the API
+
+       * include/client.h: add a pointer for auth requests to struct
+       Connection so we can kill outstanding auth requests if a client
+       socket closes unexpectedly
+
+       * ircd/s_bsd.c: cli_connect() could become 0 during the course of
+       the sock or timer callback; take that into account in the assert
+
+       * ircd/list.c: add magic number checking and setting--magic
+       numbers are zero'd on frees to detect double-frees; add back
+       setting of cli_from() to 0 to break the back-link from the struct
+       Connection (duh)
+
+       * ircd/ircd.c: set me's magic number correctly
+
+       * include/client.h: define magic numbers and accessor/verifier
+       macros
+
+       * ircd/list.c: assert that dealloc_client() is called with
+       cli_connect(cptr) == 0; set cli_connect(cptr) to 0 before calling
+       dealloc_client(); don't mess with cli_from(cptr)
+
+       * ircd/s_bsd.c: only attempt to dealloc a connection if the
+       associated client has already been destroyed, or at least delinked
+
+2001-06-05  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/list.c (free_client): only try to delete the socket when
+       the fd hasn't already been closed, avoiding a double-free
+
+       * ircd/list.c (free_connection): make sure the client is really
+       gone before doing away with the connection
+
+       * ircd/s_bsd.c: record that socket has been added in con_freeflag
+       field; queue a socket_del() as soon as the socket is close()'d;
+       use con_freeflag & FREEFLAG_TIMER instead of con_timer; clear
+       FREEFLAG_SOCKET on ET_DESTROY event in client_sock_callback(),
+       then dealloc the connection if safe; mark socket as dead when
+       there's a read error or EOF; clear FREEFLAG_TIMER flag upon entry
+       to client_timer_callback(); dealloc connection if safe upon
+       ET_DESTROY event in client_timer_callback()
+
+       * ircd/list.c: use con_freeflag instead of con_timer; only dealloc
+       the connection if both socket and timer have been destroyed;
+       destroy both socket and timer explicitly and carefully
+
+       * include/client.h: replace the con_timer field with a
+       con_freeflag field, to indicate what still needs freeing; define
+       the freeflags
+
+       * ircd/engine_select.c (engine_loop): duh...sockList[i] could
+       become 0
+
+       * ircd/engine_devpoll.c (engine_loop): duh...sockList[i] could
+       become 0
+
+       * ircd/s_bsd.c: add some extra assertions to try to track down a
+       corruption problem
+
+       * ircd/engine_select.c (engine_loop): add an extra assert to try
+       to track down a corruption problem
+
+       * ircd/engine_poll.c (engine_loop): add an extra assert to try to
+       track down a corruption problem
+
+       * ircd/engine_kqueue.c (engine_loop): add an extra assert to try
+       to track down a corruption problem
+
+       * ircd/engine_devpoll.c (engine_loop): skip slots that have become
+       empty during processing; add an extra assert to try to track down
+       a corruption problem
+
+       * ircd/engine_kqueue.c (engine_delete): make sure to zero deleted
+       entries
+
+2001-06-04  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/s_bsd.c (client_sock_callback): client is no longer
+       blocked, so we must mark it as unblocked
+
+       * ircd/engine_select.c: add Debug() calls galore; add handling for
+       SS_NOTSOCK; use a dummy sock variable to keep things from
+       disappearing on us; correct timeout calculation; update nfds for
+       efficiency
+
+       * ircd/engine_poll.c: use new debugging level (DEBUG_ENGINE);
+       remove a spurious "if (sock)" which will always be true; update
+       nfds for efficiency
+
+       * ircd/engine_kqueue.c: add Debug() calls galore; add handling for
+       SS_NOTSOCK (just in case); correct timeout calculation
+
+       * ircd/engine_devpoll.c: add Debug() calls galore; add handling
+       for SS_NOTSOCK; correct timeout calculation; add EAGAIN handling
+
+       * include/s_debug.h (DEBUG_ENGINE): add new debugging level;
+       pretty-indent numbers
+
+       * ircd/engine_poll.c (engine_loop): break out SS_NOTSOCK
+       case--it's not a socket; the check for writability is most likely
+       not needed, but present for completeness
+
+2001-05-24  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/s_bsd.c: add Debug messages; call read_packet() even if the
+       no newline flag is set; call read_packet() when the timer expires,
+       regardless of what's in the buffer--read_packet() should be able
+       to deal properly
+
+       * ircd/IPcheck.c (ip_registry_connect_succeeded): correct a NOTICE
+       sent to clients to include the client nickname (duh)
+
+       * ircd/ircd_events.c: don't destroy a timer if it's already marked
+       for destruction; replace a missing ! in socket_del()
+
+       * ircd/engine_poll.c (engine_loop): reference a temporary variable
+       so we don't have to worry about sockList[i] going away
+
+       * ircd/s_bsd.c (client_sock_callback): add Debug messages
+
+       * ircd/s_auth.c: add Debug messages all over the place
+
+       * ircd/ircd_events.c: add and edit some Debug messages; add a list
+       of routines to convert some of the enums and flags from numbers
+       into human-readable strings for the Debug messages
+
+       * ircd/engine_poll.c: hack some Debug messages to use the new name
+       conversion routines in ircd_events.c; add an extra assert for a
+       condition that shouldn't ever happen; apparently recv() can return
+       EAGAIN when poll() returns readable--I wonder why...
+
+       * include/ircd_events.h: declare some helper routines under
+       DEBUGMODE
+
+2001-05-23  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/s_bsd.c (client_sock_callback): add an extra assertion
+       check
+
+       * ircd/s_auth.c: add more Debug messages
+
+       * ircd/list.c (make_client): add an extra assertion check
+
+       * ircd/ircd_events.c (socket_events): don't call the engine events
+       changer if we haven't actually made any changes to the event mask
+
+       * ircd/uping.c: add some Debug messages
+
+       * ircd/s_stats.c: document new /STATS e
+
+       * ircd/s_err.c: add RPL_STATSENGINE to report the engine name
+
+       * ircd/s_bsd.c: remove static client_timer variable; in
+       read_packet(), if there's still data in the client's recvQ after
+       parsing, add a 2 second timer (con_proc); fix the ET_DESTROY case
+       of client_sock_callback to handle destroying the timer properly;
+       rewrote client_timer_callback from scratch to be called on an
+       individual client
+
+       * ircd/m_stats.c: add /STATS e to report the engine name
+
+       * ircd/list.c: deal with con_timer field in struct Connection
+       properly; correct a core-level bug in remove_client_from_list--if
+       the client is the only one in the list, we try to update
+       GlobalClientList's cli_prev pointer--not good
+
+       * ircd/ircd.c: remove call to init_client_timer()
+
+       * ircd/engine_poll.c: made Debug messages more uniform by
+       prepending "poll:" to them all; corrected an off-by-one error that
+       caused poll_count to be 1 less than the actual count and removed
+       my work-around; added Debug messages to indicate which socket is
+       being checked and what the results are
+
+       * ircd/Makefile.in: ran a make depend
+
+       * include/s_bsd.h: remove init_client_timer(), since we're doing
+       it differently now
+
+       * include/numeric.h (RPL_STATSENGINE): a stats reply to report the
+       engine name
+
+       * include/ircd_policy.h (HEAD_IN_SAND_STATS_E): turn off /stats e
+       reports for non-opers
+
+       * include/client.h: add con_timer and con_proc fields to struct
+       Connection and define accessor macros--con_timer marks that
+       con_proc contains a valid timer, and con_proc is used to pace user
+       data
+
+       * ircd/s_bsd.c (close_connection): let free_client() destroy the
+       socket
+
+       * ircd/s_auth.c (start_auth): add a Debug call to indicate when
+       auth has begun on a client
+
+       * ircd/ircd_events.c: ensure that event_execute() is called with a
+       non-NULL event; modify event_add() macro to properly zero list
+       bits; modify gen_dequeue() to not try to clip it out of a list
+       it's already been clipped out of; change signal socket
+       initialization to use state SS_NOTSOCK; permit timeout values of
+       0 in add_timer(); add many Debug calls; change socket_del() and
+       timer_del() to always set the GEN_DESTROY flag; use GEN_MARKED in
+       timer_run() instead of GEN_DESTROY so that event_generate() will
+       pass on the events; remove the switch and replace with a simpler
+       if-then-else tree in timer_run(); don't allow destroyed sockets to
+       be destroyed again, nor their states or event masks to be changed
+
+       * ircd/ircd.c: initialize "running" to 1
+
+       * ircd/engine_poll.c: deal with SS_NOTSOCK "sockets"; add Debug
+       messages all over the place; fix a counting problem in
+       engine_add(); turn wait into a signed integer and set it to -1
+       only if timer_next() returns 0; adjust wait time to be relative;
+       don't call gen_ref_dec() if socket disappeared while we were
+       processing it
+
+       * include/ircd_events.h: the pipe for signals is not a socket, so
+       we must mark it as such--added SS_NOTSOCK for that special socket;
+       events won't be generated if GEN_DESTROY is on, so add GEN_MARKED
+       for the benefit of timer_run()
+
+       * configure.in: add --enable-pedantic and --enable-warnings to
+       turn on (and off) -Wall -pedantic in CFLAGS
+
+2001-05-21  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/s_conf.c: change "s_addr" element accesses to "address"
+       element accesses
+
+       * include/s_conf.h: on some systems, "s_addr" is a macro; use
+       "address" instead
+
+2001-05-18  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/engine_kqueue.c: include ircd_alloc.h; set_or_clear returns
+       void in this file; add a missing semi-colon; declare errcode,
+       codesize
+
+       * ircd/uping.c (uping_sender_callback): it's pptr, not uping
+
+       * ircd/s_user.c (register_user): comment out spurious reference to
+       nextping
+
+       * ircd/s_serv.c (server_estab): comment out spurious reference to
+       nextping
+
+       * ircd/s_conf.c (read_configuration_file): comment out spurious
+       reference to nextping and nextconnect
+
+       * ircd/s_bsd.c: comment out some spurious references to formerly
+       global (now non-existant) variables; correct a couple of typos
+
+       * ircd/s_auth.c: pre-declare some functions referenced in the
+       callback; correct a typo
+
+       * ircd/res.c (start_resolver): pass errno value of ENFILE
+
+       * ircd/listener.c (accept_connection): you know your API is messed
+       up when...variables that shouldn't have been global crop up in
+       other files
+
+       * ircd/list.c (free_client): substitution of == for =
+
+       * ircd/ircd_signal.c: include assert.h for assertion checking;
+       check ev_data() to find out what signal generated event
+
+       * ircd/ircd_events.c: some references to the variable "timer"
+       should have been references to the variable "ptr"
+
+       * ircd/engine_select.c: it's struct fd_set, not struct fdset;
+       ev_timer(ev) is already a timer pointer; declare codesize as a
+       size_t to correct signedness issue; use timer_next(), not
+       time_next()
+
+       * ircd/engine_poll.c: ev_timer(ev) is already a timer pointer;
+       select fd out of struct pollfd in assertion checking; declare
+       errcode and codesize; use timer_next(), not time_next()
+
+       * ircd/engine_kqueue.c: ev_timer(ev) is already a timer pointer;
+       use function timer_next(), not time_next()
+
+       * ircd/engine_devpoll.c: ev_timer(ev) is already a timer pointer;
+       use function timer_next(), not time_next()
+
+       * ircd/Makefile.in (IRCD_SRC): add ircd_events.c to the list of
+       compiled sources; do make depend
+
+       * include/list.h: pre-declare struct Connection
+
+       * include/ircd_events.h (gen_ref_inc): cast to the right structure
+       name
+
+       * include/s_auth.h: duh; missing */
+
+2001-05-10  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/send.c: update write events status after sending data or
+       accumulating data to be sent
+
+       * ircd/m_list.c (m_list): update write events status after
+       canceling a running /list
+
+       * ircd/channel.c (list_next_channels): update write events status
+       after listing a few channels
+
+       * ircd/s_bsd.c: extensive changes to update to new events model;
+       remove on_write_unblocked() and the two implementations of
+       read_message(), which have been deprecated by this change
+
+       * ircd/s_auth.c: set the socket events we're interested in for
+       clients; simplify some logic that does the connect_nonb followed
+       by the socket_add
+
+       * ircd/list.c: define free_connection() to free a connection
+       that's become freeable once the struct Socket has been
+       deallocated; fix up free_client() to take this new behavior into
+       account
+
+       * ircd/ircd.c: call init_client_timer()
+
+       * include/s_bsd.h: declare new REGISTER_ERROR_MESSAGE when unable
+       to register connect-in-progress with events system; declare
+       init_client_timer() (HACK!) to preserve rate-limiting behavior
+
+       * include/list.h: declare new free_connection()
+
+       * include/client.h: add a struct Socket to struct Connection
+
+2001-05-09  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/ircd_signal.c: massage the handlers for SIGHUP, SIGINT, and
+       SIGTERM into event callbacks; perform the actions in the
+       callbacks, since they're not called in the context of the signal;
+       set up the signal callbacks in the event engine
+
+       * ircd/ircd_events.c (signal_callback): we're supposed to look for
+       a specific signal; don't generate an event if there is no signal
+       structure for it
+
+       * ircd/ircd.c: nuke nextconnect and nextping and replace them with
+       connect_timer and ping_timer; massage try_connections() and
+       check_pings() into timer callbacks that re-add themselves at the
+       right time; remove ircd.c's "event_loop()"; initialize the event
+       system and the connect_timer and ping_timer
+
+       * ircd/uping.c: correct a couple more typos
+
+       * ircd/s_auth.c: rework to use new events system
+
+       * ircd/os_solaris.c (os_connect_nonb): update to new interface
+
+       * ircd/os_openbsd.c (os_connect_nonb): update to new interface
+
+       * ircd/os_linux.c (os_connect_nonb): update to new interface
+
+       * ircd/os_generic.c (os_connect_nonb): update to new interface
+
+       * ircd/os_bsd.c (os_connect_nonb): update to new interface
+
+       * include/s_auth.h: remove deprecated members of struct
+       AuthRequest, replacing them with struct Socket and struct Timer
+       structures; add flags to indicate when these structures have been
+       released by the event system; remove the deprecated
+       timeout_auth_queries()
+
+       * include/ircd_osdep.h (os_connect_nonb): connect could complete
+       immediately, so change the interface to handle that possibility
+
+       * ircd/uping.c (uping_server): noticed and corrected a typo
+
+       * ircd/listener.c: set up to use ircd_event's struct Socket by
+       adding an socket_add() call to inetport(), replacing
+       free_listener() with socket_del() in close_listener(), and
+       reworking accept_connection to be called as the callback
+
+       * ircd/ircd.c: add a call to IPcheck_init()
+
+       * ircd/IPcheck.c: remove IPcheck_expire(); rework
+       ip_registry_expire() to be called from a timer; write
+       IPcheck_init() to set up the expiration timer (hard-coded for a
+       60-second expiration time)
+
+       * include/listener.h: add a struct Socket to the struct Listener;
+       remove accept_connection()
+
+       * include/IPcheck.h: add IPcheck_init(), remove IPcheck_expire()
+
+2001-05-08  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/ircd_events.c: include config.h; use USE_KQUEUE and
+       USE_DEVPOLL instead of HAVE_KQUEUE and HAVE_DEVPOLL_H
+
+       * ircd/engine_select.c: include config.h; set FD_SETSIZE to
+       MAXCONNECTIONS, not IRCD_FD_SETSIZE...
+
+       * ircd/engine_poll.c: include config.h
+
+       * ircd/engine_kqueue.c: include config.h
+
+       * ircd/engine_devpoll.c: include config.h
+
+       * ircd/Makefile.in: include engine sources in compilation and make
+       depend steps
+
+       * configure.in: add checks for enabling the /dev/poll- and
+       kqueue-based engines
+
+       * acconfig.h: add lines for USE_DEVPOLL and USE_KQUEUE
+
+       * ircd/Makefile.in: work in the engine sources
+
+2001-05-07  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/m_settime.c: include ircd_snprintf.h
+
+       * ircd/ircd_relay.c: stomp a couple of gcc warnings suggesting
+       parens around a construct that had both || and &&
+
+       * ircd/chkconf.c: #include "config.h" to get some important
+       definitions
+
+       * ircd/Makefile.in: revamp ircd makefile for new build system
+
+       * doc/Makefile.in: revamp doc makefile for new build system
+
+       * config/*: Removed old build system files
+
+       * stamp-h.in: a stamp file
+
+       * install-sh: install-sh for new build system
+
+       * configure.in: configure.in for new build system
+
+       * configure: configure script for new build system (built by
+       autoconf)
+
+       * config.sub: config.sub for new build system
+
+       * config.h.in: config.h.in for new build system (built by
+       autoheader)
+
+       * config.guess: config.guess for new build system
+
+       * aclocal.m4: aclocal.m4 for new build system (built by aclocal
+       1.4)
+
+       * acinclude.m4: aclocal.m4 macros for new build system
+
+       * acconfig.h: config.h skeleton for new build system
+
+       * Makefile.in: modify for new build system
+
+2001-05-01  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/s_err.c: get rid of the last vestiges of TIME_T_FMT
+
+       * ircd/m_settime.c: get rid of the last vestiges of TIME_T_FMT
+
+       * ircd/m_server.c: get rid of the last vestiges of TIME_T_FMT
+
+2001-05-01  Perry Lorier       <Isomer@coders.net>
+       * doc/iauth.doc: Protocol for iauth server. (from hybrid).
+       * doc/linux-poll.patch: Patch to make Linux under 2.2 not deadlock
+               when you have far far too many sockets in use.
+       * {include,ircd}/iauth.c: A start on iauth support.
+
+2001-05-01  Perry Lorier       <Isomer@coders.net>
+       * ircd/s_err.c: Suggested wording change.
+       * ircd/s_user.c: Users aren't target limited against +k users.
+       * ircd/chkconf.c: Made it compile again, who knows if it works, but
+               now I can at least make install
+        * various: Cleanups on m_*.c files.
+
+
+2001-04-23  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/s_misc.c (exit_client): make netsplit server notice say the
+       right thing
+
+       * ircd/m_links.c (m_links_redirect): forward-port RPL_ENDOFLINKS
+       change to make Khaled happy...
+
+       * ircd/m_whois.c (do_whois): pull-up of m_whois() fix
+       (do_whois): duh...
+
+2001-04-21  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/msgq.c: finally remove the msgq_integrity() hack, as it's
+       turned up no more bugs
+
+       * ircd/ircd.c: use /* */ comments instead of // comments--all the
+       world's not gcc :(
+
+       * ircd/s_conf.c (conf_add_server): use /* */ comments instead of
+       // comments--all the world's not gcc :(
+
+       * ircd/runmalloc.c: finally garbage-collect unused file
+
+       * include/runmalloc.h: finally garbage-collect unused file
+
+       * ircd/<multiple files>: addition of '#include "config.h"' before
+       all other includes in most .c files
+
+       * include/<multiple files>: remove includes of config.h, which are
+       now going into the raw .c files
+
+2001-04-20  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/m_whois.c (do_whois): display proper server name if the
+       user is looking up himself
+
+       * ircd/m_who.c (m_who): disable match by servername or display of
+       server names by non-opers
+
+       * include/ircd_policy.h: add define for
+       HEAD_IN_SAND_WHO_SERVERNAME to cover full intent of sub-motion 15
+       of CFV 165
+
+2001-04-18  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/s_conf.c: keep the $R in memory so we can see it clearly
+       when we do a /stats k
+
+       * ircd/s_user.c (set_user_mode): pull-up of changes to prevent
+       users from turning on +s and +g
+
+       * ircd/s_misc.c (exit_client): pull-up of changes to turn off
+       net.split notice
+
+       * ircd/parse.c: pull-up of changes to disable /trace, /links, and
+       /map for users
+
+       * ircd/m_whois.c (do_whois): pull-up of server name masking for
+       /whois
+
+       * ircd/m_user.c (m_user): removal of umode and snomask defaulting
+       functions, pull-up
+
+       * ircd/m_stats.c (m_stats): pull-up of stats-disabling stuff
+
+       * ircd/m_map.c (m_map_redirect): pull-up of m_map_redirect()
+
+       * ircd/m_links.c (m_links_redirect): pull-up of m_links_redirect()
+
+       * ircd/channel.c (channel_modes): pull-up of channel key display
+       as *
+
+       * include/ircd_policy.h: pull-up of ircd_policy.h
+
+       * include/client.h: pull-up of Set/ClearServNotice()
+
+       * ircd/gline.c (do_gline): report client name in G-line message
+       (pull-up)
+
+       * ircd/s_user.c (register_user): pull-up--show IP address in some
+       server notices dealing only with users; report which connection
+       class has filled up
+
+       * ircd/s_stats.c (report_deny_list): use conf->flags &
+       DENY_FLAGS_IP insteaf of conf->ip_kill
+
+       * ircd/m_stats.c (report_klines): use conf->flags & DENY_FLAGS_IP
+       insteaf of conf->ip_kill
+
+       * ircd/s_conf.c: use flags field in struct DenyConf; pull-up of
+       K-line by real name
+
+       * include/s_conf.h: use a flags field in struct DenyConf; define
+       DENY_FLAGS_FILE, DENY_FLAGS_IP, and DENY_FLAGS_REALNAME for
+       pull-up of K-line by real name
+
+       * ircd/m_trace.c: pull-up of IP show for user connections
+
+       * doc/example.conf: pull-up of the realname K-line documentation
+
+       * ircd/ircd.c: forward port of pid file advisory locking mechanism
+
+2001-04-16  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/send.c (sendcmdto_flag_butone): recast to just broadcast to
+       all servers, rather than to only servers that have +w/+g/whatever
+       users on them; among other things, this removes that atrocity
+       known as sentalong[] from this function
+
+       * ircd/m_admin.c: must include ircd.h to declare "me"; must
+       include hash.h to declare FindUser()
+
+       * ircd/m_wallusers.c: implementation of WALLUSERS
+
+       * ircd/m_desynch.c (ms_desynch): only send DESYNCHs to opers
+
+       * ircd/m_wallops.c: only send WALLOPS to opers
+
+       * ircd/parse.c: add WALLUSERS command to parser table
+
+       * include/handlers.h: declare wallusers handlers
+
+       * include/msg.h: add WALLUSERS command
+
+       * ircd/send.c (sendcmdto_flag_butone): if FLAGS_OPER is or'd with
+       flag, send only to appropriate opers
+
+2001-04-13  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/uping.c: refit to use the new events interface
+
+       * ircd/res.c: refit to use the new events interface
+
+       * ircd/ircd_events.c: create timer_chg(), which permits a
+       (non-periodic) timer's expire time to be modified; change the
+       logic in timer_run() so that timers that were re-added while the
+       event was being processed will not be destroyed prematurely
+
+       * include/uping.h: include the events header, declare some extra
+       fields in struct UPing, remove timeout value, and define some
+       flags for marking which cleanup items have yet to be done
+
+       * include/ircd_events.h: add a prototype for timer_chg() to change
+       the expire time of a running timer
+
+2001-03-13 Joseph Bongaarts <foxxe@wtfs.net>
+       * ircd/os_openbsd.c: Tweaked the openbsd hack a bit.
+       
+2001-03-07  Joseph Bongaarts  <foxxe@wtfs.net>
+
+       * config/configure.in: Add check for OpenBSD
+
+       * ircd/os_openbsd.c: Add seperate os dep file for openbsd which
+       differs from generic BSD, particularly in its handling of
+       _XOPEN_SOURCE.
+       
+2001-02-12  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/m_gline.c (ms_gline): propagate a G-line that happened to
+       have been added by a U-lined server, rather than going through the
+       activate/deactivate logic; propagate G-line removals by U-lined
+       servers as well
+
+       * ircd/gline.c: rename propagate_gline() to gline_propagate();
+       make gline_propagate() return an int 0 (convenience return); only
+       update lastmod in gline_activate() and gline_deactivate() if the
+       current lastmod is non-zero, since 0 lastmod is our flag of a
+       U-lined server having added a G-line
+
+       * include/gline.h (gline_propagate): exporting the G-line
+       propagation function
+
+       * ircd/m_list.c (m_list): duh; permit explicit channel name
+       specification only when /list gets two arguments ("Kev
+       #wasteland") rather than when /list gets more than two
+       arguments--nice braino
+
+2001-01-29  Thomas Helvey <twhelvey1@home.com>
+
+       * ircd/ircd_reply.c (need_more_params): fix bug that allowed
+       unregistered clients to spam opers with protocol violation
+       messages. Note: the bugfix may have eliminated some useful
+       protocol violation messages.
+       Please send protocol violation messages explicitly from the
+       functions they are discovered in, you have much better context
+       for the error there and it helps to document the behavior of the
+       server. This was also a design bug in that it violated the
+       "A function should do one thing" heuristic. Patching this one
+       would have resulted in a continuous spawning of other bugs over
+       the next 3 years, so I killed it. Check around for stuff this
+       broke and readd the calls to protocol_violation in the functions
+       that need to send the message.
+
+2001-01-29  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/channel.c (mode_parse_ban): stopper a tiny leak--if a ban
+       already existed, then the logic would (attempt to) skip it, but
+       would not free the ban string; now the ban string is free'd and
+       the ban count is decremented, releasing the ban for use
+
+       * ircd/s_user.c: make send_umode_out() take a prop argument
+       instead of testing for the PRIV_PROPAGATE privilege itself; fix
+       set_umode() to use this new argument, calculating it before
+       calculating the new privileges for a -o'd user
+
+       * ircd/m_oper.c (m_oper): pass the new prop argument to
+       send_umode_out()
+
+       * ircd/channel.c (mode_parse_ban): turn off MODE_ADD bit in bans
+       that we're not actually going to add because they already exist;
+       test that particular bit before adding to the linked list
+
+       * include/s_user.h: add a prop argument to send_umode_out() to
+       indicate whether or not to propagate the user mode
+
+2001-01-24  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/msgq.c: ircd_vsnprintf() returns the number of bytes that
+       it would have written; upper-bound the number to prevent overflows
+       by proxy; also, tune buffer size given to ircd_vsnprintf() to take
+       into account the fact that ircd_vsnprintf() already takes the
+       terminal \0 into account
+
+2001-01-22  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/msgq.c: add an incredibly ugly hack to attempt to track
+       down an apparent buffer overflow; remove msgq_map(), since it's no
+       longer used anywhere; slight tweaks to prevent off-by-one errors,
+       but these can't explain the problems we've seen
+
+       * include/msgq.h: remove msgq_map(), since it's no longer used
+       anywhere
+
+2001-01-18  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/s_user.c (set_nick_name): call client_set_privs() after
+       parsing user modes
+
+2001-01-17  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/s_bsd.c (read_message): fix a typo in the select version of
+       read_message()
+
+       * ircd/whowas.c (whowas_free): MyFree() is a macro that expects
+       its argument to be an lvalue, which means we can't use
+       whowas_clean()'s handy-dandy "return ww" feature
+
+       * ircd/ircd_features.c: default LOCOP_KILL to TRUE--oops...
+
+2001-01-16  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/ircd_events.c (timer_run): it's possible that the timer got
+       deleted during the callback processing, so don't go to the bother
+       of requeuing it if the destroy flag is set
+
+       * ircd/engine_select.c: define FD_SETSIZE to be IRCD_FD_SETSIZE
+       out of config.h if this is a *BSD; include errno.h (oops);
+       decrement error count after an hour using a timer; use FD_SETSIZE
+       constant instead of IRCD_FD_SETSIZE constant; fill in event
+       processing code
+
+       * ircd/engine_poll.c: include errno.h (oops); decrement error
+       count after an hour using a timer; fill in event processing code
+
+       * ircd/engine_kqueue.c: include errno.h (oops); decrement error
+       count after an hour using a timer; assert events filter is either
+       EVFILT_READ or EVFILT_WRITE; fill in event processing code
+
+       * ircd/engine_devpoll.c: include errno.h (oops); decrement error
+       count after an hour using a timer; fill in event processing code
+
+2001-01-15  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/client.c: fixed feattab; basically, when I changed features
+       to use small integers specifying bit positions, instead of the
+       bits themselves, I forgot to update feattab to not | these
+       privileges together; also fixed a bug in the antiprivs masking
+       loop in client_set_privs()--last index wouldn't get parsed
+
+2001-01-11  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/ircd_events.c: call event_generate() with new data
+       argument; make it set that field in struct Event; make
+       socket_add() return the value of the eng_add callback
+
+       * ircd/engine_select.c: make engine_add() return a
+       successful/unsuccessful status; add bounds-checking outside of an
+       assert; use accessor macros; use log_write(), not the deprecated
+       ircd_log(); add an assert to engine_loop() to double-check for
+       data structure corruption
+
+       * ircd/engine_poll.c: make engine_add() return a
+       successful/unsuccessful status; add bounds-checking outside of an
+       assert; use accessor macros; use log_write(), not the deprecated
+       ircd_log(); add an assert to engine_loop() to double-check for
+       data structure corruption
+
+       * ircd/engine_kqueue.c: implementation of an engine for kqueue()
+
+       * ircd/engine_devpoll.c: implementation of an engine for /dev/poll
+
+       * include/ircd_events.h: define some accessor macros; add ev_data
+       to struct Event for certain important data--errno values, for
+       instance; make EngineAdd callback tell us if it was successful or
+       not; add extra argument to event_generate(); make socket_add()
+       return the status from EngineAdd
+
+2001-01-10  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/ircd_events.c: pass initializer information about how many
+       total _filedescriptors_ may be opened at once
+
+       * ircd/ircd.c: use exported "running" instead of unexported
+       thisServer.running
+
+       * ircd/engine_select.c: implementation of an event engine based on
+       select()
+
+       * ircd/engine_poll.c: implementation of an event engine based on
+       poll()
+
+       * include/ircd_events.h: pass the engine initializer an integer
+       specifing how many _filedescriptors_ may be opened at once
+
+       * include/ircd.h: running has to be exported for the engine_*
+       event loops
+
+2001-01-09  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/ircd_events.c: include some needed headers; add some
+       comments; make evEngines[] const; bundle sig_sock and sig_fd into
+       a struct named sigInfo; rework struct evInfo to have a queue of
+       _generators_, and only when threaded; added a gen_init() function
+       to centralize generator initialization; fix various compile-time
+       errors; rework event_add() for new queueing scheme and checked for
+       compile-time errors; add casts where needed; spell evEngines[]
+       correctly; make engine_name() return const char*
+
+       * include/ircd_events.h: type EventCallBack depends on struct
+       Event, so pre-declare it; put _event_ queue into generators, and
+       only when threaded; give engine data a union to store both ints
+       and pointers; make engine name a const; fix gen_ref_dec() macro;
+       make engine_name() return a const char*
+
+       * ircd/ircd_events.c: gen_dequeue() is now exported, so move it
+       down with the non-static functions; modify event_execute() to use
+       the new gen_ref_dec() to simplify code; make sure event_generate()
+       does not generate new events for generators marked for destruction
+
+       * include/ircd_events.h: the engines, at least, may need to modify
+       reference counts to keep generators from going away while
+       something still points at them, so add reference counter
+       manipulators and export gen_dequeue() for them
+
+       * ircd/ircd_events.c: set up the list of engines to try; set up
+       the signal struct Socket; rename netInfo to evInfo; move static
+       functions near the beginning of the file; do away with
+       signal_signal() (since we no longer keep a signal count ourselves)
+       and call event_generate() directly from signal_callback--also
+       renamed some functions; allow signal_callback() to read up to
+       SIGS_PER_SOCK at once from the signal pipe; add event_init() to
+       initialize the entire event system; add event_loop() to call the
+       engine's event loop; initialize new struct GenHeader member,
+       gh_engdata; remove timer_next(); add socket_add() function to add
+       a socket; add socket_del() to mark a socket for deletion; add
+       socket_state() to transition a socket between states; add
+       socket_events() to set what events we're interested in on the
+       socket; add engine_name() to retrieve event engine's name
+
+       * include/ircd_events.h: add engine data field to struct
+       GenHeader; rename SOCK_ACTION_REMOVE to SOCK_ACTION_DEL; add a
+       note about states vs s_events; remove signal count; fold union
+       Generator back into struct Event; remove count members from struct
+       Generators; redefine engine callbacks to not take a struct
+       Engine*; add explanatory comments to callback definitions; add
+       some engine callbacks to handle operations; remove struct Engine
+       flag member--can detect single flag from eng_signal member; add
+       event_init(), event_loop(), engine_name(), and the socket_*()
+       functions; make timer_next() a macro to avoid a function call
+
+2001-01-08  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * include/ircd_events.h: rename to ircd_events.h, since it handles
+       events, not just networking stuff; add signal support; more
+       structural rearrangement
+
+       * ircd/ircd_events.c: rename to ircd_events.c, since it handles
+       events, not just networking stuff; add signal support; more
+       structural rearrangement
+
+2001-01-07  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/ircd_network.c: implement timer API; add reference counts
+       appropriately
+
+       * include/ircd_network.h: firm up some pieces of the interface;
+       split out members everything has into a separate structure; add
+       reference counts; add timer API
+
+2001-01-06  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/ircd_network.c: static data and event manipulation
+       functions for new event processing system
+
+       * include/ircd_network.h: data structures for new event processing
+       system
+
+2001-01-03  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/whowas.c: Completely re-did the old allocation scheme by
+       turning it into a linked list, permitting the
+       NICKNAMEHISTORYLENGTH feature to be changed on the fly
+
+       * ircd/s_debug.c (count_memory): use FEAT_NICKNAMEHISTORYLENGTH
+       feature instead of old #define
+
+       * ircd/ircd_features.c: add NICKNAMEHISTORYLENGTH feature as an
+       integer feature with a notify callback (whowas_realloc)
+
+       * ircd/client.c (client_set_privs): second memset was supposed to
+       be over antiprivs, not privs; thanks, Chris Behrens
+       <cbehrens@xo.com> for pointing that out...
+
+       * include/whowas.h: new elements for an extra linked list in
+       struct Whowas; a notify function for feature value changes
+
+       * include/ircd_features.h: new feature--FEAT_NICKNAMEHISTORYLENGTH
+
+       * config/config-sh.in: NICKNAMEHISTORYLENGTH is now a feature
+
+2001-01-02  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * config/config-sh.in: get rid of DEFAULT_LIST_PARAMETER
+       compile-time option--now in features subsystem
+
+       * ircd/motd.c (motd_init): rework motd_init() to be called as the
+       notify function for MPATH and RPATH features (should probably
+       split it up a bit, though...)
+
+       * ircd/m_privs.c (mo_privs): if called with no parameters, return
+       privs of the caller, rather than an error
+
+       * ircd/m_list.c: pull usage message into its own function; pull
+       list parameter processing into its own function that does not
+       modify the contents of the parameter; add list_set_default() to
+       set the default list parameter (uses the notify hook); rework
+       m_list() to make use of these functions; removed dead code
+
+       * ircd/ircd_log.c (log_feature_mark): make sure to return 0, since
+       we have no notify handler
+
+       * ircd/ircd_features.c: add notify callback for notification of
+       value changes; give mark callback an int return value to indicate
+       whether or not to call the notify callback; fix up feature macros
+       for new notify callback; add DEFAULT_LIST_PARAM feature; rewrite
+       string handling in feature_set() to deal with def_str being a null
+       pointer; wrote feature_init() to set up all defaults appropriately
+
+       * ircd/ircd.c (main): call feature_init() instead of
+       feature_mark(), to avoid calling notify functions while setting up
+       defaults
+
+       * ircd/client.c: updated to deal with new privileges structure
+
+       * ircd/class.c: updated so init_class() can be called should one
+       of PINGFREQUENCY, CONNECTFREQUENCY, MAXIMUM_LINKS, or
+       DEFAULTMAXSENDQLENGTH be changed
+
+       * include/ircd_log.h: log_feature_mark() updated to fit with new
+       API changes
+
+       * include/ircd_features.h: added DEFAULT_LIST_PARAM feature and
+       feature_init() function (found necessary since adding the notify
+       stuff and notifying motd.c during start-up...before we defined
+       RPATH!)
+
+       * include/client.h: move privs around to enable addition of more
+       bits if necessary; based on the FD_* macros
+
+       * include/channel.h: declare list_set_default (actually located in
+       m_list.c *blanche*)
+
+       * ircd/s_user.c: retrieve MAXSILES and MAXSILELENGTH (now
+       AVBANLEN*MAXSILES) from features subsystem
+
+       * ircd/s_debug.c (debug_serveropts): CMDLINE_CONFIG doesn't go to
+       anything anymore
+
+       * ircd/s_bsd.c: retrieve HANGONGOODLINK and HANGONRETRYDELAY from
+       the features subsystem
+
+       * ircd/s_auth.c (start_auth): NODNS migrated to the features
+       subsystem
+
+       * ircd/random.c: created random_seed_set() function to set seed
+       value, along with some stuff to make ircrandom() a little more
+       random--state preserving, xor of time instead of direct usage,
+       etc.; it's still a pseudo-random number generator, though, and
+       hopefully I haven't broken the randomness
+
+       * ircd/m_version.c: FEATUREVALUES makes use of feature_int() calls
+
+       * ircd/m_join.c: use features interface to retrieve
+       MAXCHANNELSPERUSER
+
+       * ircd/ircd_features.c: add NODISP flag for super-secret features;
+       add a whole bunch of new features migrated over from make config
+
+       * ircd/ircd.c: use features interface to retrieve PINGFREQUENCY,
+       CONNECTTIMEOUT, and TIMESEC
+
+       * ircd/client.c (client_get_ping): use features interface to
+       retrieve PINGFREQUENCY
+
+       * ircd/class.c: use features interface to retrieve PINGFREQUENCY,
+       CONNECTFREQUENCY, MAXIMUM_LINKS, and DEFAULTMAXSENDQLENGTH
+
+       * ircd/chkconf.c (DEFAULTMAXSENDQLENGTH): since it's now in the
+       features subsystem, we have to add something explicit
+
+       * ircd/channel.c: use features interface to retrieve
+       KILLCHASETIMELIMIT, MAXBANLENGTH, MAXBANS, and MAXCHANNELSPERUSER;
+       note that MAXBANLENGTH is now calculated dynamically from MAXBANS
+       and AVBANLEN
+
+       * ircd/Makefile.in: run make depend
+
+       * include/supported.h (FEATURESVALUES): update to reference
+       feature settings
+
+       * include/random.h: add prototype for random_seed_set
+
+       * include/ircd_features.h: add several more features
+
+       * include/channel.h: move MAXBANS and MAXBANLENGTH into feature
+       subsystem
+
+       * config/config-sh.in: feature-ized some more stuff
+
+       * include/motd.h: some new elements in motd.h for motd.c changes
+
+       * ircd/motd.c: motd_cache() now searches a list of already cached
+       MOTD files; saves us from having duplicate caches in memory if
+       there are two identical T-lines for two different sites...
+
+2001-01-02  Perry Lorier <isomer@coders.net>
+       * ircd/motd.c: don't core if the motd isn't found.  Bug found by
+       Amarande.
+
+2001-01-02  Perry Lorier <isomer@coders.net>
+       * ircd/s_err.c: Added third param to 004 - the channel modes that tage params.  Used by hybrid/epic.
+       * ircd/s_channels.c: Added fix for msg'ing a -n+m channel - thanks
+               to guppy for noticing, and hektik for providing the fix.
+       * misc others: Minor cleanups, added more protocol_violations, ripped
+               out more P09 stuffs, bit more protocol neg stuff.
+
+2000-12-19  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/m_ison.c (m_ison): Dianora says that ISON has to end with a
+       space (*sigh* stupid clients...)
+
+       * ircd/s_user.c: make WALLOPS_OPER_ONLY a feature managed through
+       ircd_features.[ch]
+
+       * ircd/s_err.c: get rid of GODMODE conditionals
+
+       * ircd/s_debug.c (debug_serveropts): switch to using appropriate
+       calls into the features subsystem for various serveropts
+       characters
+
+       * ircd/s_conf.c (find_conf_entry): get rid of USEONE conditional
+
+       * ircd/s_bsd.c: remove GODMODE conditional; use features subsystem
+       to get value of VIRTUAL_HOST and CLIENT_FLOOD; remove
+       NOFLOWCONTROL conditional
+
+       * ircd/s_auth.c: use features subsystem to determine value of
+       KILL_IPMISMATCH
+
+       * ircd/parse.c: get rid of NOOPER and GODMODE conditionals; use
+       features subsystem to determine the setting of IDLE_FROM_MSG
+
+       * ircd/numnicks.c: get rid of EXTENDED_NUMERICS conditionals
+
+       * ircd/motd.c: get value of NODEFAULTMOTD from features subsystem;
+       use features subsystem to get motd file names
+
+       * ircd/m_settime.c: get value of RELIABLE_CLOCK from features
+       subsystem
+
+       * ircd/m_server.c: get rid of CRYPT_LINK_PASSWORD, since it does
+       us no good; use features subsystem to figure out if we need to do
+       HUB-type stuff; make TESTNET debugging sendto_opmask_butone's use
+       the Debug(()) macro instead; get value of RELIABLE_CLOCK from
+       features subsystem
+
+       * ircd/m_privmsg.c: get IDLE_FROM_MSG from the features subsystem
+
+       * ircd/m_oper.c: get CRYPT_OPER_PASSWORD from the features
+       subsystem
+
+       * ircd/m_connect.c: get SERVER_PORT from the features subsystem
+
+       * ircd/ircd_log.c (log_set_file): fix a bug that kept log files
+       from getting marked if they were already set to something...
+
+       * ircd/ircd_features.c: add a flag to indicates read-only access;
+       add several new features that used to be compile-time selected
+
+       * ircd/ircd.c: grab pidfile out of feature subsystem; don't check
+       access to motd files (what the heck?); make sure to initialize the
+       feature subsystem before trying to write the config file
+
+       * ircd/dbuf.c: use feature_int() to retrieve BUFFERPOOL settings;
+       use feature_bool() to figure out if we're using the FERGUSON
+       flusher
+
+       * ircd/Makefile.in: MPATH and RPATH are now done differently, so
+       remove the clause that creates empty files of that name; also ran
+       make depend
+
+       * include/sys.h: CLIENT_FLOOD is now a feature; unfortunately,
+       there is no easy way to bounds-check it at present
+
+       * include/querycmds.h: make sure ircd_features.h is included; use
+       feature_str(FEAT_DOMAINNAME) in calls to match()
+
+       * include/ircd_features.h: many new features that used to be
+       compile-time selected
+
+       * config/config-sh.in: add * to DOMAINNAME; try also using first
+       argument to search in /etc/resolv.conf; removed many compile-time
+       options that now can be configured through the features system
+
+2000-12-18  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * doc/api/log.txt: how to use the logging API
+
+       * doc/api/features.txt: how to use the features API
+
+       * doc/api/api.txt: how to write API documentation
+
+       * include/ircd_features.h: rearranged a couple of features for
+       neatness purposes
+
+       * ircd/ircd_features.c: cleaned up the macros some; rearranged
+       some code to all go into the switch; rearranged a couple of
+       features for neatness purposes
+
+2000-12-16  Greg Sikorski <gte@atomicrevs.demon.co.uk>
+       * ircd/os_bsd.c: Added os_set_tos for BSD users.
+
+2000-12-16  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/ircd_features.c: Isomer almost got it right; you need to
+       use F_I(), since it's an integer value, not a boolean value.  The
+       asserts in feature_int would catch you out...  Also made the F_*
+       macros take flags
+
+       * ircd/s_err.c: define RPL_PRIVS reply
+
+       * ircd/parse.c: put new PRIVS command into command table
+
+       * ircd/m_privs.c (mo_privs): message handler to report operator
+       privileges
+
+       * ircd/ircd_features.c: declare new features OPER_SET and
+       LOCOP_SET; redo boolean testing routine to accept TRUE, YES, and
+       ON for boolean TRUE, and FALSE, NO, and OFF for boolean FALSE
+
+       * ircd/client.c: simplify client_set_privs() with a table that
+       defines what features to test for; add new client_report_privs()
+
+       * ircd/Makefile.in: compile new m_privs.c; run make depend
+
+       * include/numeric.h (RPL_PRIVS): new reply numeric for displaying
+       an operator's privileges
+
+       * include/msg.h: define new command: PRIVS
+
+       * include/ircd_features.h: create new features OPER_SET and
+       LOCOP_SET for controlling access to /set
+
+       * include/handlers.h (mo_privs): declare message handler for
+       reporting oper privileges
+
+       * include/client.h (client_report_privs): declare function to
+       report what privileges an oper has
+
+       * ircd/m_whois.c (do_whois): fix a bug that caused /whois to
+       report that a user is an oper if the oper doing the /whois had
+       PRIV_SEE_OPERS
+
+2000-12-17  Isomer <Isomer@coders.net>
+       * ircd/listener.c: added support for TOS twiddling as a 'feature'.
+
+2000-12-17  Isomer <Isomer@coders.net>
+       * ircd/os_linux.c: add TOS stuffs
+
+       * ircd/listener.c: add TOS stuffs
+
+2000-12-16  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/whocmds.c (do_who): use HasPriv to determine whether or not
+       to indicate a user is an oper
+
+       * ircd/s_user.c: clear privileges setting when deopping; don't
+       propagate +o unless user has PRIV_PROPAGATE privilege
+
+       * ircd/s_debug.c (debug_serveropts): created debug_serveropts()
+       function and replaced how the server option string is generated
+
+       * ircd/parse.c: remove conditional on CONFIG_OPERCMDS
+
+       * ircd/m_whois.c (do_whois): use HasPriv to determine whether or
+       not to indicate the user is an operator
+
+       * ircd/m_who.c: use HasPriv to determine whether or not a user
+       should be displayed in the list of opers
+
+       * ircd/m_version.c: call debug_serveropts() to get server option
+       string
+
+       * ircd/m_userip.c (userip_formatter): use HasPriv to determine
+       whether or not to show oper status
+
+       * ircd/m_userhost.c (userhost_formatter): use HasPriv to determine
+       whether or not to show oper status
+
+       * ircd/m_restart.c (mo_restart): replace ugly #ifdef conditional
+       checks with HasPriv check; remove dead code
+
+       * ircd/m_rehash.c (mo_rehash): replace ugly #ifdef conditional
+       checks with HasPriv check
+
+       * ircd/m_opmode.c (mo_opmode): use HasPriv to check permissions;
+       use feature_bool to check if disabled
+
+       * ircd/m_oper.c (m_oper): set oper priviliges
+
+       * ircd/m_mode.c (m_mode): replace #ifdef conditional with HasPriv
+       check
+
+       * ircd/m_kill.c (mo_kill): use HasPriv checks to determine if we
+       can kill
+
+       * ircd/m_kick.c (m_kick): replace #ifdef conditional with HasPriv
+       check
+
+       * ircd/m_jupe.c (mo_jupe): rework permissions checking structure;
+       use feature_bool to check if disabled
+
+       * ircd/m_join.c (m_join): remove BADCHAN conditional; replace
+       #ifdef conditional with a HasPriv check
+
+       * ircd/m_gline.c (mo_gline): rework permissions checking
+       structure; use feature_bool to check if any part is disabled
+
+       * ircd/m_die.c: replace ugly #ifdef conditionals with HasPriv
+       check; remove dead code
+
+       * ircd/m_clearmode.c: use feature_bool() to detect if we're
+       disabled; use HasPriv to figure out what we're permitted to do;
+       only allow clearmode on moded channels
+
+       * ircd/ircd_features.c: define various features; use HasPriv to
+       verify permissions to set/reset
+
+       * ircd/gline.c (gline_add): use HasPriv instead of #ifdef
+       conditionals
+
+       * ircd/client.c (client_set_privs): function to set an oper's
+       privileges
+
+       * ircd/channel.c: use HasPriv calls instead of #ifdef conditionals
+
+       * include/whocmds.h: deconditionalize several macros and
+       substitute appropriate calls to HasPriv()
+
+       * include/s_debug.h: get rid of global serveropts[]; define new
+       function debug_serveropts() to build that string on the fly
+
+       * include/ircd_features.h: define some features
+
+       * include/client.h: add privs member to struct Connection; define
+       various priviledges
+
+       * include/channel.h: no longer using IsOperOnLocalChannel; remove
+       conditional of MAGIC_OPER_OVERRIDE on OPER_WALK_THROUGH_LMODES
+
+       * doc/Configure.help: remove help information for deprecated
+       options
+
+       * config/config-sh.in: remove certain deprecated options having to
+       do with what opers can and cannot do--first stage in moving
+       compile-time constants into the .conf
+
+2000-12-16  Isomer <Isomer@coders.net>
+       * ircd/parse.c: detect if the prefix is missing and try and recover
+       instead of coring.
+
+2000-12-15  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/ircd_log.c: found and fixed some bugs in the debug logging
+       code that would sometimes result in the log file not being
+       reopened--which meant that a user could connect and get the
+       logging output--oops
+
+       * ircd/Makefile.in: run make depend...
+
+       * ircd/s_stats.c: get rid of report_feature_list()
+
+       * ircd/s_err.c: add the 'bad value' error message, shift error
+       messages over somewhat
+
+       * ircd/s_debug.c (debug_init): call log_debug_init with the
+       use_tty flag
+
+       * ircd/s_conf.c (read_configuration_file): unmark features before
+       reading the config file, then reset unmarked features after
+       reading the config file
+
+       * ircd/m_stats.c: use feature_report() instead of
+       report_feature_list()
+
+       * ircd/ircd_log.c: fix log_debug_file (bogus assertion); add
+       special 'mark' flags and use them; add the stuff needed by the
+       features API
+
+       * ircd/ircd_features.c: rework the features API and add gobs of
+       comments to try to explain what some of these complex functions
+       are actually doing
+
+       * include/s_stats.h: get rid of report_feature_list(); use
+       feature_report() instead
+
+       * include/numeric.h: added a new error message and shifted old
+       values over some--this is, after all, an alpha
+
+       * include/ircd_log.h: log_debug_init now takes an integer to tell
+       it if it should be using the tty; added a couple of functions
+       required by the features API
+
+       * include/ircd_features.h: add an enum and some more functions to
+       flesh out the feature API--it should now be possible to put all
+       those compile-time constants in the config file!
+
+       * ircd/send.c: got the direction of the assert incorrect...
+
+       * ircd/send.c: implement the efficiency of flush_connections by
+       creating a linked list of struct Connection's with queued data;
+       also get rid of flush_sendq_except and make sure to yank
+       connections out of the list when their sendQs become empty (notice
+       the assertion in flush_connections!)
+
+       * ircd/s_bsd.c (close_connection): must yank the Connection out of
+       the sendq list
+
+       * ircd/list.c (dealloc_connection): must yank the Connection out
+       of the sendq list
+
+       * ircd/dbuf.c (dbuf_put): call flush_connections instead of the
+       deprecated flush_sendq_except
+
+       * ircd/client.c: define a couple new helper functions for sendq
+       threading--this will make the flush_connections function in send.c
+       considerably more efficient by creating a linked list of
+       Connections that have queued data to send
+
+       * include/send.h: remove flush_sendq_except, as it's not used
+       anymore
+
+       * include/client.h: declare a couple new helper functions for the
+       sendq threading system
+
+2000-12-14  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/m_ison.c (m_ison): Apply Diane Bruce's patch to make ISON
+       parse all arguments
+
+       * ircd/s_debug.c (count_memory): modify to report for clients and
+       connections, not local clients and remote clients
+
+       * ircd/list.c: fiddle with the client-fiddling functions to take
+       into account the divorce of struct Connection from struct Client
+
+       * ircd/ircd.c: define a struct Connection for me, initialize it,
+       and link it into the right place (ewww, globals!)
+
+       * include/client.h: remove CLIENT_{LOCAL,REMOTE}_SIZE; split
+       struct Client into struct Client and struct Connection; redefine
+       local-portion accessor macros to go through struct Client to the
+       struct Connection; define struct Connection accessor macros
+
+2000-12-13  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/whowas.c: missed a couple of accesses to a struct Client
+
+       * ircd/uping.c: missed a couple of accesses to a struct Client
+
+       * ircd/send.c: missed a couple of accesses to a struct Client
+
+       * ircd/s_user.c: missed a couple of accesses to a struct Client
+
+       * ircd/s_misc.c: missed a couple of accesses to a struct Client
+
+       * ircd/s_conf.c: missed a couple of accesses to a struct Client
+
+       * ircd/s_bsd.c: missed a couple of accesses to a struct Client
+
+       * ircd/s_auth.c: missed a couple of accesses to a struct Client
+
+       * ircd/res.c: missed a couple of accesses to a struct Client
+
+       * ircd/parse.c: missed a couple of accesses to a struct Client
+
+       * ircd/m_whois.c: use new accessor macros for struct Client
+
+       * ircd/m_who.c: use new accessor macros for struct Client
+
+       * ircd/m_wallchops.c: use new accessor macros for struct Client
+
+       * ircd/m_version.c: use new accessor macros for struct Client
+
+       * ircd/m_userip.c: use new accessor macros for struct Client
+
+       * ircd/m_userhost.c: use new accessor macros for struct Client
+
+       * ircd/m_user.c: use new accessor macros for struct Client
+
+       * ircd/m_uping.c: use new accessor macros for struct Client
+
+       * ircd/m_trace.c: use new accessor macros for struct Client
+
+       * ircd/m_topic.c: use new accessor macros for struct Client
+
+       * ircd/m_time.c: use new accessor macros for struct Client
+
+       * ircd/m_stats.c: use new accessor macros for struct Client
+
+       * ircd/m_squit.c: use new accessor macros for struct Client
+
+       * ircd/m_silence.c: use new accessor macros for struct Client
+
+       * ircd/m_server.c: use new accessor macros for struct Client;
+       remove dead code
+
+       * ircd/m_rpong.c: use new accessor macros for struct Client
+
+       * ircd/m_rping.c: use new accessor macros for struct Client
+
+       * ircd/m_quit.c: use new accessor macros for struct Client
+
+       * ircd/m_privmsg.c: use new accessor macros for struct Client
+
+       * ircd/m_pong.c: use new accessor macros for struct Client; remove
+       dead code
+
+       * ircd/m_ping.c: use new accessor macros for struct Client
+
+       * ircd/m_pass.c: use new accessor macros for struct Client
+
+       * ircd/m_part.c: use new accessor macros for struct Client
+
+       * ircd/m_oper.c: use new accessor macros for struct Client
+
+       * ircd/m_notice.c: use new accessor macros for struct Client
+
+       * ircd/m_nick.c: use new accessor macros for struct Client
+
+       * ircd/m_names.c: use new accessor macros for struct Client
+
+       * ircd/m_mode.c: use new accessor macros for struct Client
+
+       * ircd/m_map.c: use new accessor macros for struct Client
+
+       * ircd/m_list.c: use new accessor macros for struct Client
+
+       * ircd/m_links.c: use new accessor macros for struct Client;
+       remove some dead code
+
+       * ircd/m_kill.c: use new accessor macros for struct Client; remove
+       some dead code
+
+       * ircd/m_kick.c: use new accessor macros for struct Client
+
+       * ircd/m_join.c: use new accessor macros for struct Client; remove
+       some dead code
+
+       * ircd/m_ison.c: use new accessor macros for struct Client
+
+       * ircd/m_invite.c: use new accessor macros for struct Client
+
+       * ircd/m_info.c: use new accessor macros for struct Client
+
+       * ircd/m_gline.c: use new accessor macros for struct Client
+
+       * ircd/m_error.c: use new accessor macros for struct Client
+
+       * ircd/m_create.c: use new accessor macros for struct Client
+
+       * ircd/m_connect.c: use new accessor macros for struct Client;
+       removed some dead code
+
+       * ircd/m_burst.c: use new accessor macros for struct Client
+
+       * ircd/m_away.c: use new accessor macros for struct Client
+
+       * ircd/m_admin.c: use new accessor macros for struct Client
+
+       * ircd/hash.c: missed a couple of accesses to a struct Client
+
+       * ircd/gline.c: missed a couple of accesses to a struct Client
+
+       * ircd/crule.c: missed a couple of accesses to a struct Client
+
+       * ircd/class.c: missed an access to a struct Client
+
+       * ircd/channel.c: missed a couple of accesses to a struct Client
+
+       * ircd/IPcheck.c: missed an access to a struct Client
+
+       * include/querycmds.h: fix a couple of stats macros to use
+       structure accessor macros
+
+       * include/client.h: change structure member names to highlight any
+       places in the code I've missed
+
+2000-12-12  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/whowas.c: use new struct Client accessor macros
+
+       * ircd/whocmds.c: use new struct Client accessor macros
+
+       * ircd/send.c: use new struct Client accessor macros
+
+       * ircd/s_user.c: use new struct Client accessor macros; removed
+       some dead code
+
+       * ircd/s_serv.c: use new struct Client accessor macros; removed
+       some dead code
+
+       * ircd/s_numeric.c: use new struct Client accessor macros
+
+       * ircd/s_misc.c: use new struct Client accessor macros
+
+       * ircd/s_debug.c: use new struct Client accessor macros
+
+       * ircd/s_conf.c: use new struct Client accessor macros
+
+       * ircd/s_bsd.c: use new struct Client accessor macros
+
+       * ircd/s_auth.c: use new struct Client accessor macros
+
+       * ircd/parse.c: use new struct Client accessor macros
+
+       * ircd/packet.c: use new struct Client accessor macros
+
+       * ircd/numnicks.c: use new struct Client accessor macros
+
+       * ircd/motd.c: use new struct Client accessor macros
+
+       * ircd/listener.c: use new struct Client accessor macros
+
+       * ircd/list.c: use new struct Client accessor macros
+
+       * ircd/jupe.c: use new struct Client accessor macros
+
+       * ircd/ircd_snprintf.c: use new struct Client accessor macros
+
+       * ircd/ircd_reply.c: use new struct Client accessor macros
+
+       * ircd/ircd_relay.c: use new struct Client accessor macros
+
+       * ircd/ircd.c: use new struct Client accessor macros
+
+       * ircd/gline.c: catch some instances of me.<stuff> I missed
+       previously
+
+       * ircd/client.c: use cli_ instead of con_
+
+       * ircd/class.c: use cli_ instead of con_
+
+       * ircd/channel.c: use cli_ instead of con_
+
+       * ircd/IPcheck.c: use cli_ instead of con_; catch some instances
+       of me.<stuff> I missed previously
+
+       * include/client.h: use cli_ instead of con_...seemed like a good
+       idea at the time *shrug*
+
+2000-12-11  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/hash.c: use struct Client accessor macros
+
+       * ircd/gline.c: use struct Client accessor macros
+
+       * ircd/crule.c: use struct Client accessor macros
+
+       * ircd/client.c: use struct Client accessor macros; remove some
+       dead code
+
+       * ircd/class.c: use struct Client accessor macros
+
+       * ircd/channel.c: use struct Client accessor macros; remove some
+       dead code
+
+       * ircd/IPcheck.c: use struct Client accessor macros
+
+       * include/numnicks.h: use struct Client accessor macros
+
+       * include/client.h: first step to divorcing struct Client and
+       struct Connection--define accessor macros and use them
+
+       * ircd/gline.c: When Uworld removed Uworld-set G-lines, only the
+       uplink would remove them.  This is because the removal protocol
+       message wasn't being sent to the uplinks.  This is fixed by fixing
+       propagate_gline() to send the proper number of arguments depending
+       on whether or not we're adding or deleting the Uworld gline, and
+       by having gline_deactivate() make sure to turn off the active bit
+       and call propagate_gline() if it's a Uworld gline
+
+2000-12-10  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/os_generic.c: make sure IOV_MAX gets defined, just in case
+
+       * ircd/os_bsd.c: apparently BSD doesn't have IOV_MAX defined
+       anywhere intelligent...
+
+2000-12-09  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/send.c (send_queued): call deliver_it with appropriate
+       arguments
+
+       * ircd/s_serv.c: reorder a couple of headers--cosmetic
+
+       * ircd/s_bsd.c (deliver_it): make deliver_it work with a struct
+       MsgQ
+
+       * ircd/os_solaris.c (os_sendv_nonb): function for calling writev
+       with appropriate iovec
+
+       * ircd/os_linux.c (os_sendv_nonb): function for calling writev
+       with appropriate iovec
+
+       * ircd/os_generic.c (os_sendv_nonb): function for calling writev
+       with appropriate iovec
+
+       * ircd/os_bsd.c (os_sendv_nonb): function for calling writev with
+       appropriate iovec
+
+       * ircd/msgq.c (msgq_mapiov): add a len_p argument for totalling up
+       exactly how much we're trying to write out to the fd
+
+       * include/s_bsd.h: make deliver_it take a struct MsgQ
+
+       * include/msgq.h: add a len_p argument to msgq_mapiov to help
+       detect short writes that indicate possible socket blocking
+
+       * include/ircd_osdep.h: declare os_sendv_nonb()
+
+       * ircd/channel.c (modebuf_mode): don't add empty modes...
+
+2000-12-08  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * include/send.h: add prio argument to send_buffer to select
+       between normal and priority queues
+
+       * ircd/s_user.c (send_user_info): add prio argument to send_buffer
+       call
+
+       * ircd/m_ison.c (m_ison): add prio argument to send_buffer call
+
+       * ircd/ircd_reply.c (send_reply): add prio argument to send_buffer
+       call
+
+       * ircd/channel.c (send_channel_modes): add prio argument to
+       send_buffer call
+
+       * ircd/send.c (send_buffer): add a prio argument to select the
+       priority queue; update send.c functions to use it
+
+       * ircd/msgq.c (msgq_add): remove msgq_prio; fold msgq_link and
+       msgq_add; add a prio argument to msgq_add to select the priority
+       queue
+
+       * include/msgq.h: remove msgq_prio; add a prio argument to
+       msgq_add
+
+       * ircd/send.c: remove sendbuf; remove GODMODE code; switch to
+       using msgq functions instead of dbuf functions; remove old, dead
+       sendto_* functions; redo send_buffer to take a struct MsgBuf;
+       rework sendcmdto_* functions to make use of the new struct MsgBuf
+
+       * ircd/s_user.c: remove hunt_server; restructure send_user_info to
+       make appropriate use of struct MsgBuf
+
+       * ircd/s_debug.c (count_memory): count memory used by the MsgQ
+       system and report it
+
+       * ircd/s_conf.c (read_configuration_file): use
+       sendto_opmask_butone instead of the now dead sendto_op_mask
+
+       * ircd/s_bsd.c: switch to using appropriate MsgQLength and other
+       calls on sendQ
+
+       * ircd/parse.c (parse_server): get rid of a piece of GODMODE code
+
+       * ircd/msgq.c: add msgq_append and msgq_bufleft; fix a bug in
+       msgq_clean
+
+       * ircd/m_version.c: fix spelling in comments marking dead code
+
+       * ircd/m_userip.c (userip_formatter): restructure to make use of
+       struct MsgBuf
+
+       * ircd/m_userhost.c (userhost_formatter): restructure to make use
+       of struct MsgBuf
+
+       * ircd/m_stats.c: use MsgQLength on a sendQ
+
+       * ircd/m_settime.c: use MsgQLength instead of DBufLength on a
+       sendQ; mark a piece of dead code
+
+       * ircd/m_names.c: use send_reply instead of sendto_one
+
+       * ircd/m_mode.c: use new mode; remove old dead code
+
+       * ircd/m_ison.c (m_ison): restructure to make use of struct MsgBuf
+
+       * ircd/m_burst.c: use BUFSIZE instead of IRC_BUFSIZE; remove old
+       dead code
+
+       * ircd/listener.c (accept_connection): use sendto_opmask_butone
+       instead of sendto_op_mask
+
+       * ircd/list.c (free_client): use MsgQClear to clear sendQ
+
+       * ircd/ircd_reply.c: remove send_error_to_client; restructure
+       send_reply to make use of struct MsgBuf
+
+       * ircd/dbuf.c (dbuf_put): remove argument to flush_sendq_except,
+       since its no longer used (at least currently)
+
+       * ircd/channel.c: restructure send_channel_modes to make use of
+       struct MsgBuf; remove set_mode, add_token_to_sendbuf, cancel_mode,
+       and send_hack_notice; use BUFSIZE instead of IRC_BUFSIZE
+
+       * ircd/Makefile.in: add msgq.c to list of sources; run make depend
+
+       * ircd/IPcheck.c: use sendcmdto_one instead of sendto_one
+
+       * include/send.h: send_buffer now takes a struct MsgBuf * instead
+       of a char *; flush_sendq_except now takes no arguments, as sendq
+       flushing currently only happens in dbuf.h and sendQ is a struct
+       MsgQ; remove prototypes for a lot of old sendto_* functions that
+       aren't used anymore; remove sendbuf and IRC_BUFSIZE--the former is
+       no longer needed, and the latter is identical to BUFSIZE in
+       ircd_defs.h
+
+       * include/s_user.h: make InfoFormatter take a struct MsgBuf*
+       instead of a char *; also make it return void, instead of char *
+
+       * include/msgq.h: add msgq_append and msgq_bufleft functions
+
+       * include/client.h: use a struct MsgQ instead of a struct DBuf for
+       sendq
+
+       * doc/Configure.help: Remove help for compile-time options that
+       have gone away
+
+       * config/config-sh.in: remove CONFIG_NEWMODE
+
+       * ircd/m_server.c (mr_server): don't send server IPs in any server
+       notices
+
+       * ircd/msgq.c (msgq_vmake): add \r\n to messages
+
+2000-12-07  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * include/msgq.h: declare the MsgQ API
+
+       * ircd/msgq.c: implementation of new MsgQ system
+
+2000-12-06  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/ircd_features.c: #include was supposed to be for
+         ircd_features.h, not features.h--missed when I had to do a
+         rename because of namespace collision
+
+2000-12-05  Greg Sikorski <gte@atomicrevs.demon.co.uk>
+       * ircd/m_topic.c: Added missing braces that caused all remote
+         topics to be ignored.
+
+2000-12-04  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/m_create.c: I'm tired of the exit_client warning :)
+       (ms_create): discovered that exit_client() was being called with
+       too few arguments
+
+       * ircd/s_misc.c (exit_client): remove all dependance on
+       FNAME_USERLOG, since that's now gone; log only to LS_USER
+
+       * ircd/s_debug.c: USE_SYSLOG no longer means anything
+
+       * ircd/m_oper.c (m_oper): no longer log to LS_OPERLOG--we already
+       log to LS_OPER
+
+       * ircd/m_kill.c: no longer conditionalize on SYSLOG_KILL
+
+       * ircd/ircd_log.c: remove LS_OPERLOG, LS_USERLOG
+
+       * include/ircd_log.h: remove LS_OPERLOG, LS_USERLOG--they serve
+       the same purpose as LS_USER and LS_OPER
+
+       * config/config-sh.in: remove no longer relevant log config
+       variables
+
+       * ircd/uping.c (uping_init): use log_write instead of ircd_log
+
+       * ircd/s_misc.c (exit_client): use log_write instead of ircd_log
+
+       * ircd/s_conf.c: use log_write instead of ircd_log
+
+       * ircd/s_bsd.c (report_error): use log_write instead of ircd_log
+
+       * ircd/s_auth.c (timeout_auth_queries): use log_write instead of
+       ircd_log
+
+       * ircd/res.c (send_res_msg): use log_write instead of ircd_log
+
+       * ircd/m_who.c: use log_write instead of write_log; no longer
+       conditionalize on WPATH; mark dead ircd_log calls
+
+       * ircd/m_uping.c: mark dead ircd_log call
+
+       * ircd/m_server.c (mr_server): use log_write instead of ircd_log
+
+       * ircd/m_restart.c: use log_write instead of ircd_log; mark dead
+       ircd_log calls
+
+       * ircd/m_rehash.c (mo_rehash): use log_write instead of ircd_log
+
+       * ircd/m_oper.c: use log_write instead of ircd_log; no longer
+       conditionalize on FNAME_OPERLOG; mark dead ircd_log calls
+
+       * ircd/m_kill.c: mark dead ircd_log calls
+
+       * ircd/m_connect.c: use log_write instead of ircd_log; mark dead
+       ircd_log
+
+       * ircd/m_clearmode.c: use log_write instead of write_log; no
+       longer conditionalize on OPATH
+
+       * ircd/jupe.c: use log_write instead of write_log; no longer
+       conditionalize on JPATH
+
+       * ircd/ircd_log.c: add USER subsystem; remove ircd_log() compat
+       function; fix a couple of bugs
+
+       * ircd/ircd_alloc.c: fixed a comment
+
+       * ircd/ircd.c: use log_write instead of ircd_log; fold server
+       notice generation in a couple of cases
+
+       * ircd/gline.c: use log_write instead of write_log; no longer
+       conditionalize on GPATH
+
+       * ircd/channel.c (modebuf_flush_int): use log_write instead of
+       write_log; no longer conditionalize on OPATH
+
+       * ircd/Makefile.in: run make depend, since dependencies have
+       changed
+
+       * doc/example.conf: add system USER to documentation
+
+       * include/ircd_log.h: add system USER; remove old ircd_log()
+       declarations
+
+2000-12-04  Isomer <isomer@coders.net>
+       * ircd/m_names.c: Add NAMES_EON to do_names to say add a
+       'end_of_names' reply when done.
+       * ircd/m_join.c: use NAMES_EON as mentioned above
+
+2000-12-01  net  <simms@LUCIDA.QC.CA>
+
+       * ircd/motd.c: add a freelist for struct Motds
+
+2000-11-30  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/s_stats.c (report_feature_list): report features--only
+       local opers can see logging configuration, since it doesn't really
+       mean anything to users
+
+       * ircd/s_err.c: add reply messages for new feature subsystem
+
+       * ircd/s_conf.c: add F lines to .conf
+
+       * ircd/parse.c: add the message descriptions for /set, /reset, and
+       /get
+
+       * ircd/m_stats.c: add /stats f
+
+       * ircd/m_set.c (mo_set): implement /set
+
+       * ircd/m_reset.c (mo_reset): implement /reset
+
+       * ircd/m_rehash.c: /rehash m now flushes MOTD cache, and /rehash l
+       reopens log files (for log file rotation)
+
+       * ircd/m_get.c (mo_get): implement /get
+
+       * ircd/ircd_log.c: use int instead of void return value; add
+       log_report_features() and log_canon(); fix a function that
+       disappears if DEBUGMODE not #define'd
+
+       * ircd/ircd_features.c: functions to manipulate feature settings
+       either from the config file or with the new /set, /reset, and /get
+       commands
+
+       * ircd/Makefile.in: add new .c files, run make depend
+
+       * include/s_stats.h: declare report_feature_list() (/stats f
+       handler)
+
+       * include/numeric.h: add RPL_STATSFLINE, RPL_FEATURE,
+       ERR_NOFEATURE, ERR_BADLOGTYPE, ERR_BADLOGSYS, and ERR_BADLOGVALUE
+       reply numerics
+
+       * include/msg.h: add defines for SET, RESET, and GET
+
+       * include/ircd_log.h: add a function to canonicalize subsystem
+       names; change some void return values to int
+
+       * include/ircd_features.h: new features subsystem handles all the
+       manipulation of special features, like log files
+
+       * include/handlers.h: declare new mo_{s,res,g}et message handlers
+       for fiddling with features run-time
+
+       * include/client.h (SNO_DEFAULT): don't set SNO_DEBUG by default;
+       seemed like a good idea at the time...
+
+       * doc/example.conf: document new F lines
+
+2000-11-29  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/s_debug.c: rewrite debug_init() and vdebug() in terms of
+       new logging functions, which have special support for the debug
+       log; added loop detection to vdebug(), so that I can
+       sendto_opmask_butone() from log_vwrite() without incurring another
+       call to vdebug()
+
+       * ircd/s_conf.c (rehash): call log_reopen() from rehash routine;
+       this allows log file rotations
+
+       * ircd/m_kill.c: call log_write_kill() instead of ircd_log_kill()
+
+       * ircd/ircd_log.c: much more work fleshing out the interface;
+       removed old interface; included backwards-compat ircd_log()
+       function that logs to subsystem LS_OLDLOG
+
+       * ircd/ircd.c: switch to new log_init()/log_close()/log_reopen()
+       functions
+
+       * include/ircd_log.h: include stdarg.h for va_list; move ordering
+       warning to top of file; fill out LogSys enum; declare new
+       log_debug_init(), log_vwrite(), log_write_kill(), and
+       log_[sg]et_*() functions; add flags argument to log_write();
+       defined flags to inhibit various logging actions
+
+       * include/client.h: added support for new SNO_DEBUG, enabled only
+       if DEBUGMODE is defined
+
+2000-11-28  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/ircd_log.c: make sure the various LOG_* constants are
+       defined (probably not needed, since #include <syslog.h> isn't
+       conditional); various static data needed for the new logging
+       functions; definitions of new logging functions
+
+       * include/ircd_log.h: new LogSys enum, declarations for part of
+       new logging API
+
+       * ircd/motd.c: we were setting type to MOTD_CLASS unconditionally,
+       which was of course stupid; switched to using switch/case in
+       initialization in motd_create(); zero the MotdList.other pointer
+       from motd_clear()
+
+       * ircd/ircd.c (main): motd_init() has to come before init_conf(),
+       or we overwrite init_conf()'s hard work with respect to T-lines
+
+2000-11-27  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/s_stats.c: comment out report_motd_list and include a
+       reference to motd_report()
+
+       * ircd/s_conf.c: rip out the old MOTD manipulation functions; call
+       motd_add() from the conf parser; call motd_clear() from the rehash
+       routine; remove the no longer needed memory clearing and reloading
+       stuff from the rehash service routine
+
+       * ircd/motd.c: loads new API, including static internal functions
+       to do allocation/deallocation, etc.
+
+       * ircd/m_stats.c: use new motd_report() instead of
+       report_motd_list()
+
+       * ircd/m_motd.c: use new syntax for motd_send()
+
+       * ircd/ircd.c: use new motd_init() function
+
+       * ircd/Makefile.in (SRC): forgot to add motd.c to SRC in
+       Makefile.(in); also ran make depend
+
+       * include/motd.h: don't need config.h, but now do need time.h;
+       define new structures and constants; redefine old API and define
+       new functions
+
+2000-11-22  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/s_user.c (register_user): use motd_signon() instead of
+       calling m_motd; much cleaner this way
+
+       * ircd/motd.c: write the new motd_* stuff to make MOTD handling
+       less of a crock
+
+       * ircd/m_motd.c: rewrite m{,s}_motd to call out to new motd_*
+       functions
+
+       * include/motd.h: define new MOTD API stuff
+
+2000-11-20  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/ircd_reply.c (protocol_violation): rewrite
+       protocol_violation so it'll actually work
+
+       oh, yeah, use %s -> cptr->name, instead of %c -> cptr, so we get
+       the client's real name in there.
+
+       * ircd/m_motd.c (m_motd): Iso's addition of get_client_class(sptr)
+       resulted in core dumps if NODEFAULTMOTD is defined, because m_motd
+       gets called from register_user with a NULL sptr.  This is probably
+       a design problem, but this bandaid will do for now...
+
+2000-11-19  Isomer <isomer@coders.net>
+       * ircd/ircd_reply.c: added 'protocol_violation', thus alerting us
+       to problems in the server<->server protocol.
+
+       * ircd/m_connect.c: allow remote connects with a port of '0'
+       meaning to use the port in the config file.
+
+       * ircd/m_create.c: Enable hacking protection, lets see how far we
+       get.
+
+       * ircd/m_error.c: The RFC says never accept ERROR from unreg'd
+       clients, so we don't any more.
+
+       * ircd/m_kill.c: The kill path is now made up of numnicks of servers,
+       and the user@host is displayed of the victim.
+
+       * ircd/m_map.c: reloaded 'dump_map'.
+
+       * ircd/m_trace.c: allow per class T:
+
+       * ircd/m_stats.c: allow local opers /remote stats anywhere on the 'net.
+
+2000-11-17  Isomer <isomer@coders.net>
+
+       * ircd/m_topic.c: Fixed bug where we'd only send to clients topics
+       that were the *same* instead of different.  Oh the embarrasment!
+
+       * ircd/IPcheck.c: Merged net's fix.
+
+2000-11-02  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/m_whois.c: remove compiler warning by adding a newline to
+       end of file
+
+       * ircd/m_names.c: moved the flags up to s_user.h
+
+       * ircd/m_join.c: call do_names instead of m_names; restructure
+       ms_join to never transmute a JOIN into a CREATE, but use the TS in
+       the JOIN (if present) to timestamp the channel
+
+       * ircd/channel.c: send JOINs individually, instead of grouping
+       them, so that we can send the channel's creation time
+
+       * include/s_user.h: declare do_names()
+
+2000-10-30  Isomer <isomer@coders.net>
+       * ircd/m_oper.c: Fixed warning
+
+2000-10-30  Isomer <isomer@coders.net>
+       * ircd/m_oper.c: Fixed over agressive cut and no paste
+
+2000-10-30  Isomer <isomer@coders.net>
+
+       * ircd/m_topic.c: Restructured, fixed bug where topics on local
+       channels are propergated (I forget who pointed this out to me, but
+       thanks anyway).  Also to save bandwidth don't send the topic to
+       users if the topic is already the same on the server (but still
+       propergate to other servers).  X/W's "autotopic" feature must
+       chew a lot of bandwidth, hopefully this will help reduce this.
+
+       * doc/rfc1459.rfc: Updated documentation on /topic.
+
+       * ircd/listener.c: snotice warnings about failed accept()'s
+       potentially warning admins that they're running out of fd's.
+
+       * ircd/stats.c, ircd/class.c: Removed /stats v, added number of
+       people in a class in /stats y
+
+       * ircd/m_create.c: Checks for timewarp hacking and squit's
+       evil servers. (currently disabled)
+       
+
+2000-10-30  net <simms@lucida.qc.ca>
+       
+       * ircd/gline.c: Fixed various bugs Isomer left behind.
+
+2000-10-26  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/m_join.c (m_join): reply on attempt to join a BADCHANed
+       channel is now ERR_BANNEDFROMCHAN instead of ERR_BADCHANNAME
+
+2000-10-24  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/channel.c: ok, now last mode rules; mode +ps will always
+       result in +s (and won't send a mode if the channel is already +s);
+       mode +sp will always result in +p; -n+n on a +n channel results in
+       no mode change; -n+n on a -n channel results in a +n mode change;
+       etc.
+
+2000-10-23  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/channel.c: add "add" and "del" elements to ParseState to
+       avoid not-too-pretty -p+s when +s is sufficient; fix a bug in
+       mode_parse_limit that caused it to clear all channel modes
+       prematurely; restructure mode_parse_mode to avoid calling
+       modebuf_mode too early (ties in with first mentioned change);
+       better logic for +p/+s mutual exclusivity; initialize "add" and
+       "del" elements in mode_parse; send simple modes down to
+       modebuf_mode after the loop in mode_parse
+
+2000-09-28  Greg Sikorski <gte@atomicrevs.demon.co.uk>
+       * ircd/m_names.c: Fixed a non-lethal logic error that 
+       triggers an assert() in find_member_link while debugging.
+       (Spotted by Maniac-).
+2000-09-19  Thomas Helvey <helveytw@home.com>
+       * ircd/s_conf.c: move K:lines to their own list and data
+       structures, add supporting code.
+       * ircd/m_stats.c: cleanup stats processing a bit move
+       kline listing code to a new function, haven't figured
+       out where it goes yet tho'
+       * ircd/s_stats.c: added K:line bulk lister
+       * include/s_conf.h: added new DenyConf struct
+       * *[ch]: fixeup code that depended on changes
+
+2000-09-17  Thomas Helvey <helveytw@home.com>
+       * ircd/class.c: encapsulate class list
+       * include/class.h: clean up classes
+       * * fixup code that depended on changes
+
+2000-09-17  Thomas Helvey <helveytw@home.com>
+       * ircd/s_conf.c: add me to local conf
+       * include/s_conf.h: move CONF_ME macro to chkconf.c
+       * ircd/s_bsd.c: cleanup initialization, allow virtual host
+       to be changed by rehash
+
+2000-09-17  Thomas Helvey <helveytw@home.com>
+       * include/class.h: add missing prototype
+       * ircd/class.c: make argument to get_conf_class const
+
+2000-09-17  Thomas Helvey <helveytw@home.com>
+       * ircd/*.c: merged in changes from 2.10.10.pl12, cleanup
+       merge conflicts.
+       * ircd/*.h: merged in changes from 2.10.10.pl12, cleanup
+       merge conflicts
+
+2000-09-16  Thomas Helvey <helveytw@home.com>
+       * ircd/s_conf.c: add code for server struct
+       * ircd/client.c: copy of class.c sort of, new file for client
+       specific operations, will move things here as appropriate,
+       currently only one function is exported from here.
+       * ircd/*.c: general logic cleanups, convert negatives to
+       positives in places.
+
+2000-09-16  Thomas Helvey <helveytw@home.com>
+       * ircd/s_conf.c: add code for new crule data structs, strip quotes
+       * ircd/crule.c: clean up scary casting a bit, type safety stuff
+       * include/s_conf.h: add CRuleConf struct and support, remove
+       unused constants
+       * include/crule.h: type safety cleanups
+       * ircd/*.c: fixup code that depended on stuff I changed
+
+2000-09-15  Thomas Helvey <helveytw@home.com>
+       * ircd/s_conf.c: start adding code for new conf data structs, changed
+       listeners, admin line, motd lines, class lines. Move validate_hostent
+       to resolver. General mayhem.
+       * include/s_conf.h: new data structs and accessors
+       * ircd/res.c: move validate_hostent here, rewrite, use regular
+       expression for validation.
+       * doc/example.conf: update docs for port
+
+2000-09-14  Thomas Helvey <helveytw@home.com>
+       * ircd/s_conf.c (conf_init): rewrite conf file parser, start to break
+       up conf_init into managable chunks.
+       * ircd/listener.c (set_listener_mask): fix logic bug core dump.
+       * include/s_conf.h: add new data struct for local info (unwinding the mess).
+
+2000-09-13  Thomas Helvey <helveytw@home.com>
+       * ircd/list.c: put Clients in free lists, pre-allocate MAXCONNECTIONS
+       local clients.
+       * ircd/list.c: put SLinks in free lists
+       * ircd/channel.c: put Memberships in free lists
+       * ircd/ircd.c: rearrange initializations a bit in main
+       Note: With these changes, ircd NEVER frees Clients, SLinks or
+       Memberships. It will also rarely need to allocate new
+       ones during net bursts and other disruptions. This should
+       cut down on memory fragmentation a bit as well.
+
+2000-08-30  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/m_names.c (do_names): pull-up from do_names fix in
+       u2.10.10.pl11
+
+2000-07-15  Perry Lorier       <Isomer@coders.net>
+       * various: IP only k:'s and G:'s now do bit tests instead of two(!) 
+                 match()'s.  Major Major cpu savings.  Also speed up the
+                 other case slightly.  As a side effect you can now
+                k/Gline *@10.0.0.0/8.  I'll do bans tomorrow, it's nearing
+                3am.
+
+2000-07-15  Perry Lorier       <Isomer@coders.net>
+       * various: Fixed warnings after compiling on an alpha.
+2000-07-09  Perry Lorier       <Isomer@coders.net>
+       * doc/ircd.8: Applied grammitical changes by Liandrin, applied
+                     changes suggested by various other people.
+       * ircd/IPcheck.c: More bug fixes.  Current problem appears to be
+                       that it gets a corrupt entry somehow.
+2000-07-09  Greg Sikorski <gte@atomicrevs.demon.co.uk>
+       * ircd/m_oper.c: Clean up compiler warning.
+
+2000-07-08  Perry Lorier       <Isomer@coders.net>
+       * doc/ircd.8: Updated the documentation, it was slightly out of date
+                     being updated around 1989.
+       * ircd/m_whois.c: Rewrote for clarity, and probably a bit more speed.
+                         fixed a few minor glitches.
+       * doc/rfc1459.unet: Updated.
+       * ircd/IPcheck.c: Fixed more bugs.
+       * ircd/s_bsd.c: We now keep track of servers we've conected.
+
+2000-07-02  Perry Lorier       <Isomer@coders.net>
+       * ircd/s_misc.c: Fixed remote IPcheck bug.  Ok, I'm a moron, so sue
+                       me.  Thanks to Hektik, thanks thanks thanks thanks
+                       thanks thanks thanks thanks thank thanks thank thanks
+
+2000-07-01  Perry Lorier       <Isomer@coders.net>
+       * ircd/s_conf.c: "Fixed" the "bug" where people would "evade" K:'s.
+       * ircd/s_conf.c, include/IPcheck.h: Fixed compile warnings.
+
+2000-06-22  Perry Lorier       <Isomer@coders.net>
+       * ircd/IPcheck.c: Large chunks redone.
+       * ircd/s_conf.c: Changes due to IPcheck - ONE nolonger supported,
+                       single AND double digit limits are allowed now.
+       * misc other: Changes to IPcheck.
+
+2000-06-30  Perry Lorier       <Isomer@coders.net>
+       * ircd/ircd.c: Fix command line parameter bugs.
+
+2000-06-30  Perry Lorier       <Isomer@coders.net>
+       * ircd/m_kill.c: Fixed bug with LOCAL_KILL_ONLY
+       * ircd/m_nick.c: Tidied things up.
+
+2000-06-12 Joseph Bongaarts <foxxe@trms.com>
+       * ircd/m_stats.c: Iso forgot mo_stats when he added /stats v
+       
+2000-05-29  Perry Lorier       <Isomer@coders.net>
+       * ircd/m_stats.c: add /stats v to do only the last part of the /trace
+       * ircd/IPcheck.c: Cosmetic change, if we meddle with it enough do
+                       you think it'll get bored and fix itself?
+
+2000-06-09  Greg Sikorski <gte@atomicrevs.demon.co.uk>
+
+       * ircd/m_names.c: Clean up compiler warnings.
+
+2000-06-09  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/channel.c (mode_parse_client): don't send warning if
+       there's not enough arguments for a +/-o/v; means the habit of
+       doing "/mode #channel +oooooo bob" doesn't result in a bunch of
+       error messages
+
+2000-06-04  Greg Sikorski <gte@atomicrevs.demon.co.uk>
+
+       * ircd/m_names.c: Re-factor code to remove unneccessary
+       GlobalChannelList iteration every time someone joins a channel.
+
+2000-06-02  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/s_user.c: add struct Gline * argument to register_user;
+       look up global glines and repropagate them if necessary; send
+       acknowledgement of gline to remote servers when registering users
+
+       * ircd/s_serv.c (server_estab): don't send acknowledgement of
+       local glines to remote servers; do send gline acknowledgement of
+       bursted users
+
+       * ircd/m_user.c (m_user): pass new struct Gline * argument to
+       register_user
+
+       * ircd/m_pong.c: pass new struct Gline * argument to register_user
+
+       * ircd/m_nick.c (ms_nick): document protocol change
+
+       * ircd/gline.c: support GLINE_LASTMOD
+
+       * include/s_user.h: add struct Gline * argument to register_user
+
+       * include/gline.h: add GLINE_LASTMOD to look up non-zero lastmods
+
+       * ircd/s_conf.c (find_kill): add unsigned int argument to
+       gline_lookup()
+
+       * ircd/gline.c: add GLINE_GLOBAL to lookup or find only global
+       glines; add unsigned int argument to gline_lookup()
+
+       * include/gline.h: add GLINE_GLOBAL flag; add unsigned int
+       argument to gline_lookup()
+
+       * ircd/m_server.c: Resend jupe only when there is no %<lastmod>
+       parameter, or when it falls out of bounds: see comments prior to
+       call to jupe_resend(); call server_estab with struct Jupe
+       parameter, so that we place the appropriate %<lastmod> in the
+       appropriate place.
+
+       * ircd/s_serv.c (server_estab): send %<lastmod> for introduced
+       server, as well as for servers when we're sending the BURST
+
+       * include/s_serv.h: add a struct Jupe * to the arguments for
+       server_estab() so that we can send the appropriate lastmod
+       parameter
+
+       * ircd/m_gline.c (ms_gline): actually, this should be the
+       slightest bit more efficient...
+
+       * ircd/m_jupe.c (ms_jupe): actually, this should be the slightest
+       bit more efficient...
+
+       * ircd/m_gline.c (ms_gline): inhibit GLINE processing resends
+       during netburst
+
+       * ircd/m_jupe.c (ms_jupe): inhibit JUPE processing resends during
+       netburst
+
+       * ircd/channel.c (joinbuf_join): really remove user from local
+       channels
+
+2000-05-29  Perry Lorier       <Isomer@coders.net>
+       * ircd/m_names.c: Removed redundant space. 
+       * ircd/s_bsd.c: Fixed incorrect syntax on ERROR line.
+
+2000-05-18  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/m_burst.c (ms_burst): er...that should have been a ",", not
+       a " "
+
+2000-05-04  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/channel.c: replace bogus assertions with returns, which is
+       logically correct; only wipe out limit/key if they were originally
+       set in the first place; remove user from channel when doing a
+       PARTALL; only send MODE +o for user CREATEing channel if user is
+       not MyUser--CREATE will only be used if the channel did not
+       originally exist, therefore we can assume no one local is on the
+       channel anyway, and we don't exactly need for the user to see an
+       explicit +o for themselves
+
+       * doc/readme.gline: describe the syntax of the GLINE command
+
+       * doc/readme.jupe: update to reflect a couple of changes to JUPE
+
+       * ircd/gline.c: don't propagate local changes
+
+       * ircd/jupe.c: don't propagate local changes
+
+       * ircd/m_gline.c (mo_gline): force local flag when deactivating
+       glines with 0 lastmod
+
+       * ircd/gline.c (gline_deactivate): G-lines with zero lastmod time
+       are now removed instead of being deactivated
+
+       * ircd/m_gline.c (ms_gline): make G-lines of the form "GLINE *
+       -<mask>" be accepted
+
+       * ircd/channel.c (send_channel_modes): deal with one of the last
+       vestiges of sendbuf
+
+       * ircd/m_burst.c (ms_burst): debugged ban processing; removed
+       debugging hooks
+
+       * ircd/channel.c (modebuf_extract): remove debugging
+       sendto_opmask_butone calls
+
+2000-05-03  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/channel.c: support a couple of new flags to support using
+       mode_parse; fix some bugs with 0 struct ModeBuf *; implementation
+       of modebuf_extract to extract added flags for use by ms_burst
+
+       * include/channel.h: a couple of new flags to support using
+       mode_parse inside ms_burst
+
+       * ircd/m_burst.c (ms_burst): brand new implementation of BURST
+
+       * ircd/m_endburst.c: add loop to processing of end_of_burst to
+       free empty channels after the BURST is over.
+
+       * ircd/m_server.c: convert to use new send.c functions--I wanted
+       to rewrite it from scratch, but the logic's pretty complex; I may
+       still rewrite it, though...
+
+2000-05-02  Thomas Helvey <tomh@inxpress.net>
+
+       * ircd/ircd.c: fix broken header include ordering
+
+2000-05-02  Thomas Helvey <tomh@inxpress.net>
+       
+       * ircd/IPcheck.c: cleanups for ZenShadow's cleanups
+        review emailed privately
+
+       * include/IPcheck.h: removed unneeded include
+
+2000-05-02  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/s_user.c (hunt_server): throw in a comment so I know what
+       the sendto_one is for
+
+       * include/querycmds.h (Count_unknownbecomesclient): convert to
+       sendto_opmask_butone
+
+       * ircd/send.c: start removing dead code
+
+       * include/send.h: start removing dead code
+
+       * ircd/m_rping.c: convert to sendcmdto_one / send_reply /
+       hunt_server_cmd
+
+       * ircd/m_rpong.c: convert to sendcmdto_one / send_reply
+
+2000-05-01  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/m_stats.c: convert to sendcmdto_one / send_reply
+
+       * ircd/m_kick.c: Completely reimplement m_kick
+
+       * ircd/channel.c: send_user_joins removed; it was dead code,
+       anyway...
+
+2000-05-01  Perry Lorier <isomer@coders.net>
+       * ircd/m_invite.c: Fix for the rest of m_invite.c, and again.
+       * ircd/channels.c: My fix for the part problem.  Untested, probably
+               won't work.  Can't be much worse than the current problem.
+               it'll either work or core, take your pick.
+
+
+2000-04-30  Perry Lorier <isomer@coders.net>
+       * config/config-sh.in: Fix for CONNEXIT
+       * ircd/s_{user,misc}.c: Fix for CONNEXIT
+       * ircd/m_invite.c: Fix for incorrectly numnickified invite.
+                       (Kev: Want to come talk to me about this?)
+
+2000-04-30  Steven M. Doyle <steven@doyle.net>
+       * ircd/ircd.c
+         - general cleanups and readability enhancements
+         - rewrite of setuid/chroot code.
+         - server will no longer run as root
+         - -DPROFIL compile option removed
+         - Fixed IPcheck API calls
+       * config/config-sh.in
+         - Fixed up chroot compile options
+         - Added options for debug and profile compiles
+       * config/gen.ircd.Makefile
+         - Support for new debug/profile options
+       * ircd/Makefile.in
+         - Support for new debug/profile options
+       * ircd/ircd_signal.c
+         - Removed -DPROFIL
+
+       * include/IPcheck.h
+         - Removed old API prototypes, added new ones
+       
+       * ircd/IPcheck.c
+         - Readability cleanups (well, I -think-...)
+         - Changed IPRegistryEntry.last_connect to a time_t.  The previously
+           used unsigned short was probably causing interesting things after
+           a client had been connected longer than about 65,535 seconds...
+         - Removed old API functions.
+
+       * ircd/whocmds.c
+         - Removed IPcheck.h include
+       
+       * Additionally modified IPcheck API calls in:
+         - ircd/m_nick.c
+         - ircd/m_auth.c
+         - ircd/s_bsd.c
+         - ircd/s_conf.c
+         - ircd/s_misc.c
+         - ircd/s_serv.c
+         - ircd/s_user.c
+       
+       
+2000-04-30  Perry Lorier <isomer@coders.net>
+       * ircd/s_bsd.c: Sigh. :)
+        * ircd/m_mode.c: fix for modeless channels by poptix.
+
+2000-04-29  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/m_join.c: reimplement JOIN in terms of struct JoinBuf
+
+       * ircd/channel.c (clean_channelname): make clean_channelname also
+       truncate long channel names
+
+2000-04-28  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/m_create.c: reimplement CREATE in terms of struct JoinBuf
+
+       * ircd/channel.c: implemented joinbuf_init, joinbuf_join,
+       joinbuf_flush
+
+       * include/channel.h: definitions and declarations for the struct
+       JoinBuf abstraction
+
+2000-04-29  Perry Lorier <isomer@coders.net>
+       * ircd/s_bsd.c: Ok, so I thought I compiled and tested this...
+
+2000-04-29  Perry Lorier <isomer@coders.net>
+       * ircd/s_bsd.c: Add debugging code to IPcheck
+
+2000-04-28  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * include/ircd_reply.h (SND_EXPLICIT): use instead of RPL_EXPLICIT
+
+       * ircd/ircd_reply.c (send_reply): use SND_EXPLICIT instead of
+       RPL_EXPLICIT
+
+       * ircd/m_userhost.c (m_userhost): add a dead code comment
+
+       * ircd/m_desynch.c: forgot one...
+
+       * ircd/m_rehash.c (mo_rehash): er, duplicates :)
+
+       * ircd/m_proto.c (proto_send_supported): just change a comment so
+       it doesn't show up in my scans
+
+       * ircd/ircd_reply.c (send_reply): fix a slight bug...
+
+       * ircd/s_numeric.c (do_numeric): use new sendcmdto_* functions,
+       kinda hackish...
+
+       * ircd/parse.c (parse_server): argument wrangling to make
+       processing in do_numeric a little easier to deal with
+
+       * ircd/s_serv.c (server_estab): SERVER should come from
+       acptr->serv->up, not &me
+
+       * ircd/m_lusers.c: accidentally left out sptr for a %C
+
+       * ircd/send.c: hack to support doing wallchops...
+
+       * ircd/m_whowas.c: convert to new send functions
+
+       * ircd/m_whois.c: convert to new send functions
+
+       * ircd/m_who.c: convert to new send functions
+
+       * ircd/m_wallops.c: convert to new send functions
+
+       * ircd/m_wallchops.c: convert to new send functions
+
+       * ircd/m_version.c: convert to new send functions
+
+       * ircd/m_userip.c: convert to new send functions
+
+       * ircd/m_userhost.c: convert to new send functions
+
+       * ircd/m_uping.c: convert to new send functions
+
+       * ircd/m_trace.c: convert to new send functions
+
+       * ircd/m_topic.c: convert to new send functions
+
+       * ircd/m_time.c: convert to new send functions
+
+       * ircd/m_squit.c: convert to new send functions
+
+       * ircd/m_silence.c: convert to new send functions
+
+       * ircd/m_settime.c: convert to new send functions
+
+       * ircd/m_restart.c: convert to new send functions
+
+       * ircd/m_rehash.c: convert to new send functions
+
+       * ircd/m_privmsg.c: convert to new send functions
+
+       * ircd/m_pong.c: convert to new send functions
+
+       * ircd/m_ping.c: convert to new send functions
+
+       * ircd/m_pass.c: convert to new send functions
+
+       * ircd/m_opmode.c: convert to new send functions
+
+       * ircd/m_oper.c: convert to new send functions
+
+       * ircd/m_notice.c: convert to new send functions
+
+       * ircd/m_nick.c: convert to new send functions
+
+       * ircd/m_names.c: convert to new send functions
+
+       * ircd/m_motd.c: convert to new send functions
+
+       * ircd/m_mode.c: convert to new send functions
+
+       * ircd/m_map.c: convert to new send functions
+
+       * ircd/m_lusers.c: convert to new send functions
+
+       * ircd/m_list.c: convert to new send functions
+
+       * ircd/m_links.c: convert to new send functions
+
+       * ircd/m_kill.c: convert to new send functions
+
+       * ircd/m_jupe.c: convert to new send functions
+
+       * ircd/m_invite.c: convert to new send functions
+
+       * ircd/m_info.c: convert to new send functions
+
+       * ircd/m_help.c: convert to new send functions
+
+       * ircd/m_gline.c: convert to new send functions
+
+       * ircd/m_error.c: convert to new send functions
+
+       * ircd/m_endburst.c: convert to new send functions
+
+       * ircd/m_die.c: convert to new send functions
+
+       * ircd/m_destruct.c: convert to new send functions
+
+       * ircd/m_defaults.c: convert to new send functions
+
+       * ircd/m_connect.c: convert to new send functions
+
+2000-04-28  Perry Lorier <isomer@coders.net>
+       * RELEASE.NOTES: Describe a few more undocumented features.
+       * config/config-sh.in: change the default paths for logging
+       and the recommended number of channels.
+       * include/supported.h: Rearrange slightly, added CHANTYPE's
+
+2000-04-27  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/m_close.c: convert to send_reply
+
+       * ircd/m_clearmode.c: convert to send_reply, sendcmdto_serv_butone
+
+       * ircd/m_away.c: convert to send_reply and sendcmdto_serv_butone
+
+       * ircd/m_admin.c: convert to send_reply and hunt_server_cmd
+
+       * ircd/s_user.c (hunt_server_cmd): new hunt_server replacement
+       that takes cmd and tok arguments, etc.  NOTE: THIS IMPLEMENTATION
+       HAS A MAJOR HACK!!!  The whole hunt_server architecture should be
+       carefully rethought...
+
+       * ircd/s_stats.c (hunt_stats): use new hunt_server_cmd
+
+       * include/s_user.h: hunt_server_cmd -- replacement for hunt_server
+
+       * ircd/s_misc.c: *sigh* 2.10.10 doesn't support squitting by
+       numeric nick; therefore, we have to use the server name
+
+       * ircd/m_squit.c (ms_squit): allow to squit by server numeric nick
+
+       * ircd/send.c: fix minor bugs
+
+       * ircd/s_user.c (check_target_limit): mark dead code so I filter
+       it when I grep
+
+       * ircd/s_serv.c (exit_new_server): mark dead code so I filter it
+       when I grep
+
+       * ircd/parse.c: mark dead code so I filter it when I grep
+
+       * ircd/map.c: mark dead code so I filter it when I grep
+
+       * ircd/ircd.c: mark dead code so I filter it when I grep
+
+       * ircd/ircd_relay.c: convert over to new sendcmdto_*, send_reply
+       functions
+
+       * ircd/channel.c: mark dead code so I filter it when I grep
+
+       * ircd/s_stats.c: use send_reply instead of sendto_one w/rpl_str;
+       hope I'm not stepping on toes...
+
+       * ircd/s_conf.c: more sendto_opmask_butone / send_reply
+       conversions; use ircd_snprintf in a couple of cases to negate the
+       possibility of buffer overflow
+
+2000-04-26  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/channel.c: convert as much as possible to new send
+       semantics
+
+       * ircd/send.c (sendcmdto_common_channels): fix a subtle bug --
+       test member->user->from->fd, not from->fd
+
+       * ircd/gline.c (gline_add): go ahead and add badchans; we just
+       won't look for them in m_gline; this way, they always work...
+
+       * ircd/jupe.c: use ircd_vsnprintf conversion specifiers
+
+       * ircd/gline.c: since write_log now uses ircd_vsnprintf, use
+       ircd_vsnprintf conversion specifiers
+
+       * ircd/support.c (write_log): use ircd_vsnprintf for write_log, so
+       I have my conversion specifiers
+
+       * ircd/gline.c (do_gline): use send_reply for ERR_YOUREBANNEDCREEP
+
+       * ircd/send.c (sendcmdto_flag_butone): explicitly send WALLOPS to
+       local users
+
+       * ircd/s_serv.c (exit_new_server): rewrite exit_new_server to be a
+       little less brain-dead
+
+       * ircd/s_misc.c: use sendcmdto_one, sendrawto_one, and send_reply
+
+       * ircd/s_debug.c: use send_reply with RPL_EXPLICIT for
+       RPL_STATSDEBUG
+
+       * ircd/res.c (cres_mem): use send_reply with RPL_EXPLICIT for
+       RPL_STATSDEBUG
+
+       * ircd/list.c (send_listinfo): use send_reply with RPL_EXPLICIT
+       for RPL_STATSDEBUG
+
+       * ircd/m_pong.c: use RPL_EXPLICIT for ERR_BADPING
+
+       * ircd/ircd.c: use RPL_EXPLICIT for ERR_BADPING
+
+       * ircd/s_user.c (register_user): use RPL_EXPLICIT for
+       ERR_INVALIDUSERNAME
+
+       * ircd/ircd_reply.c (send_reply): support RPL_EXPLICIT
+
+       * include/ircd_reply.h (RPL_EXPLICIT): somewhat of a hack to mark
+       a numeric as needing to use an explicit pattern, which will be the
+       first argument in the variable argument list
+
+       * ircd/s_user.c: use sendrawto_one instead of sendto_one to send
+       non-prefixed nospoof PING
+
+       * ircd/s_bsd.c: use sendrawto_one instead of sendto_one to send
+       non-prefixed SERVER login
+
+       * ircd/ircd.c (check_pings): fix last sendto_one calls (except for
+       a numeric usage further up)
+
+       * include/send.h: declare sendrawto_one
+
+       * ircd/send.c (sendrawto_one): new function to use ONLY for
+       non-prefixed commands, like PING to client, or PASS/SERVER on
+       server registration
+
+2000-04-25  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/ircd_snprintf.c (doprintf): implement %H for possible
+       future expansion (channel numerics?)
+
+       * include/ircd_snprintf.h: added documentation to # to explain use
+       with %C; added documentation for : to explain use with %C; added
+       documentation for %H for channels
+
+       * ircd/whocmds.c: use send_reply
+
+       * ircd/userload.c: use sendcmdto_one
+
+       * ircd/uping.c: use sendcmdto_one
+
+       * ircd/send.c: use new flags to %C format string; ':' prefixes
+       client name with a colon for local connects, '#' uses
+       nick!user@host form for local connects
+
+       * ircd/s_user.c: use send_reply, sendto_opmask_butone,
+       sendcmdto_one, sendcmdto_serv_butone, sendcmdto_flag_butone
+
+       * ircd/s_serv.c: use sendcmdto_one, sendto_opmask_butone
+
+       * ircd/s_bsd.c: use sendto_opmask_butone, send_reply,
+       sendcmdto_one
+
+       * ircd/s_auth.c: use sendto_opmask_butone
+
+       * ircd/res.c: use sendcmdto_one
+
+       * ircd/ircd_snprintf.c (doprintf): minor bug fixes and some
+       debugging assertions
+
+2000-04-24  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/support.c: dumpcore is no longer used, so get rid of it
+
+       * ircd/parse.c: use send_reply, sendcmdto_one
+
+       * ircd/map.c: use send_reply
+
+       * ircd/listener.c: use send_reply
+
+       * ircd/jupe.c: use sendto_opmask_butone, send_reply
+
+       * ircd/ircd_reply.c: use send_reply
+
+       * ircd/ircd.c: use sendto_opmask_butone
+
+       * ircd/gline.c: use sendto_opmask_butone, send_reply
+
+       * ircd/ircd_snprintf.c (doprintf): make it deal with incompletely
+       registered clients; make FLAG_ALT print nick!user@host; make
+       FLAG_COLON print :blah
+
+       * ircd/class.c (report_classes): use send_reply instead of
+       sendto_one
+
+       * ircd/hash.c (m_hash): replace sendto_one with sendcmdto_one
+
+       * ircd/IPcheck.c (ip_registry_connect_succeeded): replace
+       sendto_one with sendcmdto_one
+
+2000-04-21  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/send.c: clean up logic in sendcmdto_channel_butone; use
+       MyConnect() instead of IsServer() in sendcmdto_flag_butone; define
+       sendcmdto_match_butone
+
+       * include/send.h: declare sendcmdto_match_butone
+
+2000-04-20  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/jupe.c: update to use send_reply()
+
+       * ircd/gline.c: update to use send_reply()
+
+       * include/ircd_reply.h: declare send_reply
+
+       * ircd/ircd_reply.c (send_reply): send_error_to_client, but for
+       replies; uses ircd_snprintf
+
+       * ircd/send.c: added comments to redirect searchers to appropriate
+       sendcmdto_* function; moved new functions to end of file; added
+       explanatory comments; reordered arguments; defined new functions
+       mentioned below
+
+       * ircd/m_jupe.c: reorder arguments to sendcmdto_* functions
+
+       * ircd/m_gline.c: reorder arguments to sendcmdto_* functions
+
+       * ircd/jupe.c: reorder arguments to sendcmdto_* functions
+
+       * ircd/gline.c: reorder arguments to sendcmdto_* functions
+
+       * include/send.h: reorder arguments, add explanatory comments,
+       declare new functions sendcmdto_flag_butone, sendto_opmask_butone,
+       and vsendto_opmask_butone
+
+2000-04-19  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/send.c: define sendcmdto_channel_butone, wrote a simplified
+       vsendto_op_mask that uses '*' instead of the receiving client
+       nickname
+
+       * include/send.h: declare sendcmdto_channel_butone; takes a skip
+       argument that allows you to skip (or not to skip) deaf users,
+       users behind bursting servers, and non channel operators
+
+2000-04-17  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/send.c: new sendcmdto_channel_butserv -- note that old
+       sendto_channel_butserv has a subtle bug; also wrote
+       sendcmdto_common_channels.
+
+       * include/send.h: declare new sendcmdto_* functions
+
+       * ircd/jupe.c: support local deactivations of jupes
+
+       * ircd/gline.c: support local deactivations of glines
+
+       * include/jupe.h: JUPE_LDEACT allows jupes to be locally
+       deactivated; if they aren't locally deactivated, then it slaves to
+       the net-wide activation status; JupeIsRemActive() tests only
+       whether the jupe is active everywhere else
+
+       * include/gline.h: GLINE_LDEACT allows glines to be locally
+       deactivated; if they aren't locally deactivated, then it slaves to
+       the net-wide activation status; GlineIsRemActive() tests only
+       whether the gline is active everywhere else
+
+       * ircd/gline.c: detect overlapping G-lines; if an existing, wider
+       gline expires after the new one will, we drop the new one,
+       otherwise we add the G-line after that one (so the wide one will
+       apply first); if the new one contains an existing G-line and if it
+       will expire after the existing one, we drop the existing one to
+       save memory
+
+       * ircd/m_gline.c (mo_gline): opers could issue remote local
+       glines when CONFIG_OPERCMDS was off; fixed
+
+2000-04-16  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/m_jupe.c (mo_jupe): allow target argument to be dropped if
+       this is a local JUPE
+
+       * ircd/gline.c: add flags argument to gline_activate and
+       gline_deactivate for future expansion
+
+       * ircd/m_gline.c: pass flags to gline_activate and
+       gline_deactivate
+
+       * include/gline.h: add flags argument to gline_activate and
+       gline_deactivate
+
+       * ircd/jupe.c: add flags argument to jupe_activate and
+       jupe_deactivate for future expansion
+
+       * include/jupe.h: add flags argument to jupe_activate and
+       jupe_deactivate
+
+       * ircd/m_jupe.c: pass a flags argument to jupe_add instead of
+       local, active; pass flags to jupe_activate and jupe_deactivate
+
+       * include/gline.h: remove dead code
+
+       * ircd/gline.c: make gline expire times relative to CurrentTime,
+       since that should be monotonically increasing, instead of
+       TStime(), which can be set backwards, and which can therefore
+       cause an expire time to increase; make local glines be removed
+       instead of just deactivated; don't let gline_find() look for
+       user@host glines if the mask being looked up is a channel mask
+
+       * ircd/send.c (vsendcmdto_one): forgot to account for the case
+       where origin is a server and destination is a user
+
+       * ircd/jupe.c: make jupe expire times relative to CurrentTime,
+       since that should be monotonically increasing, instead of
+       TStime(), which can be set backwards, and which can therefore
+       cause an expire time to increase; make local jupes be removed
+       instead of just deactivated
+
+       * ircd/ircd_snprintf.c: d'oh, thanks for catching that; short for
+       limit is fine.  any other warnings I should know about?
+
+2000-04-15  Thomas Helvey <tomh@inxpress.net>
+
+       * ircd/*.c: const correctness and type safety cleanups to
+       get code to compile with C++ compiler. Still has
+       signed/unsigned comparison warnings.
+
+2000-04-15  Greg Sikorski <gte@atomicrevs.demon.co.uk>
+
+       * ircd/userload.c: change <sys/time.h> include to <time.h> for
+         portability.
+
+2000-04-14  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/m_gline.c (mo_gline): d'oh, target isn't a numeric; use %C
+       and convert acptr...
+
+       * ircd/s_user.c: move gline_lookup function call into
+       register_user, where it'll have a username to lookup!
+
+       * ircd/m_gline.c: modify to utilize new sendcmdto_* series of
+       functions; also stuff send_error_to_client into return clauses
+
+       * ircd/m_jupe.c: modify to utilize new sendcmdto_* series of
+       functions; also use send_error_to_client where that makes sense
+
+       * ircd/jupe.c: modify to utilize new sendcmdto_* series of
+       functions; also use send_error_to_client where that makes sense
+
+       * ircd/gline.c: modify to utilize new sendcmdto_* series of
+       functions; also fix gline_lookup() to deal properly with remote
+       clients--boy, do struct Client and struct User need to be cleaned
+       up!
+
+       * ircd/ircd_snprintf.c (doprintf): a dest of &me is a server,
+       too...
+
+       * ircd/send.c: wrote sendcmdto_one(), vsendcmdto_one(), and
+       sendcmdto_serv_butone(), all utilizing the %v conversion of
+       ircd_snprintf()
+
+       * include/send.h: define IRC_BUFSIZE, max size of a message;
+       declare sendcmdto_one(), vsendcmdto_one(), and
+       sendcmdto_serv_butone()
+
+       * include/msg.h: define all the CMD_* constants needed to utilize
+       the new sendcmdto_* series of functions
+
+       * ircd/Makefile.in (SRC): list ircd_snprintf.c; run make depend
+
+       * ircd/gline.c: remove old, dead code.
+
+       * ircd/m_gline.c (mo_gline): disallow setting of global G-lines
+       unless CONFIG_OPERCMDS is enabled; disallow listing of all G-lines
+       (don't advertise proxies); remove dead code
+
+       * ircd/parse.c: oper handler for JUPE only lists jupes unless
+       CONFIG_OPERCMDS is enabled
+
+       * ircd/m_jupe.c (mo_jupe): don't compile mo_jupe() if
+       CONFIG_OPERCMDS is not enabled; we'll disable it in parse.c
+
+       * ircd/m_opmode.c (mo_opmode): if CONFIG_OPERCMDS is not enabled,
+       always return ERR_DISABLED
+
+       * ircd/m_clearmode.c (mo_clearmode): if CONFIG_OPERCMDS is not
+       enabled, always return ERR_DISABLED
+
+       * ircd/s_err.c: add error message to indicate disabled commands
+
+       * include/numeric.h (ERR_DISABLED): to indicate disabled commands
+
+       * doc/Configure.help: add documentation for CONFIG_OPERCMDS
+
+       * config/config-sh.in: add CONFIG_OPERCMDS, default both it and
+       CONFIG_NEW_MODE to 'y' for now
+
+       * ircd/gline.c (gline_list): fix a minor formatting bogon
+
+       * BUGS: since I fixed that bug, might as well mark it fixed.
+
+       * ircd/m_join.c: look up badchans with GLINE_EXACT
+
+       * ircd/m_gline.c: fix parc count problems; look up existing
+       G-lines with GLINE_EXACT; only set new lastmod when
+       activating/deactivating existing glines if old lastmod was not 0
+
+       * ircd/gline.c: forgot to copy the gline reason over; don't
+       propagate a gline with 0 lastmod if origin is user; add
+       GLINE_EXACT to force exact matching of gline mask
+
+       * ircd/ircd_snprintf.c (doprintf): forgot to deal with the zero
+       flag properly
+
+       * ircd/s_conf.c (find_kill): gline_find() takes a char *userhost,
+       but gline_lookup() actually takes a client--d'oh.
+
+2000-04-13  Thomas Helvey <tomh@inxpress.net>
+       * ircd/IPcheck.c: Back port BLMet's bugfix from 2.10.10
+
+2000-04-13  Greg Sikorski <gte@atomicrevs.demon.co.uk>
+
+       * ircd/whocmds.c: Don't make idle flag default in /who, to prevent:
+         "/who * x"
+         "Gte3 H*iwg Gte@212.49.240.217 :1 :0 I am the one that was."
+         (Found by Plexus).
+
+       * ircd/whocmds.c: Change idle time calc from socket idle to user
+         idle.
+
+2000-04-13  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * config/aclocal.m4 (unet_CHECK_TYPE_SIZES): check size of void *,
+       too, for ircd_snprintf.c
+
+       * include/ircd_snprintf.h: documentation for ircd_(v)snprintf, in
+       comments; mostly descended from the Linux manpage for printf, but
+       also documenting the extensions.
+
+       * ircd/ircd_snprintf.c: NULL dest is equivalent to going to a
+       client; make 'q' be the same as 'L'; remove __inline__; only
+       define EXTENSION if HAVE_LONG_LONG is defined
+
+       * include/handlers.h: declare m_gline()
+
+       * ircd/parse.c: gline can be called by users, but it only lists
+       the glines.
+
+       * ircd/s_user.c (set_nick_name): resend gline if a remote server
+       introduces a glined client
+
+       * ircd/s_serv.c (server_estab): burst glines, too
+
+       * ircd/gline.c: fix up all the expire times to be offsets;
+       simplify gline_resend()
+
+       * ircd/m_gline.c: begin coding replacements for ms_gline(),
+       mo_gline(), and m_gline()
+
+       * ircd/gline.c (gline_add): allow *@#channel to work correctly;
+       also, prohibit local BADCHANs if LOCAL_BADCHAN not defined
+
+2000-04-13  Greg Sikorski <gte@atomicrevs.demon.co.uk>
+
+       * tools/Bouncer/*: Add comments/documentation/tags.
+       * tools/Bouncer/*: Add debug defines, make task fork().
+
+2000-04-12  Thomas Helvey <tomh@inxpress.net>
+       * ircd/s_err.c: Cleanup s_err.c make one table so we
+       don't have to do anything tricky to get an error string.
+
+2000-04-12  Greg Sikorski <gte@atomicrevs.demon.co.uk>
+       * Add port bouncer for http (x/w)
+
+2000-04-12  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/s_conf.c (find_kill): replaced call to find_gline() with a
+       call to gline_find(); also used GlineReason() instead of direct
+       reference to structure member
+
+       * ircd/m_join.c (m_join): replace bad_channel() calls with calls
+       to gline_find(name, GLINE_BADCHAN), and also check to see if gline
+       is active
+
+       * ircd/channel.c: nothing seems to be called anywhere...
+
+       * ircd/s_err.c: update a couple of replies to dovetail with new
+       semantics
+
+       * ircd/gline.c: begin complete re-implementation of gline.c along
+       the lines of the final design of jupe.c
+
+       * include/gline.h: begin complete re-implementation of gline.c
+       along the lines of the final design of jupe.c
+
+       * ircd/channel.c (mode_process_clients): fix "Deop of +k user on
+       %s by %s" message...
+
+       * ircd/ircd_snprintf.c: my new snprintf()-like functions
+
+       * include/ircd_snprintf.h: my new snprintf()-like functions
+
+2000-04-11  Thomas Helvey <tomh@inxpress.net>
+       * ircd/IPcheck.c: removed old dead code
+       * ircd/s_user.c (send_user_info): removed non-standard
+          user not found message for userhost/userip
+
+2000-04-11  Greg Sikorski <gte@atomicrevs.demon.co.uk>
+
+       * ircd/s_err.c: Added missing quotes to ERR_DONTCHEAT numeric.
+       * doc/p10.html: Work on chapter 4.
+
+2000-04-10  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/channel.c (mode_parse_client): fix coredump on /mode
+       #foobar +o nosuchnick
+
+2000-04-10  Perry Lorier  <Isomer@coders.net>
+       * BUGS: Added bug.
+
+2000-04-09  Thomas Helvey <tomh@inxpress.net>
+       * include/IPcheck.h: fix prototype
+       * ircd/s_user.c: fix usage of IPcheck_remote_connect
+       * ircd/IPcheck.c: removed unused args
+
+2000-04-09  Thomas Helvey <tomh@inxpress.net>
+       * include/IPcheck.h: add proto for IPcheck_expire
+
+       * ircd/IPcheck.c: Rewrote
+
+       * ircd/ircd.c: Add IPcheck_expire to main message loop
+
+       * ircd/s_user.c: Redo target hashing, refactor target code
+
+       * include/numeric.h: Cleaned up numerics, added which ones are
+       in use by other networks and what they are in use for.
+
+       * ircd/channel.c: cleaned can_join(), allow anyone through anything
+       if /invited, simplified the function.  Opers overusing OPEROVERRIDE
+       will get a message explaining to them not to cheat.
+
+       * ircd/m_join.c: cleaned up the various join functions, should be
+       a lot more efficient.  Still needs work.  Now assumes that s<->s
+       won't send it a JOIN 0.  Service coders - note this and tread with
+       care.
+
+       * ircd/m_stats.c: added Gte-'s stats doc patch.
+
+       * ircd/m_version.c: /version now returns the 005 numeric as well.
+       as requested by Liandrin.
+
+
+2000-04-07  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/m_clearmode.c: add include for support.h for write_log()
+
+       * configure: move ircd/crypt/* to tools/*
+
+2000-04-06  Thomas Helvey <tomh@inxpress.net>
+       * ircd/s_auth.c: Shorten auth connect timeout to 60 seconds
+          set client host to server alias if connection from localhost
+
+2000-04-06  Perry Lorier <isomer@coders.net>
+       * ircd/ircd.c: Fix core during pinging (oops)
+       
+2000-04-06  Perry Lorier <isomer@coders.net>
+       * ircd/send.c: fixed wrong ident being sent to channels bug.
+       * include/numerics.h: Updated some of the numerics from other
+       networks.  Flagged some as 'unused' by undernet.
+
+2000-03-30  Perry Lorier <isomer@coders.net>
+       * ircd/ircd.c: Lets see if this helps the ping problem at all.
+       * ircd/whocmds.c, /doc/readme.who: Added %l specifier to get idle
+       time for local clients. (as requested), extended who now returns all
+       the flags (@+!) so you can tell the complete state of a client.
+
+2000-03-30  Thomas Helvey <tomh@inxpress.net>
+       * m_rping.c m_rpong.c: add Gte's rping/rpong fixes
+
+2000-03-30  Perry Lorier <isomer@coders.net>
+       * ircd/parse.c: oops, missed opers.
+
+2000-03-30  Perry Lorier <isomer@coders.net>
+       * ircd/parse.c: fixed mystifying ping bug thats been plaguing us
+       for so long.  Remember: m_ping MUST be in the parse array. :)
+
+2000-03-30  Perry Lorier <isomer@coders.net>
+       * ircd/ircd.c: test in check_pings was wrong.  I move that we
+       disallow cvs commit after 10pm localtime....
+
+2000-03-30  Perry Lorier <isomer@coders.net>
+       * ircd/m_pong.c: Fix it for servers too.
+
+2000-03-30  Perry Lorier <isomer@coders.net>
+       * ircd/m_pong.c: Fix ping timeout bugs
+
+2000-03-30  Perry Lorier <isomer@coders.net>
+       * ircd/channel.c: Bans had CurrentTime in their when field instead
+       of TStime()
+
+2000-03-31  Thomas Helvey <tomh@ixpress.net>
+       * ircd/numnicks.c (SetXYYCapacity): fix for extended
+       numerics.
+
+2000-03-30  Perry Lorier <isomer@coders.net>
+       * ircd/m_nick.c: send kills both ways so when we add nick change
+       on collision we don't desync the network.
+
+       * ircd/map.c: Fixup the map a bit more.
+
+2000-03-31  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/m_clearmode.c (do_clearmode): Log the CLEARMODE to OPATH
+
+       * ircd/m_opmode.c: Log the mode changes to OPATH
+
+       * ircd/channel.c (modebuf_flush_int): Log the mode changes to
+       OPATH
+
+       * include/channel.h (MODEBUF_DEST_LOG): Log the mode changes to
+       OPATH
+
+       * doc/Configure.help: help text for CONFIG_LOG_OPMODE / OPATH
+
+       * config/config-sh.in: added OPATH for opmode log file
+
+       * ircd/m_clearmode.c (do_clearmode): updated uses of
+       modebuf_mode_string() for the new usage
+
+       * ircd/channel.c: added flag MODE_FREE and an int argument to
+       modebuf_mode_string() to indicate that the string must be free'd;
+       updated calls to modebuf_mode_string() for the new usage; called
+       collapse(pretty_mask()) on the ban string and use allocated memory
+       for it; added ban list length accounting; fixed a number of small
+       bugs in ban processing
+
+       * include/channel.h: added flag MODE_FREE and an int argument to
+       modebuf_mode_string() to indicate that the string must be free'd
+
+       * ircd/m_clearmode.c (do_clearmode): made sure clearmode removed
+       keys and limits that are set
+
+2000-03-30  Perry Lorier <isomer@coders.net>
+       * ircd/ircd.c: rewrote check_pings() for maintainability
+       and speed.  Also changed quit msg's so they don't have
+       redundant nick[host] info in them.
+
+       * ircd/send.c: Changed write errors to report what error
+       occured (if possible).
+
+       * ircd/gline.c: added gline comment to the quit.
+
+       * ircd/m_server.c: Added suggestions to server quits mentioning
+       what went wrong so the admin can fix it earlier instead of asking
+       questions...
+
+       * ircd/map.c: Changed m_map() to hide numerics, show a * beside
+       servers that aren't fully burst yet.  And show '(--s)' for servers
+       where its not sure.
+
+       * doc/example.conf: Fixed wrapped U:
+
+2000-03-30  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/m_mode.c (ms_mode): implemented a new m_mode in terms of
+       mode_parse() (version selectable at compile time)
+
+       * ircd/m_clearmode.c (mo_clearmode): clean_channelname(parv[1])
+
+       * ircd/m_opmode.c (mo_opmode): clean_channelname(parv[1])
+
+       * config/config-sh.in: add new config option to enable new m_mode
+       implementation
+
+       * doc/Configure.help: add documentation for new config option
+       CONFIG_NEW_MODE
+
+       * ircd/channel.c (mode_parse_client): /opmode #foobar -o -- 461
+       MODE -v : Not enough parameters
+
+       * ircd/m_clearmode.c (do_clearmode): do_clearmode() would remove
+       +k and +l even if they weren't set...
+
+       * ircd/m_opmode.c: implement the OPMODE command using mode_parse()
+
+       * ircd/channel.c: make mode_process_clients() clear the DEOPPED
+       flag; fix +s+p exclusivity; add MODE_ADD/MODE_DEL to flag list
+       for; test the 0-th member, not the i-th member, of the client
+       change state stuff
+
+       * ircd/m_clearmode.c (do_clearmode): use the new
+       mode_invite_clear() function
+
+       * ircd/channel.c: cleared up all the compile-time warnings and
+       errors
+
+       * include/channel.h: added declarations for mode_ban_invalidate()
+       and mode_invite_clear()
+
+       * ircd/channel.c: finished mode_parse(), then broke it up into a
+       dozen or so helper functions to make the code easier to read
+
+2000-03-29  Thomas Helvey <tomh@inxpress.net>
+       * ircd/ircd.c: refactor server initialization a bit, use
+       getopt for parsing command line, refactor init_sys, main,
+       and other bits.
+
+       * ircd/s_bsd.c: add functions for initialization to clean
+       up logic a bit and remove duplicated code.
+
+       * include/ircd.h: add struct for server process related
+       variables.
+
+2000-03-29  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/channel.c: initial definition of mode_parse(); flags to
+       prevent doing the same thing multiple times; helper method
+       send_notoper() to send a "Not oper"/"Not on channel" notice
+
+       * include/channel.h: declare mode_parse() and helper flags
+
+       * ircd/channel.c (modebuf_flush_int): fiddled with timestamp
+       sending to match the current action of set_mode() closely enough
+       that hopefully there won't be major conflicts
+
+       * ircd/channel.c (modebuf_flush_int): consolidated the mode string
+       building logic, reversed the order of the arguments to mode
+       commands to have '-' preceed '+'
+
+2000-03-29  Thomas Helvey <tomh@inxpress.net>
+       * ircd/s_bsd.c (add_connection): don't disable socket options
+       let OS tune itself and allow important performance tweaks to 
+       work.
+
+2000-03-28  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/channel.c (modebuf_flush_int): use %d, not %-15d; I got
+       confused by set_mode, which is doing some really weird logic;
+       guess what I'm going to rewrite next?  ;)
+
+2000-03-28  Kevin L. Mitchell  <klmitch@emc.com>
+
+       * include/channel.h: added MODE_SAVE for the bounds checking stuff
+       in modebuf_flush
+
+       * ircd/channel.c: make modebuf_flush into modebuf_flush_int and
+       make it do bounds checking on the buffer; all modes are sent only
+       if the all parameter is 1; modebuf_flush is the exported wrapper
+
+       * include/channel.h: add BOUNCE, renumber flags to get a little
+       more space
+
+       * ircd/channel.c (modebuf_flush): don't overload HACK2, add
+       BOUNCE; send DESYNCH message
+
+2000-03-27  Kevin L. Mitchell  <klmitch@emc.com>
+
+       * ircd/m_clearmode.c (do_clearmode): only mark the modes the
+       channel actually has in effect for deletion
+
+       * ircd/channel.c: added explanatory comments to all added
+       functions; made flushing take place at the correct place even if
+       the MODEBUF_DEST_DEOP flag is set; rewrote build_string() helper
+       to bash some stupid bugs; made modebuf_flush() return if ModeBuf
+       is empty, fixed the apparent source, removed some bogus string
+       termination code, properly terminate the mode strings, add support
+       for HACK2 and HACK3, made limit strings not be sent if the limit
+       is being removed, changed where '+' and '-' come from in sent
+       strings, added support for DEOP flag, set up bouncing code for
+       HACK2
+
+       * ircd/Makefile.in: ran make depend
+
+       * include/channel.h: added new defines for future functionality,
+       made modebuf_flush() return int so I can use tail recursion
+
+       * ircd/m_clearmode.c: add msg.h to includes; other misc cleanups
+       to make it all compile
+
+       * ircd/m_opmode.c: add msg.h to includes...
+
+       * ircd/m_clearmode.c: implemented mo_clearchan()/ms_clearchan()
+
+       * ircd/channel.c (modebuf_flush): realized I forgot to
+       nul-terminate addbuf/rembuf properly...
+
+       * ircd/m_clearmode.c (do_clearmode): wrote do_clearmode()...
+
+       * ircd/channel.c (modebuf_flush): correct sendto_server_butone to
+       sendto_serv_butone--blah^2
+
+       * ircd/send.c (sendto_serv_butone): stupid comments confused me
+
+       * ircd/channel.c (modebuf_flush): if there are no mode changes to
+       propagate, we're done...
+
+       * ircd/channel.c (modebuf_flush): duh; it's sendto_server_butone,
+       not sendto_all_butone
+
+       * ircd/m_clearmode.c: define skeleton for m{o,s}_clearmode
+
+       * ircd/m_opmode.c: define skeleton for m{o,s}_opmode
+
+       * ircd/Makefile.in (SRC): added m_opmode() and m_clearmode() to
+       the list
+
+       * ircd/parse.c: added messages for opmode and clearmode
+
+       * include/handlers.h: added declarations for mo_opmode(),
+       ms_opmode(), mo_clearmode(), and ms_clearmode()
+
+       * include/msg.h: define MSG_OPMODE, TOK_OPMODE, MSG_CLEARMODE, and
+       TOK_CLEARMODE
+
+       * include/channel.h (MODEBUF_DEST_OPMODE): Define the
+       MODEBUF_DEST_OPMODE flag
+
+       * ircd/channel.c (modebuf_flush): added new flag,
+       MODEBUF_DEST_OPMODE; causes channel MODE/HACK(4) notice to appear
+       to originate from source's server (or source itself, if
+       IsServer(source)); also causes a server-level MODE to be sent as
+       OPMODE instead
+
+       * include/channel.h: defined MODEBUF_DEST_SERVER,
+       MODEBUF_DEST_HACK4
+
+       * ircd/channel.c: Add another argument to build_string() to handle
+       numeric nicks; implemented MODEBUF_DEST_SERVER to send MODEs to
+       servers; implemented MODEBUF_DEST_HACK4 to cause HACK(4) notices
+       to be sent out
+
+2000-03-27  Perry Lorier <isomer@coders.net>
+
+       * ircd/s_bsd.c: fixed missing 'u' typo.
+
+2000-03-26  Kevin L. Mitchell  <klmitch@emc.com>
+
+       * ircd/channel.c: implement modebuf_init(), _mode(), _mode_uint(),
+       _mode_string(), _mode_client(), _flush(); also implemented a
+       simple build_string()
+
+       * include/channel.h: added definition of ModeBuf, modebuf_*
+       manipulation functions, and a couple of helper macros
+
+2000-03-24 Thomas Helvey <tomh@inxpress.net>
+  * numicks.c: convert extended numerics to use original mask version
+  * numnicks.h: ""
+  * s_user.c:
+2000-03-23 Thomas Helvey <tomh@inxpress.net>
+  * Merge in changes from production
+2000-03-22 Thomas Helvey <tomh@inxpress.net>
+  * numicks.c: Tweak to numnick generator to reduce possibility of duplicates.
+  * rfc1459.unet: Add Maniac's documentation for /names 0
+* Fix misc. jupe bugs that somehow made it into the tree
+* Escape /names 0 to mean /names --Maniac
+* Don't core when server asks for info --Maniac 
+* Add Kev's jupe patch --Bleep
+* Add Maniacs squit patch --Bleep
+* Merge in u2_10_10_beta07 changes --Bleep
+* Merge in u2_10_10_beta06 changes --Bleep
+* Start ircu2.10.11 development, beta branch u2_10_10 --Bleep
+#-----------------------------------------------------------------------------
diff --git a/Doxyfile b/Doxyfile
new file mode 100644 (file)
index 0000000..be52175
--- /dev/null
+++ b/Doxyfile
@@ -0,0 +1,1078 @@
+# Doxyfile 1.3.4
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project
+#
+# All text after a hash (#) is considered a comment and will be ignored
+# The format is:
+#       TAG = value [value, ...]
+# For lists items can also be appended using:
+#       TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (" ")
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded
+# by quotes) that should identify the project.
+
+PROJECT_NAME           = "Undernet IRC Daemon"
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number.
+# This could be handy for archiving the generated documentation or
+# if some version control system is used.
+
+PROJECT_NUMBER         = "$Name: u2_10_12_09 $"
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute)
+# base path where the generated documentation will be put.
+# If a relative path is entered, it will be relative to the location
+# where doxygen was started. If left blank the current directory will be used.
+
+OUTPUT_DIRECTORY       = doc/doxygen
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all
+# documentation generated by doxygen is written. Doxygen will use this
+# information to generate all constant output in the proper language.
+# The default language is English, other supported languages are:
+# Brazilian, Catalan, Chinese, Chinese-Traditional, Croatian, Czech, Danish, Dutch,
+# Finnish, French, German, Greek, Hungarian, Italian, Japanese, Japanese-en
+# (Japanese with English messages), Korean, Norwegian, Polish, Portuguese,
+# Romanian, Russian, Serbian, Slovak, Slovene, Spanish, Swedish, and Ukrainian.
+
+OUTPUT_LANGUAGE        = English
+
+# This tag can be used to specify the encoding used in the generated output.
+# The encoding is not always determined by the language that is chosen,
+# but also whether or not the output is meant for Windows or non-Windows users.
+# In case there is a difference, setting the USE_WINDOWS_ENCODING tag to YES
+# forces the Windows encoding (this is the default for the Windows binary),
+# whereas setting the tag to NO uses a Unix-style encoding (the default for
+# all platforms other than Windows).
+
+USE_WINDOWS_ENCODING   = NO
+
+# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will
+# include brief member descriptions after the members that are listed in
+# the file and class documentation (similar to JavaDoc).
+# Set to NO to disable this.
+
+BRIEF_MEMBER_DESC      = YES
+
+# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend
+# the brief description of a member or function before the detailed description.
+# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
+# brief descriptions will be completely suppressed.
+
+REPEAT_BRIEF           = YES
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
+# Doxygen will generate a detailed section even if there is only a brief
+# description.
+
+ALWAYS_DETAILED_SEC    = YES
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all inherited
+# members of a class in the documentation of that class as if those members were
+# ordinary class members. Constructors, destructors and assignment operators of
+# the base classes will not be shown.
+
+INLINE_INHERITED_MEMB  = NO
+
+# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full
+# path before files name in the file list and in the header files. If set
+# to NO the shortest path that makes the file name unique will be used.
+
+FULL_PATH_NAMES        = NO
+
+# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag
+# can be used to strip a user-defined part of the path. Stripping is
+# only done if one of the specified strings matches the left-hand part of
+# the path. It is allowed to use relative paths in the argument list.
+
+STRIP_FROM_PATH        =
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter
+# (but less readable) file names. This can be useful is your file systems
+# doesn't support long names like on DOS, Mac, or CD-ROM.
+
+SHORT_NAMES            = NO
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen
+# will interpret the first line (until the first dot) of a JavaDoc-style
+# comment as the brief description. If set to NO, the JavaDoc
+# comments will behave just like the Qt-style comments (thus requiring an
+# explict @brief command for a brief description.
+
+JAVADOC_AUTOBRIEF      = YES
+
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen
+# treat a multi-line C++ special comment block (i.e. a block of //! or ///
+# comments) as a brief description. This used to be the default behaviour.
+# The new default is to treat a multi-line C++ comment block as a detailed
+# description. Set this tag to YES if you prefer the old behaviour instead.
+
+MULTILINE_CPP_IS_BRIEF = NO
+
+# If the DETAILS_AT_TOP tag is set to YES then Doxygen
+# will output the detailed description near the top, like JavaDoc.
+# If set to NO, the detailed description appears after the member
+# documentation.
+
+DETAILS_AT_TOP         = NO
+
+# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented
+# member inherits the documentation from any documented member that it
+# reimplements.
+
+INHERIT_DOCS           = YES
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
+# tag is set to YES, then doxygen will reuse the documentation of the first
+# member in the group (if any) for the other members of the group. By default
+# all members of a group must be documented explicitly.
+
+DISTRIBUTE_GROUP_DOC   = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab.
+# Doxygen uses this value to replace tabs by spaces in code fragments.
+
+TAB_SIZE               = 8
+
+# This tag can be used to specify a number of aliases that acts
+# as commands in the documentation. An alias has the form "name=value".
+# For example adding "sideeffect=\par Side Effects:\n" will allow you to
+# put the command \sideeffect (or @sideeffect) in the documentation, which
+# will result in a user-defined paragraph with heading "Side Effects:".
+# You can put \n's in the value part of an alias to insert newlines.
+
+ALIASES                =
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources
+# only. Doxygen will then generate output that is more tailored for C.
+# For instance, some of the names that are used will be different. The list
+# of all members will be omitted, etc.
+
+OPTIMIZE_OUTPUT_FOR_C  = YES
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java sources
+# only. Doxygen will then generate output that is more tailored for Java.
+# For instance, namespaces will be presented as packages, qualified scopes
+# will look different, etc.
+
+OPTIMIZE_OUTPUT_JAVA   = NO
+
+# Set the SUBGROUPING tag to YES (the default) to allow class member groups of
+# the same type (for instance a group of public functions) to be put as a
+# subgroup of that type (e.g. under the Public Functions section). Set it to
+# NO to prevent subgrouping. Alternatively, this can be done per class using
+# the \nosubgrouping command.
+
+SUBGROUPING            = YES
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+
+# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in
+# documentation are documented, even if no documentation was available.
+# Private class members and static file members will be hidden unless
+# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES
+
+EXTRACT_ALL            = YES
+
+# If the EXTRACT_PRIVATE tag is set to YES all private members of a class
+# will be included in the documentation.
+
+EXTRACT_PRIVATE        = NO
+
+# If the EXTRACT_STATIC tag is set to YES all static members of a file
+# will be included in the documentation.
+
+EXTRACT_STATIC         = YES
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs)
+# defined locally in source files will be included in the documentation.
+# If set to NO only classes defined in header files are included.
+
+EXTRACT_LOCAL_CLASSES  = YES
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all
+# undocumented members of documented classes, files or namespaces.
+# If set to NO (the default) these members will be included in the
+# various overviews, but no documentation section is generated.
+# This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_MEMBERS     = NO
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all
+# undocumented classes that are normally visible in the class hierarchy.
+# If set to NO (the default) these classes will be included in the various
+# overviews. This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_CLASSES     = NO
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all
+# friend (class|struct|union) declarations.
+# If set to NO (the default) these declarations will be included in the
+# documentation.
+
+HIDE_FRIEND_COMPOUNDS  = NO
+
+# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any
+# documentation blocks found inside the body of a function.
+# If set to NO (the default) these blocks will be appended to the
+# function's detailed documentation block.
+
+HIDE_IN_BODY_DOCS      = NO
+
+# The INTERNAL_DOCS tag determines if documentation
+# that is typed after a \internal command is included. If the tag is set
+# to NO (the default) then the documentation will be excluded.
+# Set it to YES to include the internal documentation.
+
+INTERNAL_DOCS          = NO
+
+# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate
+# file names in lower-case letters. If set to YES upper-case letters are also
+# allowed. This is useful if you have classes or files whose names only differ
+# in case and if your file system supports case sensitive file names. Windows
+# users are advised to set this option to NO.
+
+CASE_SENSE_NAMES       = YES
+
+# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen
+# will show members with their full class and namespace scopes in the
+# documentation. If set to YES the scope will be hidden.
+
+HIDE_SCOPE_NAMES       = NO
+
+# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen
+# will put a list of the files that are included by a file in the documentation
+# of that file.
+
+SHOW_INCLUDE_FILES     = YES
+
+# If the INLINE_INFO tag is set to YES (the default) then a tag [inline]
+# is inserted in the documentation for inline members.
+
+INLINE_INFO            = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen
+# will sort the (detailed) documentation of file and class members
+# alphabetically by member name. If set to NO the members will appear in
+# declaration order.
+
+SORT_MEMBER_DOCS       = YES
+
+# The GENERATE_TODOLIST tag can be used to enable (YES) or
+# disable (NO) the todo list. This list is created by putting \todo
+# commands in the documentation.
+
+GENERATE_TODOLIST      = YES
+
+# The GENERATE_TESTLIST tag can be used to enable (YES) or
+# disable (NO) the test list. This list is created by putting \test
+# commands in the documentation.
+
+GENERATE_TESTLIST      = YES
+
+# The GENERATE_BUGLIST tag can be used to enable (YES) or
+# disable (NO) the bug list. This list is created by putting \bug
+# commands in the documentation.
+
+GENERATE_BUGLIST       = YES
+
+# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or
+# disable (NO) the deprecated list. This list is created by putting
+# \deprecated commands in the documentation.
+
+GENERATE_DEPRECATEDLIST= YES
+
+# The ENABLED_SECTIONS tag can be used to enable conditional
+# documentation sections, marked by \if sectionname ... \endif.
+
+ENABLED_SECTIONS       =
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines
+# the initial value of a variable or define consists of for it to appear in
+# the documentation. If the initializer consists of more lines than specified
+# here it will be hidden. Use a value of 0 to hide initializers completely.
+# The appearance of the initializer of individual variables and defines in the
+# documentation can be controlled using \showinitializer or \hideinitializer
+# command in the documentation regardless of this setting.
+
+MAX_INITIALIZER_LINES  = 30
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated
+# at the bottom of the documentation of classes and structs. If set to YES the
+# list will mention the files that were used to generate the documentation.
+
+SHOW_USED_FILES        = YES
+
+#---------------------------------------------------------------------------
+# configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated
+# by doxygen. Possible values are YES and NO. If left blank NO is used.
+
+QUIET                  = YES
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are
+# generated by doxygen. Possible values are YES and NO. If left blank
+# NO is used.
+
+WARNINGS               = YES
+
+# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings
+# for undocumented members. If EXTRACT_ALL is set to YES then this flag will
+# automatically be disabled.
+
+WARN_IF_UNDOCUMENTED   = YES
+
+# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for
+# potential errors in the documentation, such as not documenting some
+# parameters in a documented function, or documenting parameters that
+# don't exist or using markup commands wrongly.
+
+WARN_IF_DOC_ERROR      = YES
+
+# The WARN_FORMAT tag determines the format of the warning messages that
+# doxygen can produce. The string should contain the $file, $line, and $text
+# tags, which will be replaced by the file and line number from which the
+# warning originated and the warning text.
+
+WARN_FORMAT            = "$file:$line: $text"
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning
+# and error messages should be written. If left blank the output is written
+# to stderr.
+
+WARN_LOGFILE           =
+
+#---------------------------------------------------------------------------
+# configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag can be used to specify the files and/or directories that contain
+# documented source files. You may enter file names like "myfile.cpp" or
+# directories like "/usr/src/myproject". Separate the files or directories
+# with spaces.
+
+INPUT                  = ircd include
+
+# If the value of the INPUT tag contains directories, you can use the
+# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
+# and *.h) to filter out the source-files in the directories. If left
+# blank the following patterns are tested:
+# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx *.hpp
+# *.h++ *.idl *.odl *.cs *.php *.php3 *.inc
+
+FILE_PATTERNS          =
+
+# The RECURSIVE tag can be used to turn specify whether or not subdirectories
+# should be searched for input files as well. Possible values are YES and NO.
+# If left blank NO is used.
+
+RECURSIVE              = YES
+
+# The EXCLUDE tag can be used to specify files and/or directories that should
+# excluded from the INPUT source files. This way you can easily exclude a
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+
+EXCLUDE                =
+
+# The EXCLUDE_SYMLINKS tag can be used select whether or not files or directories
+# that are symbolic links (a Unix filesystem feature) are excluded from the input.
+
+EXCLUDE_SYMLINKS       = NO
+
+# If the value of the INPUT tag contains directories, you can use the
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
+# certain files from those directories.
+
+EXCLUDE_PATTERNS       =
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or
+# directories that contain example code fragments that are included (see
+# the \include command).
+
+EXAMPLE_PATH           =
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
+# and *.h) to filter out the source-files in the directories. If left
+# blank all files are included.
+
+EXAMPLE_PATTERNS       =
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
+# searched for input files to be used with the \include or \dontinclude
+# commands irrespective of the value of the RECURSIVE tag.
+# Possible values are YES and NO. If left blank NO is used.
+
+EXAMPLE_RECURSIVE      = NO
+
+# The IMAGE_PATH tag can be used to specify one or more files or
+# directories that contain image that are included in the documentation (see
+# the \image command).
+
+IMAGE_PATH             =
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should
+# invoke to filter for each input file. Doxygen will invoke the filter program
+# by executing (via popen()) the command <filter> <input-file>, where <filter>
+# is the value of the INPUT_FILTER tag, and <input-file> is the name of an
+# input file. Doxygen will then use the output that the filter program writes
+# to standard output.
+
+INPUT_FILTER           =
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
+# INPUT_FILTER) will be used to filter the input files when producing source
+# files to browse (i.e. when SOURCE_BROWSER is set to YES).
+
+FILTER_SOURCE_FILES    = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will
+# be generated. Documented entities will be cross-referenced with these sources.
+
+SOURCE_BROWSER         = YES
+
+# Setting the INLINE_SOURCES tag to YES will include the body
+# of functions and classes directly in the documentation.
+
+INLINE_SOURCES         = NO
+
+# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct
+# doxygen to hide any special comment blocks from generated source code
+# fragments. Normal C and C++ comments will always remain visible.
+
+STRIP_CODE_COMMENTS    = NO
+
+# If the REFERENCED_BY_RELATION tag is set to YES (the default)
+# then for each documented function all documented
+# functions referencing it will be listed.
+
+REFERENCED_BY_RELATION = YES
+
+# If the REFERENCES_RELATION tag is set to YES (the default)
+# then for each documented function all documented entities
+# called/used by that function will be listed.
+
+REFERENCES_RELATION    = YES
+
+# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen
+# will generate a verbatim copy of the header file for each class for
+# which an include is specified. Set to NO to disable this.
+
+VERBATIM_HEADERS       = YES
+
+#---------------------------------------------------------------------------
+# configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index
+# of all compounds will be generated. Enable this if the project
+# contains a lot of classes, structs, unions or interfaces.
+
+ALPHABETICAL_INDEX     = YES
+
+# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then
+# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns
+# in which this list will be split (can be a number in the range [1..20])
+
+COLS_IN_ALPHA_INDEX    = 5
+
+# In case all classes in a project start with a common prefix, all
+# classes will be put under the same header in the alphabetical index.
+# The IGNORE_PREFIX tag can be used to specify one or more prefixes that
+# should be ignored while generating the index headers.
+
+IGNORE_PREFIX          =
+
+#---------------------------------------------------------------------------
+# configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES (the default) Doxygen will
+# generate HTML output.
+
+GENERATE_HTML          = YES
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `html' will be used as the default path.
+
+HTML_OUTPUT            = html
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for
+# each generated HTML page (for example: .htm,.php,.asp). If it is left blank
+# doxygen will generate files with .html extension.
+
+HTML_FILE_EXTENSION    = .html
+
+# The HTML_HEADER tag can be used to specify a personal HTML header for
+# each generated HTML page. If it is left blank doxygen will generate a
+# standard header.
+
+HTML_HEADER            =
+
+# The HTML_FOOTER tag can be used to specify a personal HTML footer for
+# each generated HTML page. If it is left blank doxygen will generate a
+# standard footer.
+
+HTML_FOOTER            =
+
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading
+# style sheet that is used by each HTML page. It can be used to
+# fine-tune the look of the HTML output. If the tag is left blank doxygen
+# will generate a default style sheet
+
+HTML_STYLESHEET        =
+
+# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes,
+# files or namespaces will be aligned in HTML using tables. If set to
+# NO a bullet list will be used.
+
+HTML_ALIGN_MEMBERS     = YES
+
+# If the GENERATE_HTMLHELP tag is set to YES, additional index files
+# will be generated that can be used as input for tools like the
+# Microsoft HTML help workshop to generate a compressed HTML help file (.chm)
+# of the generated HTML documentation.
+
+GENERATE_HTMLHELP      = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can
+# be used to specify the file name of the resulting .chm file. You
+# can add a path in front of the file if the result should not be
+# written to the html output dir.
+
+CHM_FILE               =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can
+# be used to specify the location (absolute path including file name) of
+# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run
+# the HTML help compiler on the generated index.hhp.
+
+HHC_LOCATION           =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag
+# controls if a separate .chi index file is generated (YES) or that
+# it should be included in the master .chm file (NO).
+
+GENERATE_CHI           = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag
+# controls whether a binary table of contents is generated (YES) or a
+# normal table of contents (NO) in the .chm file.
+
+BINARY_TOC             = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members
+# to the contents of the HTML help documentation and to the tree view.
+
+TOC_EXPAND             = NO
+
+# The DISABLE_INDEX tag can be used to turn on/off the condensed index at
+# top of each HTML page. The value NO (the default) enables the index and
+# the value YES disables it.
+
+DISABLE_INDEX          = NO
+
+# This tag can be used to set the number of enum values (range [1..20])
+# that doxygen will group on one line in the generated HTML documentation.
+
+ENUM_VALUES_PER_LINE   = 4
+
+# If the GENERATE_TREEVIEW tag is set to YES, a side panel will be
+# generated containing a tree-like index structure (just like the one that
+# is generated for HTML Help). For this to work a browser that supports
+# JavaScript, DHTML, CSS and frames is required (for instance Mozilla 1.0+,
+# Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are
+# probably better off using the HTML help feature.
+
+GENERATE_TREEVIEW      = YES
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be
+# used to set the initial width (in pixels) of the frame in which the tree
+# is shown.
+
+TREEVIEW_WIDTH         = 250
+
+#---------------------------------------------------------------------------
+# configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will
+# generate Latex output.
+
+GENERATE_LATEX         = NO
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `latex' will be used as the default path.
+
+LATEX_OUTPUT           = latex
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
+# invoked. If left blank `latex' will be used as the default command name.
+
+LATEX_CMD_NAME         = latex
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to
+# generate index for LaTeX. If left blank `makeindex' will be used as the
+# default command name.
+
+MAKEINDEX_CMD_NAME     = makeindex
+
+# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact
+# LaTeX documents. This may be useful for small projects and may help to
+# save some trees in general.
+
+COMPACT_LATEX          = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used
+# by the printer. Possible values are: a4, a4wide, letter, legal and
+# executive. If left blank a4wide will be used.
+
+PAPER_TYPE             = a4wide
+
+# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX
+# packages that should be included in the LaTeX output.
+
+EXTRA_PACKAGES         =
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for
+# the generated latex document. The header should contain everything until
+# the first chapter. If it is left blank doxygen will generate a
+# standard header. Notice: only use this tag if you know what you are doing!
+
+LATEX_HEADER           =
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated
+# is prepared for conversion to pdf (using ps2pdf). The pdf file will
+# contain links (just like the HTML output) instead of page references
+# This makes the output suitable for online browsing using a pdf viewer.
+
+PDF_HYPERLINKS         = YES
+
+# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of
+# plain latex in the generated Makefile. Set this option to YES to get a
+# higher quality PDF documentation.
+
+USE_PDFLATEX           = YES
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode.
+# command to the generated LaTeX files. This will instruct LaTeX to keep
+# running if errors occur, instead of asking the user for help.
+# This option is also used when generating formulas in HTML.
+
+LATEX_BATCHMODE        = YES
+
+# If LATEX_HIDE_INDICES is set to YES then doxygen will not
+# include the index chapters (such as File Index, Compound Index, etc.)
+# in the output.
+
+LATEX_HIDE_INDICES     = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output
+# The RTF output is optimised for Word 97 and may not look very pretty with
+# other RTF readers or editors.
+
+GENERATE_RTF           = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `rtf' will be used as the default path.
+
+RTF_OUTPUT             = rtf
+
+# If the COMPACT_RTF tag is set to YES Doxygen generates more compact
+# RTF documents. This may be useful for small projects and may help to
+# save some trees in general.
+
+COMPACT_RTF            = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated
+# will contain hyperlink fields. The RTF file will
+# contain links (just like the HTML output) instead of page references.
+# This makes the output suitable for online browsing using WORD or other
+# programs which support those fields.
+# Note: wordpad (write) and others do not support links.
+
+RTF_HYPERLINKS         = NO
+
+# Load stylesheet definitions from file. Syntax is similar to doxygen's
+# config file, i.e. a series of assigments. You only have to provide
+# replacements, missing definitions are set to their default value.
+
+RTF_STYLESHEET_FILE    =
+
+# Set optional variables used in the generation of an rtf document.
+# Syntax is similar to doxygen's config file.
+
+RTF_EXTENSIONS_FILE    =
+
+#---------------------------------------------------------------------------
+# configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES (the default) Doxygen will
+# generate man pages
+
+GENERATE_MAN           = NO
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `man' will be used as the default path.
+
+MAN_OUTPUT             = man
+
+# The MAN_EXTENSION tag determines the extension that is added to
+# the generated man pages (default is the subroutine's section .3)
+
+MAN_EXTENSION          = .3
+
+# If the MAN_LINKS tag is set to YES and Doxygen generates man output,
+# then it will generate one additional man file for each entity
+# documented in the real man page(s). These additional files
+# only source the real man page, but without them the man command
+# would be unable to find the correct page. The default is NO.
+
+MAN_LINKS              = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES Doxygen will
+# generate an XML file that captures the structure of
+# the code including all documentation. Note that this
+# feature is still experimental and incomplete at the
+# moment.
+
+GENERATE_XML           = NO
+
+# The XML_OUTPUT tag is used to specify where the XML pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `xml' will be used as the default path.
+
+XML_OUTPUT             = xml
+
+# The XML_SCHEMA tag can be used to specify an XML schema,
+# which can be used by a validating XML parser to check the
+# syntax of the XML files.
+
+XML_SCHEMA             =
+
+# The XML_DTD tag can be used to specify an XML DTD,
+# which can be used by a validating XML parser to check the
+# syntax of the XML files.
+
+XML_DTD                =
+
+#---------------------------------------------------------------------------
+# configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will
+# generate an AutoGen Definitions (see autogen.sf.net) file
+# that captures the structure of the code including all
+# documentation. Note that this feature is still experimental
+# and incomplete at the moment.
+
+GENERATE_AUTOGEN_DEF   = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_PERLMOD tag is set to YES Doxygen will
+# generate a Perl module file that captures the structure of
+# the code including all documentation. Note that this
+# feature is still experimental and incomplete at the
+# moment.
+
+GENERATE_PERLMOD       = NO
+
+# If the PERLMOD_LATEX tag is set to YES Doxygen will generate
+# the necessary Makefile rules, Perl scripts and LaTeX code to be able
+# to generate PDF and DVI output from the Perl module output.
+
+PERLMOD_LATEX          = NO
+
+# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be
+# nicely formatted so it can be parsed by a human reader.  This is useful
+# if you want to understand what is going on.  On the other hand, if this
+# tag is set to NO the size of the Perl module output will be much smaller
+# and Perl will parse it just the same.
+
+PERLMOD_PRETTY         = YES
+
+# The names of the make variables in the generated doxyrules.make file
+# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX.
+# This is useful so different doxyrules.make files included by the same
+# Makefile don't overwrite each other's variables.
+
+PERLMOD_MAKEVAR_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will
+# evaluate all C-preprocessor directives found in the sources and include
+# files.
+
+ENABLE_PREPROCESSING   = YES
+
+# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro
+# names in the source code. If set to NO (the default) only conditional
+# compilation will be performed. Macro expansion can be done in a controlled
+# way by setting EXPAND_ONLY_PREDEF to YES.
+
+MACRO_EXPANSION        = NO
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES
+# then the macro expansion is limited to the macros specified with the
+# PREDEFINED and EXPAND_AS_PREDEFINED tags.
+
+EXPAND_ONLY_PREDEF     = NO
+
+# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files
+# in the INCLUDE_PATH (see below) will be search if a #include is found.
+
+SEARCH_INCLUDES        = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that
+# contain include files that are not input files but should be processed by
+# the preprocessor.
+
+INCLUDE_PATH           =
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
+# patterns (like *.h and *.hpp) to filter out the header-files in the
+# directories. If left blank, the patterns specified with FILE_PATTERNS will
+# be used.
+
+INCLUDE_FILE_PATTERNS  =
+
+# The PREDEFINED tag can be used to specify one or more macro names that
+# are defined before the preprocessor is started (similar to the -D option of
+# gcc). The argument of the tag is a list of macros of the form: name
+# or name=definition (no spaces). If the definition and the = are
+# omitted =1 is assumed.
+
+PREDEFINED             = DEBUGMODE FORCEINLINE IPV6
+
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then
+# this tag can be used to specify a list of macro names that should be expanded.
+# The macro definition that is found in the sources will be used.
+# Use the PREDEFINED tag if you want to use a different macro definition.
+
+EXPAND_AS_DEFINED      =
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then
+# doxygen's preprocessor will remove all function-like macros that are alone
+# on a line, have an all uppercase name, and do not end with a semicolon. Such
+# function macros are typically used for boiler-plate code, and will confuse the
+# parser if not removed.
+
+SKIP_FUNCTION_MACROS   = YES
+
+#---------------------------------------------------------------------------
+# Configuration::addtions related to external references
+#---------------------------------------------------------------------------
+
+# The TAGFILES option can be used to specify one or more tagfiles.
+# Optionally an initial location of the external documentation
+# can be added for each tagfile. The format of a tag file without
+# this location is as follows:
+#   TAGFILES = file1 file2 ...
+# Adding location for the tag files is done as follows:
+#   TAGFILES = file1=loc1 "file2 = loc2" ...
+# where "loc1" and "loc2" can be relative or absolute paths or
+# URLs. If a location is present for each tag, the installdox tool
+# does not have to be run to correct the links.
+# Note that each tag file must have a unique name
+# (where the name does NOT include the path)
+# If a tag file is not located in the directory in which doxygen
+# is run, you must also specify the path to the tagfile here.
+
+TAGFILES               =
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create
+# a tag file that is based on the input files it reads.
+
+GENERATE_TAGFILE       = ircu.tags
+
+# If the ALLEXTERNALS tag is set to YES all external classes will be listed
+# in the class index. If set to NO only the inherited external classes
+# will be listed.
+
+ALLEXTERNALS           = NO
+
+# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed
+# in the modules index. If set to NO, only the current project's groups will
+# be listed.
+
+EXTERNAL_GROUPS        = YES
+
+# The PERL_PATH should be the absolute path and name of the perl script
+# interpreter (i.e. the result of `which perl').
+
+PERL_PATH              = /usr/bin/perl
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+
+# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will
+# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base or
+# super classes. Setting the tag to NO turns the diagrams off. Note that this
+# option is superceded by the HAVE_DOT option below. This is only a fallback. It is
+# recommended to install and use dot, since it yields more powerful graphs.
+
+CLASS_DIAGRAMS         = NO
+
+# If set to YES, the inheritance and collaboration graphs will hide
+# inheritance and usage relations if the target is undocumented
+# or is not a class.
+
+HIDE_UNDOC_RELATIONS   = NO
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
+# available from the path. This tool is part of Graphviz, a graph visualization
+# toolkit from AT&T and Lucent Bell Labs. The other options in this section
+# have no effect if this option is set to NO (the default)
+
+HAVE_DOT               = NO
+
+# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for each documented class showing the direct and
+# indirect inheritance relations. Setting this tag to YES will force the
+# the CLASS_DIAGRAMS tag to NO.
+
+CLASS_GRAPH            = YES
+
+# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for each documented class showing the direct and
+# indirect implementation dependencies (inheritance, containment, and
+# class references variables) of the class with other documented classes.
+
+COLLABORATION_GRAPH    = YES
+
+# If the UML_LOOK tag is set to YES doxygen will generate inheritance and
+# collaboration diagrams in a style similiar to the OMG's Unified Modeling
+# Language.
+
+UML_LOOK               = YES
+
+# If set to YES, the inheritance and collaboration graphs will show the
+# relations between templates and their instances.
+
+TEMPLATE_RELATIONS     = NO
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT
+# tags are set to YES then doxygen will generate a graph for each documented
+# file showing the direct and indirect include dependencies of the file with
+# other documented files.
+
+INCLUDE_GRAPH          = YES
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and
+# HAVE_DOT tags are set to YES then doxygen will generate a graph for each
+# documented header file showing the documented files that directly or
+# indirectly include this file.
+
+INCLUDED_BY_GRAPH      = YES
+
+# If the CALL_GRAPH and HAVE_DOT tags are set to YES then doxygen will
+# generate a call dependency graph for every global function or class method.
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable call graphs for selected
+# functions only using the \callgraph command.
+
+CALL_GRAPH             = YES
+
+# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen
+# will graphical hierarchy of all classes instead of a textual one.
+
+GRAPHICAL_HIERARCHY    = YES
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
+# generated by dot. Possible values are png, jpg, or gif
+# If left blank png will be used.
+
+DOT_IMAGE_FORMAT       = png
+
+# The tag DOT_PATH can be used to specify the path where the dot tool can be
+# found. If left blank, it is assumed the dot tool can be found on the path.
+
+DOT_PATH               =
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that
+# contain dot files that are included in the documentation (see the
+# \dotfile command).
+
+DOTFILE_DIRS           =
+
+# The MAX_DOT_GRAPH_WIDTH tag can be used to set the maximum allowed width
+# (in pixels) of the graphs generated by dot. If a graph becomes larger than
+# this value, doxygen will try to truncate the graph, so that it fits within
+# the specified constraint. Beware that most browsers cannot cope with very
+# large images.
+
+MAX_DOT_GRAPH_WIDTH    = 1024
+
+# The MAX_DOT_GRAPH_HEIGHT tag can be used to set the maximum allows height
+# (in pixels) of the graphs generated by dot. If a graph becomes larger than
+# this value, doxygen will try to truncate the graph, so that it fits within
+# the specified constraint. Beware that most browsers cannot cope with very
+# large images.
+
+MAX_DOT_GRAPH_HEIGHT   = 1024
+
+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the
+# graphs generated by dot. A depth value of 3 means that only nodes reachable
+# from the root by following a path via at most 3 edges will be shown. Nodes that
+# lay further from the root node will be omitted. Note that setting this option to
+# 1 or 2 may greatly reduce the computation time needed for large code bases. Also
+# note that a graph may be further truncated if the graph's image dimensions are
+# not sufficient to fit the graph (see MAX_DOT_GRAPH_WIDTH and MAX_DOT_GRAPH_HEIGHT).
+# If 0 is used for the depth value (the default), the graph is not depth-constrained.
+
+MAX_DOT_GRAPH_DEPTH    = 0
+
+# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will
+# generate a legend page explaining the meaning of the various boxes and
+# arrows in the dot generated graphs.
+
+GENERATE_LEGEND        = YES
+
+# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will
+# remove the intermediate dot files that are used to generate
+# the various graphs.
+
+DOT_CLEANUP            = YES
+
+#---------------------------------------------------------------------------
+# Configuration::addtions related to the search engine
+#---------------------------------------------------------------------------
+
+# The SEARCHENGINE tag specifies whether or not a search engine should be
+# used. If set to NO the values of all tags below this one will be ignored.
+
+SEARCHENGINE           = NO
diff --git a/INSTALL b/INSTALL
new file mode 100644 (file)
index 0000000..41b6e81
--- /dev/null
+++ b/INSTALL
@@ -0,0 +1,61 @@
+
+ircu - INSTALL
+  Original by Run <carlo@runaway.xs4all.nl>,
+  Isomer <isomer@coders.net>, and Kev <klmitch@mit.edu>
+  Rewritten by Sengaia <sengaia@undernet.org> 
+  Updated by Entrope <entrope@undernet.org>
+
+Compiling and installing ircu should be a fairly straightforward process,
+if you have obtained this software as a (.tar.gz) package, please consider
+using CVS (described below). Using CVS will make updating your installation
+much easier. 
+
+After obtaining the latest version of the ircu source code, change into the
+source directory (ircu2.10.xx.yy), and run "./configure". To see the various
+ways in which you can customize your installation, run "./configure --help".
+
+The configure process will check your environment and prepare itself for
+compiling the source code. If one or more of the prerequisites cannot be
+found, configure will terminate with an error. You will need to resolve
+this and run configure again.
+
+If configure runs without error(s), you are ready to compile. To compile ircu,
+run "make". Please use GNU make and gcc. If the source code does not compile,
+make sure your environment is setup correctly. If you are convinced the source
+of the failure is ircu, gather all relevant information about your system such
+as the Architecture, OS version, the configure statement you used, etc. and
+contact coder-com@undernet.org.
+
+Once ircu is compiled, install it by running "make install".
+
+Next, you will have to configure your IRC server by setting up your ircd.conf
+file. Use the included doc/example.conf as a starting point; it is installed
+in $HOME/lib/example.conf by default.
+Setting up ircd.conf can be a bit tricky, so if this is your first time doing
+it, begin with a bare-bones configuration and extend it as you go.
+
+If you are upgrading from ircu2.10.11, use the ircd/convert-conf
+program to convert your existing configuration file(s).  It is
+compiled during "make" and installed to $PREFIX/bin/convert-conf.
+
+Good Luck!
+
+RETRIEVING IRCU VIA CVS
+
+The recommended way to get the ircu package now is to use CVS.  CVS makes
+upgrades a lot less painful and lets you get the latest package.
+
+The first thing you need to do is login to the cvs server:
+# cvs -d :pserver:anonymous@cvs.undernet.org:/cvsroot/undernet-ircu login
+
+(we recommend that you cut and paste the above line to use it :)
+When it prompts you for a password hit enter since there isn't one.
+
+To check out the the last development version of ircu, use:
+# cvs -d :pserver:anonymous@cvs.undernet.org:/cvsroot/undernet-ircu co -P ircu2.10
+The latest stable version has a tag name that depends on the version
+number; see doc/readme.cvs for details.
+
+To update your source tree to the latest version, run "cvs update -dP" from within the
+ircu2.10 directory. For more information, see http://coder-com.undernet.org.
+
diff --git a/INSTALL_FR b/INSTALL_FR
new file mode 100644 (file)
index 0000000..d29054c
--- /dev/null
@@ -0,0 +1,169 @@
+Fichier d'installation en français par delete <delete@cyberabuse.org>
+                        Mis Ã  jour par delete <delete@cyberabuse.org>
+
+
+L'UnderNet IRC daemon.
+
+L'installation de l'IRC daemon (ircd) existes dans les ordres que
+voici:
+
+1) Déballer le module.
+2) cd dans le répertoire.
+3) `./configure'
+4) `make config'
+5) `make install'
+
+1) Déballer le module.
+====================
+
+La voie recommendée pour avoir le module de l'ircu est d'utilisé CVS.
+CVS obtiend les marques améliore beaucoup moins douloureux et vous
+laisse obtenir le dernier module.
+
+1.1) La première chose que vous avez besoin de faire est de vous
+identifiez envers le serveur.
+
+Avec la commande que voici:
+
+cvs -d :pserver:anonymous@cvs.undernet.org:/cvsroot/undernet-ircu login
+
+(Nous recommandons que vous coupez et collez la ligne ci-dessus pour
+l'utiliser :). Quand il insiste pour un mot de passe Ã©criver
+'anoncvs'.
+
+1.2) Alors vous allez décider lesquels des versions vous voulez
+utiliser:
+
+stable - Ceci est la version recommandé. En cas de doute utiliser le!
+Pour avoir cette version, additioner "-r u2_10_11" Ã  la ligne de
+commande du CVS.
+
+beta - Cette version subit le test avant d'être favorisée Ã 
+ircu2.10. Il peut Ãªtre buggé. L'utilisation sur le réseau de
+production d'undernet est interdite, excepté certains serveurs
+autorisés. La flag "-r" que vous avez besoin de regardez est documenté
+sur le site web du Coder Committee's, http://coder-com.undernet.org.
+
+alpha - C'est la version de développement. On ne le garantit pas de
+compiler, et devrait Ãªtre considéré FORTEMENT instable. On ne le
+destine pas pour l'usage de production.  Pour contrôler ce
+branchement, n'employez aucun flag "-r".
+
+
+Pour vérifier la version, tapez:
+
+cvs -d :pserver:anonymous@cvs.undernet.org:/cvsroot/undernet-ircu co -P ircu2.10
+
+Les deux lignes ci-dessus ne devraient pas avoir une entrée entre
+eux. Si vous voulez utiliser un autre version, placez le flag "-r"
+approprié après le "co".  Ceci créera un répertoire ircu2.10, et
+mettra tous les fichiers dedans.
+
+Pour avoir la dernière version, tapez "cvs update -dP".
+
+Pour plus d'information, regardez sur le site de coder-com Ã :
+http://coder-com.undernet.org/
+
+La vieille (essayé et rectifiez) méthode qui fonctionne même lorsque
+le website n'est pas DoS'd (soupir) est inclue ci-dessous. En
+utilisant la méthode au-dessous vous n'avez qu'à taper "cvs update -
+dP" pour obtenir la dernière version.
+
+Le nom du module est quelque chose comme `ircu2.x.y.z.tgz ', où
+"x.y.z" est la version en cours (au moment de l'écriture nous avons
+ircu2.10.10.pl15.(development).tgz). Vous avez besoin de `gzip', du
+GNU, ouvrez la commande et uncompresser ce module. Vous pouvez
+télécharger ceci de chaque site ftp GNU pour presque n'importe quel
+système d'exploitation.
+ Si vous avez un tar GNU, taper:
+ tar -xzf ircu2.x.y.z.tgz
+ où "ircu2.x.y.z.tgz" est le nom du package.
+ Si sa ne marche pas, essayez:
+ gzip -d ircu2.x.y.z.tgz | tar -xvf ircu2.x.y.z.tar
+Les deux méthodes ont comme conséquence un répertoire "ircu2.x.y.z"
+dans votre répertoire actuel.
+
+2) cd dans la directory de base.
+================================
+
+Faites Ã  ce répertoire votre répertoire actuel en tapant:
+
+ cd ircu2.x.y.z
+
+ou ircu2.10 si vous utilisé cvs.
+
+Là où "ircu2.x.y.z" est le nom du répertoire dézippé.
+
+3) "./configure"
+=================
+
+Ceci produira le 'config/setup.h', votre configuration dépend du
+système d'exploitation.
+
+Si ceci produit un message une erreur tel que "Permission Denied",
+alors essai avec "chmod a+x ./configure" pour avoir la permission
+d'excuter le fichier.
+
+Pour plus d'information sur la commande configure, tapez "./configure
+--help".
+
+4) "make"
+=========
+
+Tapez:
+
+make
+
+dans le répertoire de base. Il devrait compiler sans erreurs ou
+avertissements.  Veuillez expédier n'importe quel problème aux
+dévelopeurs, mais seulement après que vous vous Ãªtes assurés ce n'est
+pas une erreur de vous-même.  Si vous voulez que votre système
+d'exploitation soit supporté dans de futures versions, faite une
+connexion qui fixe réellement le problème.
+
+5) "make install"
+=================
+
+Type:
+
+make install
+
+Ceci devrait installer l'ircd et la dir man.  Veuillez revérifier les
+permissions du binaire.
+
+Naturellement, vous avez besoin d'un ircd.conf syntactiquement correct
+dans DPATH.  Voyez les Docs pour certaine information sur ceci. Créez
+également un ircd.motd avec le texte de votre MOTD.  Et créez
+finalement un remote.motd avec trois lignes de texte comme MOTD Ã 
+distance.  Encore, tous ces fichiers devraient Ãªtre lisibles par
+l'ircd, et les fichiers journaux devraient Ãªtre Ã©crivable.
+
+En cas de problème.
+======================
+
+Si vous avez des problèmes Ã  configurer le serveur vous pourriez
+considérer d'installer GNU dans votre VOIE D'ACCÈS.  Dans certains cas
+un cerveau-mort /bin/sh pose le problème, dans ce cas je suggère
+d'installer le "bash" et de l'utiliser comme (as sh - > bash).  En
+conclusion, tout autre problèmes de compilent devrait Ãªtre résolu
+quand vous installez le GCC.  Si vous avez des problemes avec le
+startage du ircd, executer "./configure" encore et mettez la commande
+"--enable-debug".  Recompiler l'ircd, et executer-le avec:
+
+ircd -t -x9
+
+Cela va Ã©crire un debug output a votre Ã©crant, probablement avec la
+cause du pourquoi il ne veut pas starter.
+
+N'UTILISEZ PAS UN SERVEUR AVEC LA MISE AU POINT PERMISE SUR UN RÉSEAU
+DE PRODUCTION. Faire ainsi est un risque d'intimité grave.
+
+Si quelque chose ne marche pas, envoyer un e-mail Ã 
+coder-com@undernet.org
diff --git a/LICENSE b/LICENSE
new file mode 100644 (file)
index 0000000..9a17037
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,249 @@
+
+                   GNU GENERAL PUBLIC LICENSE
+                    Version 1, February 1989
+
+ Copyright (C) 1989 Free Software Foundation, Inc.
+                    675 Mass Ave, Cambridge, MA 02139, USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                           Preamble
+
+  The license agreements of most software companies try to keep users
+at the mercy of those companies.  By contrast, our General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  The
+General Public License applies to the Free Software Foundation's
+software and to any other program whose authors commit to using it.
+You can use it for your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Specifically, the General Public License is designed to make
+sure that you have the freedom to give away or sell copies of free
+software, that you receive source code or can get it if you want it,
+that you can change the software or use pieces of it in new free
+programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of a such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must tell them their rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+\f
+                   GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License Agreement applies to any program or other work which
+contains a notice placed by the copyright holder saying it may be
+distributed under the terms of this General Public License.  The
+"Program", below, refers to any such program or work, and a "work based
+on the Program" means either the Program or any work containing the
+Program or a portion of it, either verbatim or with modifications.  Each
+licensee is addressed as "you".
+
+  1. You may copy and distribute verbatim copies of the Program's source
+code as you receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice and
+disclaimer of warranty; keep intact all the notices that refer to this
+General Public License and to the absence of any warranty; and give any
+other recipients of the Program a copy of this General Public License
+along with the Program.  You may charge a fee for the physical act of
+transferring a copy.
+
+  2. You may modify your copy or copies of the Program or any portion of
+it, and copy and distribute such modifications under the terms of Paragraph
+1 above, provided that you also do the following:
+
+    a) cause the modified files to carry prominent notices stating that
+    you changed the files and the date of any change; and
+
+    b) cause the whole of any work that you distribute or publish, that
+    in whole or in part contains the Program or any part thereof, either
+    with or without modifications, to be licensed at no charge to all
+    third parties under the terms of this General Public License (except
+    that you may choose to grant warranty protection to some or all
+    third parties, at your option).
+
+    c) If the modified program normally reads commands interactively when
+    run, you must cause it, when started running for such interactive use
+    in the simplest and most usual way, to print or display an
+    announcement including an appropriate copyright notice and a notice
+    that there is no warranty (or else, saying that you provide a
+    warranty) and that users may redistribute the program under these
+    conditions, and telling the user how to view a copy of this General
+    Public License.
+
+    d) You may charge a fee for the physical act of transferring a
+    copy, and you may at your option offer warranty protection in
+    exchange for a fee.
+
+Mere aggregation of another independent work with the Program (or its
+derivative) on a volume of a storage or distribution medium does not bring
+the other work under the scope of these terms.
+\f
+  3. You may copy and distribute the Program (or a portion or derivative of
+it, under Paragraph 2) in object code or executable form under the terms of
+Paragraphs 1 and 2 above provided that you also do one of the following:
+
+    a) accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of
+    Paragraphs 1 and 2 above; or,
+
+    b) accompany it with a written offer, valid for at least three
+    years, to give any third party free (except for a nominal charge
+    for the cost of distribution) a complete machine-readable copy of the
+    corresponding source code, to be distributed under the terms of
+    Paragraphs 1 and 2 above; or,
+
+    c) accompany it with the information you received as to where the
+    corresponding source code may be obtained.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form alone.)
+
+Source code for a work means the preferred form of the work for making
+modifications to it.  For an executable file, complete source code means
+all the source code for all modules it contains; but, as a special
+exception, it need not include source code for modules which are standard
+libraries that accompany the operating system on which the executable
+file runs, or for standard header files or definitions files that
+accompany that operating system.
+
+  4. You may not copy, modify, sublicense, distribute or transfer the
+Program except as expressly provided under this General Public License.
+Any attempt otherwise to copy, modify, sublicense, distribute or transfer
+the Program is void, and will automatically terminate your rights to use
+the Program under this License.  However, parties who have received
+copies, or rights to use copies, from you under this General Public
+License will not have their licenses terminated so long as such parties
+remain in full compliance.
+
+  5. By copying, distributing or modifying the Program (or any work based
+on the Program) you indicate your acceptance of this license to do so,
+and all its terms and conditions.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the original
+licensor to copy, distribute or modify the Program subject to these
+terms and conditions.  You may not impose any further restrictions on the
+recipients' exercise of the rights granted herein.
+\f
+  7. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of the license which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+the license, you may choose any version ever published by the Free Software
+Foundation.
+
+  8. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+                           NO WARRANTY
+
+  9. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  10. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+                    END OF TERMS AND CONDITIONS
+\f
+       Appendix: How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to humanity, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these
+terms.
+
+  To do so, attach the following notices to the program.  It is safest to
+attach them to the start of each source file to most effectively convey
+the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) 19yy  <name of author>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 1, or (at your option)
+    any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) 19xx name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the
+appropriate parts of the General Public License.  Of course, the
+commands you use may be called something other than `show w' and `show
+c'; they could even be mouse-clicks or menu items--whatever suits your
+program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the
+  program `Gnomovision' (a program to direct compilers to make passes
+  at assemblers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+That's all there is to it!
diff --git a/Makefile.in b/Makefile.in
new file mode 100644 (file)
index 0000000..ff3b25a
--- /dev/null
@@ -0,0 +1,139 @@
+# Makefile for the Undernet IRC Daemon.
+# Copyright (C) 1997, Carlo Wood <carlo@runaway.xs4all.nl>
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+# 02111-1307, USA.
+
+#### Start of system configuration section. ####
+
+prefix = @prefix@
+srcdir = @srcdir@
+VPATH = @srcdir@
+
+SHELL = @SHPROG@
+RM = @RMPROG@
+AWK = @AWK@
+@SET_MAKE@
+#### End of system configuration section. ####
+
+SUBDIRS = doc ircd
+IRCD_MAKEFILES = Makefile doc/Makefile ircd/Makefile
+
+all: build
+
+.PHONY: server build depend install
+# Some versions of make give a warning when this is empty:
+.SUFFIXES: .dummy
+
+build: ${IRCD_MAKEFILES}
+       @for i in ${SUBDIRS}; do \
+               echo "Building $$i..."; \
+               cd $$i; ${MAKE} build; cd ..; \
+       done
+
+root-clean:
+       @for i in '*.orig' '.*.orig' '\#*' '*~' '.*~' '*.bak' '.*.bak' core; do\
+               echo "Removing $$i"; \
+               REMOVE_FILES="`find . -name "$$i" -print`"; \
+               test -n "$$REMOVE_FILES" && ${RM} -f $$REMOVE_FILES; \
+       done || true
+
+sub-clean: ${IRCD_MAKEFILES}
+       @for i in ${SUBDIRS}; do \
+               echo "Cleaning $$i..."; \
+               cd $$i; ${MAKE} clean; cd ..;\
+       done
+
+clean: root-clean sub-clean
+
+root-distclean: root-clean
+       @for i in '*.rej'; do \
+               echo "Removing $$i"; \
+               REMOVE_FILES="`find . -name "$$i" -print`"; \
+               test -n "$$REMOVE_FILES" && ${RM} -f $$REMOVE_FILES; \
+       done || true
+
+sub-distclean: ${IRCD_MAKEFILES}
+       @for i in ${SUBDIRS}; do \
+               echo "Dist-cleaning $$i..."; \
+               cd $$i; ${MAKE} distclean; cd ..;\
+       done
+
+distclean: root-distclean sub-distclean
+       ${RM} -f Makefile config.h config.log config.cache config.status \
+               stamp-h
+
+maintainer-clean: root-distclean ${IRCD_MAKEFILES}
+       @for i in ${SUBDIRS}; do \
+               echo "maintainer-cleaning $$i..."; \
+               cd $$i; ${MAKE} maintainer-clean; cd ..;\
+       done
+
+depend: ${IRCD_MAKEFILES}
+       @for i in ${SUBDIRS}; do \
+               echo "Making dependencies in $$i..."; \
+               cd $$i; ${MAKE} depend; cd ..; \
+       done
+
+install: ${IRCD_MAKEFILES}
+       test -d ${prefix} || mkdir ${prefix}
+       @for i in ${SUBDIRS}; do \
+               echo "Installing $$i..."; \
+               cd $$i; ${MAKE} install; cd ..; \
+       done
+
+uninstall: ${IRCD_MAKEFILES}
+       @for i in ${SUBDIRS}; do \
+               echo "Uninstalling $$i..."; \
+               cd $$i; ${MAKE} uninstall; cd ..; \
+       done
+
+${srcdir}/aclocal.m4: acinclude.m4
+       cd ${srcdir} && aclocal
+
+${srcdir}/configure: configure.in aclocal.m4
+       cd ${srcdir} && autoconf
+
+# autoheader might not change config.h.in, so touch a stamp file.
+${srcdir}/config.h.in: stamp-h.in
+${srcdir}/stamp-h.in: configure.in aclocal.m4 acconfig.h
+       cd ${srcdir} && autoheader
+       echo timestamp > ${srcdir}/stamp-h.in
+
+config.h: stamp-h
+stamp-h: config.h.in config.status
+       ./config.status
+
+Makefile: Makefile.in config.status
+       ./config.status
+
+doc/Makefile: doc/Makefile.in config.status
+       ./config.status
+
+ircd/Makefile: ircd/Makefile.in config.status
+       ./config.status
+
+config.status: configure
+       ./config.status --recheck
+
+# Some versions of 'make' do not support the .PHONY target :
+FORCE:
+
+# Indent all headers and source files:
+indent:
+       @test "`indent --version`" = "GNU indent 2.1.0" || \
+         (echo "You need GNU indent 2.1.0; See doc/readme.indent" && exit -1);
+       VERSION_CONTROL=none indent include/*.h ircd/*.c
+
diff --git a/README b/README
new file mode 100644 (file)
index 0000000..e722967
--- /dev/null
+++ b/README
@@ -0,0 +1,140 @@
+
+       Welcome to ircu2.10.12, the Undernet IRC daemon
+
+Version u2.10.12 of the Undernet ircd incorporates many new features
+over its predecessor, and we feel that using it will make you very
+happy indeed.
+
+New features include:
+  - A completely rewritten network event engine, which make full use
+    of the asynchronous event engines available in FreeBSD (kqueue)
+    and Solaris (/dev/poll), resulting in dramaticaly improved
+    performance.
+  - New F: (feature) lines in ircd.conf, and the GET/SET commands allow
+    many settings to be changed dynamically, rather than by with compile-
+    time configuration.
+  - The new "account" feature added to the P10 protocol, allows people to
+    remain logged in to service bots (i.e., gnuworld) during a netsplit.
+    This means people will not have to login again once the network rejoins.
+
+INSTALLATION
+
+Please see the INSTALL file for installation instructions, for hints on how
+to best configure your OS for running ircu under high load, see the various
+README.<platform> files.
+
+COMPATIBILITY
+
+This version of ircu will only work with servers that use the P10 protocol,
+some of the new features will only work between ircu2.10.12 servers.
+
+GENERAL PERFORMANCE HINTS
+
+For platform-specific notes and hints, see the platform-specific
+sections below.  These notes apply to servers that will serve large
+numbers (thousands) of clients simultaneously.  If your server serves
+a small amount of users, the defaults should work well enough.
+
+ - Run an OS that supports an asynchronous network event engine; currently
+   these are FreeBSD (kqueue), and Solaris (/dev/poll); possibly other BSDs
+   will also support kqueue. This will have a dramatic effect on performance.
+ - Make things as lean as possible: Make your server dedicated to ircu,
+   disable anything that is not neccesary, and build a custom kernel (where
+   possible).
+ - Tune kernel parameters as described in the platform-specific
+   sections below.
+ - With many clients connecting each second, ircu will be doing lots of DNS
+   lookups. Make sure that the DNS server(s) in your /etc/resolv.conf are as
+   close as possible, or run a local caching DNS server on your IRC server.
+
+TIME SYNCHRONIZATION
+
+Many things can and will go horribly wrong when the clocks on the servers
+on your network become (too far) out of sync. It is therefore highly
+recommended that all servers run a version of ntpd that will keep their
+clocks from going astray.
+
+INFORMATION HIDING
+
+As per undernet-admins CFV-165, this server contains code that will,
+by default, hide certain information from ordinary users. If you do
+not want this, override the default "HIS" feature settings in your
+ircd.conf.
+
+MORE INFORMATION
+
+For more information on this software, see the included documentation
+in the doc/ directory, as well as http://coder-com.undernet.org.
+
+For general information on the Undernet, vist http://www.undernet.org
+
+Happy IRCing!
+
+RUNNING THIS SERVER ON LINUX
+
+If you run Linux 2.6 or above (or 2.4 with appropriate patches), ircu
+can use the epoll family of system calls for much more efficient
+checks of which connections are active.  Most pre-epoll systems will
+use 100% CPU with 2000 clients; with epoll, a server may use only a
+few percent of CPU with the same load.
+
+To handle that many connections, the ircd must be started with a high
+enough file descriptor resource.  Check your distribution's docs on
+how to set the global and per-user limits according to your expected
+load.
+
+RUNNING THIS SERVER ON FREEBSD
+
+When running on FreeBSD, ircu can make use of the kqueue() event engine, which
+results in much improved performance over the old poll()-based method. kqueue
+is included in the more recent 4.x releases of FreeBSD.
+
+In order for ircu to be able to serve many clients simultaneously, you need
+to increase the maximum allowable number of open files in the system. To do
+this, add commands such as the following during your system's boot sequence:
+
+sysctl -w kern.maxfiles=16384
+sysctl -w kern.maxfilesperproc=16384
+
+Unless you will be serving thousands of clients simultaneously, you will not
+need to do the following, unless of course you just can't stand having a
+system that is not optimized to its limits :)
+
+Build a custom kernel: Make your kernel as lean as possible by removing all
+drivers and options you will not need. The following parameters will affect
+performance, they are listed with suggested values only. For more information
+on what they do exactly, see FreeBSD's documentation.
+
+maxusers        2048
+options         NMBCLUSTERS=65535
+options         ICMP_BANDLIM
+
+Also, you may wish to run the following at system startup (from /etc/rc.local,
+or whichever other method you prefer):
+
+sysctl -w net.inet.tcp.rfc1323=1
+sysctl -w net.inet.tcp.delayed_ack=0
+sysctl -w net.inet.tcp.restrict_rst=1
+sysctl -w kern.ipc.maxsockbuf=2097152
+sysctl -w kern.ipc.somaxconn=2048
+
+Created by Sengaia <sengaia@undernet.org>, July 20 2002.
+
+RUNNING THIS SERVER ON SOLARIS
+
+When running on Solaris, ircu can make use of the /dev/poll event engine, which
+results in much improved performance over the old poll()-based method. Solaris
+versions 8 and 9 include /dev/poll out of the box, for Solaris 7 you will have
+to grab and install Patch-ID 106541-21.
+
+In order to increase the number of clients ircu can handle, add lines such as
+the following to /etc/system:
+
+* set hard limit on file descriptors
+set rlim_fd_max = 16384
+* set soft limit on file descriptors
+set rlim_fd_cur = 8192
+
+For more useful hints see http://www.sean.de/Solaris/soltune.html
+
+Created by Sengaia <sengaia@undernet.org> on July 20, 2002.
diff --git a/RELEASE.NOTES b/RELEASE.NOTES
new file mode 100644 (file)
index 0000000..47106bd
--- /dev/null
@@ -0,0 +1,222 @@
+Release notes for ircu2.10.12
+Last updated: 1 Sep 2005
+Written by Michael Poole <mdpoole@troilus.org>
+Based on earlier documents by Kev <klmitch@mit.edu> and
+Braden <dbtem@yahoo.com>.
+
+This document briefly describes changes in ircu2.10.12 relative to
+ircu2.10.11.  ircu2.10.12 is only compatible with servers that
+implement the P10 protocol.  It has been tested to link against
+ircu2.10.11, but some features (notably IPv6 support and oplevels) are
+not supported by ircu2.10.11.
+
+Semantic Changes (TAKE NOTE):
+
+Channel keys and passwords (see the "oplevels" enhancement below)
+listed in a JOIN are now only checked against the corresponding
+channel.  In ircu2.10.11, "JOIN #a,#b key" would attempt to use "key"
+as the key for both #a and #b.  ircu2.10.12 will only attempt to use
+it as the key for #a.  ircu2.10.12's behavior matches that documented
+in RFC 1459.
+
+Enhancements:
+
+The configuration file format has changed to one that is easier to
+read.  It is based on the configuration parser found in ircd-hybrid.
+As usual, an example configuration file can be found in the doc
+subdirectory.
+
+ircu now supports IPv6 clients.  If your operating system provides
+IPv6 socket support, ircu can accept connections on IPv6 addresses.
+Even if your operating system does not support IPv6 sockets, you can
+link (using IPv4) to a server that has IPv6 clients, and ircu will
+treat the IPv6 clients correctly.
+
+The DNS resolver has been replaced with a streamlined version (also
+from ircd-hybrid) that avoids some of the complications from using
+the full libresolv or adns libraries.
+
+The server can query an IAUTH external authorization server.  The
+protocol is described in doc/readme.iauth.  This allows an external
+program to accept or reject any client that connects to the server
+and allows that external program to assign an account stamp to the
+incoming user.
+
+A new feature called "oplevels" has been added.  It uses new channel
+keys (+A for the administrator, +U for users) to grant chanop status
+when you join using those keys.  Part of this channel protection is
+that you cannot be deopped in channel by someone who you opped.
+
+A new channel mode, +D, has been added for auditorium-style channels.
+These are channels where most users listen but do not speak or receive
+ops or voice.  The effect of +D is that the server waits to send the
+JOIN message for new users until the user gets ops or voice or sends a
+message to the channel.  A list of join-delayed users in a channel may
+be retrieved by using /NAMES -d #channel.  The response to /NAMES -d
+uses the same format as numeric 353, but uses numeric 355 instead. If
+an op removes +D while there are still join-delayed users, the server
+automatically sets mode +d, and removes +d when the last user's join
+is shown.  It is not possible to set channel mode +d manually; its
+purpose is to warn channel users that there are "hidden" users in the
+channel.
+
+More than one hashing mechanism is now supported for oper passwords,
+and a new tool (ircd/umkpasswd) is provided to generate them.
+
+Commands that send messages to specified services may be defined in
+the configuration file by using Pseudo blocks.  This lets users use
+commands like /X or /CHANSERV from their client, without tying the
+admin to a particular arrangement or naming of services.
+
+The /stats command accepts string identifiers in addition to
+single-character identifiers.  For example, "/stats access" shows the
+same data as "/stats i".  Supported names are shown by /stats.  New
+/stats options are: /stats a (nameservers), to list DNS nameservers in
+use; /stats L (modules), to list loaded modules; and /stats R
+(mappings), to list privmsg helper commands defined by Pseudo blocks.
+By default, all of these are hidden from normal users.
+
+Client blocks (previously I: lines), Operator blocks (previously O:
+and o: lines), channel bans and silences may use CIDR notation instead
+of simple wildcards.  You may also have silence exceptions by putting
+'~' before the mask; for example, if you wish to silence everyone
+except X, you could use SILENCE *!*@*,~X!cservice@undernet.org.
+
+The server will no longer kick "net riders" in keyed (+k) channels if
+both sides of the net join have the same key.
+
+IP masks (as used in bans, G-lines, etc) are now parsed in a more
+forgiving manner.  127.0.0.0/8, 127.* and 127/8 are all accepted and
+mean the same thing.  Ambiguous expressions like 127/8 are interpreted
+as IPv4 masks; to interpret it as an IPv6 mask, use 127:/8.
+
+Configuration Changes:
+
+As mentioned above, the configuration file format has changed
+radically.  Please consult doc/example.conf for details on the
+new format.  Some prominent changes follow.
+
+The old contents of H: lines have been merged into the Connect block
+that describes the peer server(s) that should be allowed to hub.
+
+Two default virtual host addresses may be specified, one for IPv4
+sockets and one for IPv6 sockets.
+
+Nickname jupes have their own blocks, and do not share structure with
+UWorld server declarations.
+
+Operator connection classes and individual operator blocks may be
+assigned privileges, rather than having them controlled globally.
+Because of this, the feature settings that controlled the privileges
+globally have been removed.
+
+The maximum number of clients allowed per IP may be set in a Client
+block (the equivalent of C: lines).
+
+New feature settings (see doc/readme.features for explanations):
+ANNOUNCE_INVITES, HIS_STATS_L, HIS_STATS_a, HIS_STATS_R,
+LOCAL_CHANNELS, TOPIC_BURST.
+
+Deleted features, since they had no effect even in 2.10.11: AUTOHIDE,
+HIS_DESYNCS, TIMESEC.
+
+Deleted features since they are now controlled by other configuration
+entries: VIRTUAL_HOST, oper and locop privilege features.
+
+Deleted feature since it no longer applies: HIS_STATS_h.
+
+Compile Time Options:
+
+A listing of supported compile-time options may be seen by running
+"./configure --help".  The defaults should be sane.  In particular,
+you should NOT compile with --enable-debug or with --disable-symbols
+on a production network.
+
+Otherwise Undocumented Features:
+
+Despite our preferences to keep these undocumented, they are
+occasionally useful, and are described here for users who may
+need them.
+
+To enable these, you need to add them to CFLAGS prior to running
+./configure, usually as in: CFLAGS="-O2 -D<option>" ./configure
+
+-DNICKLEN=20
+
+  This allows you change the maximum nick length from 15 to 20 (or
+whatever number you use at the end).  It MUST be the same on all
+servers on your network, or bad things will happen.  You should also
+use the NICKLEN feature in ircd.conf.
+
+-DNOTHROTTLE
+  This disables the throttling code.  This is used for debugging
+*only*.  It lets you connect up to 255 clients from one host with no
+time considerations.  If this is enabled on a production server Kev will
+personally drive your server into the ground.  You have been warned.
+
+
+Operating System and Kernel Requirements:
+
+If you plan allowing more than 1000 clients on your server, you may
+need to adjust your kernel resource limits for networking and
+I/O. There are two things you will need to pay particular attention
+to, the number of file descriptors available and the number of buffers
+the kernel has available to read and write data to the file
+descriptors.
+
+To calculate kernel buffer requirements a good place to start is to
+multiply the expected number connections expected on the machine by
+the amount of data we buffer for each connection.  Doubling the result
+of the above calculation and dividing it by the size of the buffers
+the kernel uses for I/O should give you a starting place.
+
+The server uses 2K kernel buffers for clients, and 64K kernel buffers
+for servers (actual use may be somewhat higher).
+
+c_count - number of clients expected
+c_q     - number of bytes buffered for each client
+s_count - number of servers expected
+s_q     - number of bytes buffered for each server
+
+buffer count = (2 * (c_count * c_q + s_count * s_q)) / kernel buffer size
+
+If the client count is 2000 and the server count is 1 (normal leaf)
+and your server uses 2K as an I/O buffer size:
+
+You need (2 * (2000 * 2048 + 1 * 65536)) / 2048 or a minimum of 4064
+buffers available, if the kernel uses 512 byte buffers you will need a
+minimum of 16256 kernel buffers.
+
+These settings may be a bit light for net-breaks under full client
+load you will need to experiment a bit to find the right settings for
+your server.
+
+FreeBSD --WildThang
+
+You may want to increase your kernel resources if you want to put a
+lot of clients on your machine here are a few values to start with:
+
+CHILD_MAX=4096
+OPEN_MAX=4096
+FD_SETSIZE=4096
+NMBCLUSTERS=8096
+
+If you have trouble connecting *out* from your machine try:
+ sysctl -w net.inet.ip.portrange.last=10000
+
+Solaris 2.6  --Tar
+
+Increase the default hard limit for file descriptors in /etc/system:
+
+set rlim_fd_max = 4096
+
+The server will raise the soft limit to the hard limit.
+
+Linux 2.2 -- [Tri]/Isomer
+
+The kernel has a kernel destination cache size of 4096.  If the kernel
+sees more than 4096 IP's in 60s it warns 'dst cache overflow'.  This
+limit can be changed by modifying /proc/sys/net/ipv4/route/max_size.
+
+A patch to select is also recommended if you have regular poll/select
+errors.
diff --git a/acinclude.m4 b/acinclude.m4
new file mode 100644 (file)
index 0000000..8181401
--- /dev/null
@@ -0,0 +1,202 @@
+dnl
+dnl Macro: unet_NONBLOCKING
+dnl
+dnl   Check whether we have posix, bsd or sysv non-blocking sockets and
+dnl   define respectively NBLOCK_POSIX, NBLOCK_BSD or NBLOCK_SYSV.
+dnl
+AC_DEFUN([unet_NONBLOCKING],
+[dnl Do we have posix, bsd or sysv non-blocking stuff ?
+AC_CACHE_CHECK([for posix non-blocking], unet_cv_sys_nonblocking_posix,
+[AC_TRY_RUN([#include <sys/types.h>
+#include <sys/socket.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <sys/file.h>
+#include <signal.h>
+$ac_cv_type_signal alarmed() { exit(1); }
+int main(void)
+{
+  char b[12];
+  struct sockaddr x;
+  size_t l = sizeof(x);
+  int f = socket(AF_INET, SOCK_DGRAM, 0);
+  if (f >= 0 && !(fcntl(f, F_SETFL, O_NONBLOCK)))
+  {
+    signal(SIGALRM, alarmed);
+    alarm(2);
+    recvfrom(f, b, 12, 0, &x, &l);
+    alarm(0);
+    exit(0);
+  }
+  exit(1);
+}], unet_cv_sys_nonblocking_posix=yes, unet_cv_sys_nonblocking_posix=no)])
+if test $unet_cv_sys_nonblocking_posix = yes; then
+  AC_DEFINE([NBLOCK_POSIX],,[Define if you have POSIX non-blocking sockets.])
+else
+AC_CACHE_CHECK([for bsd non-blocking], unet_cv_sys_nonblocking_bsd,
+[AC_TRY_RUN([#include <sys/types.h>
+#include <sys/socket.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <sys/file.h>
+#include <signal.h>
+$ac_cv_type_signal alarmed() { exit(1); }
+int main(void)
+{
+  char b[12];
+  struct sockaddr x;
+  size_t l = sizeof(x);
+  int f = socket(AF_INET, SOCK_DGRAM, 0);
+  if (f >= 0 && !(fcntl(f, F_SETFL, O_NDELAY)))
+  {
+    signal(SIGALRM, alarmed);
+    alarm(2);
+    recvfrom(f, b, 12, 0, &x, &l);
+    alarm(0);
+    exit(0);
+  }
+  exit(1);
+}], unet_cv_sys_nonblocking_bsd=yes, unet_cv_sys_nonblocking_bsd=no)])
+if test $unet_cv_sys_nonblocking_bsd = yes; then
+  AC_DEFINE([NBLOCK_BSD],,[Define if you have BSD non-blocking sockets.])
+else
+  AC_DEFINE([NBLOCK_SYSV],,[Define if you have SysV non-blocking sockets.])
+fi
+fi])
+
+dnl
+dnl Macro: unet_SIGNALS
+dnl
+dnl   Check if we have posix signals, reliable bsd signals or
+dnl   unreliable sysv signals and define respectively POSIX_SIGNALS,
+dnl   BSD_RELIABLE_SIGNALS or SYSV_UNRELIABLE_SIGNALS.
+dnl
+AC_DEFUN([unet_SIGNALS],
+[dnl Do we have posix signals, reliable bsd signals or unreliable sysv signals ?
+AC_CACHE_CHECK([for posix signals], unet_cv_sys_signal_posix,
+[AC_TRY_COMPILE([#include <signal.h>],
+[sigaction(SIGTERM, (struct sigaction *)0L, (struct sigaction *)0L)],
+unet_cv_sys_signal_posix=yes, unet_cv_sys_signal_posix=no)])
+if test $unet_cv_sys_signal_posix = yes; then
+  AC_DEFINE([POSIX_SIGNALS],,[Define if you have POSIX signals.])
+else
+AC_CACHE_CHECK([for bsd reliable signals], unet_cv_sys_signal_bsd,
+[AC_TRY_RUN([#include <signal.h>
+int calls = 0;
+$ac_cv_type_signal handler()
+{
+  if (calls) return;
+  calls++;
+  kill(getpid(), SIGTERM);
+  sleep(1);
+}
+int main(void)
+{
+  signal(SIGTERM, handler);
+  kill(getpid(), SIGTERM);
+  exit (0);
+}], unet_cv_sys_signal_bsd=yes, unet_cv_sys_signal_bsd=no)])
+if test $unet_cv_sys_signal_bsd = yes; then
+  AC_DEFINE([BSD_RELIABLE_SIGNALS],,[Define if you have (reliable) BSD signals.])
+else
+  AC_DEFINE([SYSV_UNRELIABLE_SIGNALS],,[Define if you have (unreliable) SysV signals.])
+fi
+fi])
+
+dnl
+dnl Macro: unet_CHECK_TYPE_SIZES
+dnl
+dnl Check the size of several types and define a valid int16_t and int32_t.
+dnl
+AC_DEFUN([unet_CHECK_TYPE_SIZES],
+[dnl Check type sizes
+AC_CHECK_SIZEOF(short)
+AC_CHECK_SIZEOF(int)
+AC_CHECK_SIZEOF(long)
+AC_CHECK_SIZEOF(void *)
+AC_CHECK_SIZEOF(int64_t)
+AC_CHECK_SIZEOF(long long)
+if test "$ac_cv_sizeof_int" = 2 ; then
+  AC_CHECK_TYPE(int16_t, int)
+  AC_CHECK_TYPE(uint16_t, unsigned int)
+elif test "$ac_cv_sizeof_short" = 2 ; then
+  AC_CHECK_TYPE(int16_t, short)
+  AC_CHECK_TYPE(uint16_t, unsigned short)
+else
+  AC_MSG_ERROR([Cannot find a type with size of 16 bits])
+fi
+if test "$ac_cv_sizeof_int" = 4 ; then
+  AC_CHECK_TYPE(int32_t, int)
+  AC_CHECK_TYPE(uint32_t, unsigned int)
+elif test "$ac_cv_sizeof_short" = 4 ; then
+  AC_CHECK_TYPE(int32_t, short)
+  AC_CHECK_TYPE(uint32_t, unsigned short)
+elif test "$ac_cv_sizeof_long" = 4 ; then
+  AC_CHECK_TYPE(int32_t, long)
+  AC_CHECK_TYPE(uint32_t, unsigned long)
+else
+  AC_MSG_ERROR([Cannot find a type with size of 32 bits])
+fi
+if test "$ac_cv_sizeof_int64_t" = 8 ; then
+  AC_CHECK_TYPE(int64_t)
+  AC_CHECK_TYPE(uint64_t)
+elif test "$ac_cv_sizeof_long_long" = 8 ; then
+  AC_CHECK_TYPE(int64_t, long long)
+  AC_CHECK_TYPE(uint64_t, unsigned long long)
+else
+  AC_MSG_ERROR([Cannot find a type with size of 64 bits])
+fi])
+
+dnl Written by John Hawkinson <jhawk@mit.edu>. This code is in the Public
+dnl Domain.
+dnl
+dnl This test is for network applications that need socket() and
+dnl gethostbyname() -ish functions.  Under Solaris, those applications need to
+dnl link with "-lsocket -lnsl".  Under IRIX, they should *not* link with
+dnl "-lsocket" because libsocket.a breaks a number of things (for instance:
+dnl gethostbyname() under IRIX 5.2, and snoop sockets under most versions of
+dnl IRIX).
+dnl 
+dnl Unfortunately, many application developers are not aware of this, and
+dnl mistakenly write tests that cause -lsocket to be used under IRIX.  It is
+dnl also easy to write tests that cause -lnsl to be used under operating
+dnl systems where neither are necessary (or useful), such as SunOS 4.1.4, which
+dnl uses -lnsl for TLI.
+dnl 
+dnl This test exists so that every application developer does not test this in
+dnl a different, and subtly broken fashion.
+dnl 
+dnl It has been argued that this test should be broken up into two seperate
+dnl tests, one for the resolver libraries, and one for the libraries necessary
+dnl for using Sockets API. Unfortunately, the two are carefully intertwined and
+dnl allowing the autoconf user to use them independantly potentially results in
+dnl unfortunate ordering dependancies -- as such, such component macros would
+dnl have to carefully use indirection and be aware if the other components were
+dnl executed. Since other autoconf macros do not go to this trouble, and almost
+dnl no applications use sockets without the resolver, this complexity has not
+dnl been implemented.
+dnl
+dnl The check for libresolv is in case you are attempting to link statically
+dnl and happen to have a libresolv.a lying around (and no libnsl.a).
+dnl
+AC_DEFUN([AC_LIBRARY_NET], [
+   # Most operating systems have gethostbyname() in the default searched
+   # libraries (i.e. libc):
+   AC_CHECK_FUNC(gethostbyname, ,
+     # Some OSes (eg. Solaris) place it in libnsl:
+     AC_CHECK_LIB(nsl, gethostbyname, , 
+       # Some strange OSes (SINIX) have it in libsocket:
+       AC_CHECK_LIB(socket, gethostbyname, ,
+          # Unfortunately libsocket sometimes depends on libnsl.
+          # AC_CHECK_LIB's API is essentially broken so the following
+          # ugliness is necessary:
+          AC_CHECK_LIB(socket, gethostbyname,
+             LIBS="-lsocket -lnsl $LIBS",
+               AC_CHECK_LIB(resolv, gethostbyname),
+             -lnsl)
+       )
+     )
+   )
+  AC_CHECK_FUNC(socket, , AC_CHECK_LIB(socket, socket, ,
+    AC_CHECK_LIB(socket, socket, LIBS="-lsocket -lnsl $LIBS", , -lnsl)))
+  ])
diff --git a/aclocal.m4 b/aclocal.m4
new file mode 100644 (file)
index 0000000..38c55ce
--- /dev/null
@@ -0,0 +1,37 @@
+# generated automatically by aclocal 1.10.1 -*- Autoconf -*-
+
+# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
+# 2005, 2006, 2007, 2008  Free Software Foundation, Inc.
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+
+# Copyright (C) 1996, 1997, 1999, 2000, 2001, 2002, 2003, 2005
+# Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# serial 4
+
+# This was merged into AC_PROG_CC in Autoconf.
+
+AU_DEFUN([AM_PROG_CC_STDC],
+[AC_PROG_CC
+AC_DIAGNOSE([obsolete], [$0:
+       your code should no longer depend upon `am_cv_prog_cc_stdc', but upon
+       `ac_cv_prog_cc_stdc'.  Remove this warning and the assignment when
+       you adjust the code.  You can also remove the above call to
+       AC_PROG_CC if you already called it elsewhere.])
+am_cv_prog_cc_stdc=$ac_cv_prog_cc_stdc
+])
+AU_DEFUN([fp_PROG_CC_STDC])
+
+m4_include([acinclude.m4])
diff --git a/autom4te.cache/output.0 b/autom4te.cache/output.0
new file mode 100644 (file)
index 0000000..d6a2ace
--- /dev/null
@@ -0,0 +1,12623 @@
+@%:@! /bin/sh
+@%:@ Guess values for system-dependent variables and create Makefiles.
+@%:@ Generated by GNU Autoconf 2.61.
+@%:@ 
+@%:@ Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001,
+@%:@ 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
+@%:@ This configure script is free software; the Free Software Foundation
+@%:@ gives unlimited permission to copy, distribute and modify it.
+## --------------------- ##
+## M4sh Initialization.  ##
+## --------------------- ##
+
+# Be more Bourne compatible
+DUALCASE=1; export DUALCASE # for MKS sh
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then
+  emulate sh
+  NULLCMD=:
+  # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which
+  # is contrary to our usage.  Disable this feature.
+  alias -g '${1+"$@"}'='"$@"'
+  setopt NO_GLOB_SUBST
+else
+  case `(set -o) 2>/dev/null` in
+  *posix*) set -o posix ;;
+esac
+
+fi
+
+
+
+
+# PATH needs CR
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+  echo "#! /bin/sh" >conf$$.sh
+  echo  "exit 0"   >>conf$$.sh
+  chmod +x conf$$.sh
+  if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then
+    PATH_SEPARATOR=';'
+  else
+    PATH_SEPARATOR=:
+  fi
+  rm -f conf$$.sh
+fi
+
+# Support unset when possible.
+if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then
+  as_unset=unset
+else
+  as_unset=false
+fi
+
+
+# IFS
+# We need space, tab and new line, in precisely that order.  Quoting is
+# there to prevent editors from complaining about space-tab.
+# (If _AS_PATH_WALK were called with IFS unset, it would disable word
+# splitting by setting IFS to empty value.)
+as_nl='
+'
+IFS=" ""       $as_nl"
+
+# Find who we are.  Look in the path if we contain no directory separator.
+case $0 in
+  *[\\/]* ) as_myself=$0 ;;
+  *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+done
+IFS=$as_save_IFS
+
+     ;;
+esac
+# We did not find ourselves, most probably we were run as `sh COMMAND'
+# in which case we are not to be found in the path.
+if test "x$as_myself" = x; then
+  as_myself=$0
+fi
+if test ! -f "$as_myself"; then
+  echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
+  { (exit 1); exit 1; }
+fi
+
+# Work around bugs in pre-3.0 UWIN ksh.
+for as_var in ENV MAIL MAILPATH
+do ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var
+done
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+for as_var in \
+  LANG LANGUAGE LC_ADDRESS LC_ALL LC_COLLATE LC_CTYPE LC_IDENTIFICATION \
+  LC_MEASUREMENT LC_MESSAGES LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER \
+  LC_TELEPHONE LC_TIME
+do
+  if (set +x; test -z "`(eval $as_var=C; export $as_var) 2>&1`"); then
+    eval $as_var=C; export $as_var
+  else
+    ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var
+  fi
+done
+
+# Required to use basename.
+if expr a : '\(a\)' >/dev/null 2>&1 &&
+   test "X`expr 00001 : '.*\(...\)'`" = X001; then
+  as_expr=expr
+else
+  as_expr=false
+fi
+
+if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then
+  as_basename=basename
+else
+  as_basename=false
+fi
+
+
+# Name of the executable.
+as_me=`$as_basename -- "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+        X"$0" : 'X\(//\)$' \| \
+        X"$0" : 'X\(/\)' \| . 2>/dev/null ||
+echo X/"$0" |
+    sed '/^.*\/\([^/][^/]*\)\/*$/{
+           s//\1/
+           q
+         }
+         /^X\/\(\/\/\)$/{
+           s//\1/
+           q
+         }
+         /^X\/\(\/\).*/{
+           s//\1/
+           q
+         }
+         s/.*/./; q'`
+
+# CDPATH.
+$as_unset CDPATH
+
+
+if test "x$CONFIG_SHELL" = x; then
+  if (eval ":") 2>/dev/null; then
+  as_have_required=yes
+else
+  as_have_required=no
+fi
+
+  if test $as_have_required = yes &&    (eval ":
+(as_func_return () {
+  (exit \$1)
+}
+as_func_success () {
+  as_func_return 0
+}
+as_func_failure () {
+  as_func_return 1
+}
+as_func_ret_success () {
+  return 0
+}
+as_func_ret_failure () {
+  return 1
+}
+
+exitcode=0
+if as_func_success; then
+  :
+else
+  exitcode=1
+  echo as_func_success failed.
+fi
+
+if as_func_failure; then
+  exitcode=1
+  echo as_func_failure succeeded.
+fi
+
+if as_func_ret_success; then
+  :
+else
+  exitcode=1
+  echo as_func_ret_success failed.
+fi
+
+if as_func_ret_failure; then
+  exitcode=1
+  echo as_func_ret_failure succeeded.
+fi
+
+if ( set x; as_func_ret_success y && test x = \"\$1\" ); then
+  :
+else
+  exitcode=1
+  echo positional parameters were not saved.
+fi
+
+test \$exitcode = 0) || { (exit 1); exit 1; }
+
+(
+  as_lineno_1=\$LINENO
+  as_lineno_2=\$LINENO
+  test \"x\$as_lineno_1\" != \"x\$as_lineno_2\" &&
+  test \"x\`expr \$as_lineno_1 + 1\`\" = \"x\$as_lineno_2\") || { (exit 1); exit 1; }
+") 2> /dev/null; then
+  :
+else
+  as_candidate_shells=
+    as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  case $as_dir in
+        /*)
+          for as_base in sh bash ksh sh5; do
+            as_candidate_shells="$as_candidate_shells $as_dir/$as_base"
+          done;;
+       esac
+done
+IFS=$as_save_IFS
+
+
+      for as_shell in $as_candidate_shells $SHELL; do
+        # Try only shells that exist, to save several forks.
+        if { test -f "$as_shell" || test -f "$as_shell.exe"; } &&
+               { ("$as_shell") 2> /dev/null <<\_ASEOF
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then
+  emulate sh
+  NULLCMD=:
+  # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which
+  # is contrary to our usage.  Disable this feature.
+  alias -g '${1+"$@"}'='"$@"'
+  setopt NO_GLOB_SUBST
+else
+  case `(set -o) 2>/dev/null` in
+  *posix*) set -o posix ;;
+esac
+
+fi
+
+
+:
+_ASEOF
+}; then
+  CONFIG_SHELL=$as_shell
+              as_have_required=yes
+              if { "$as_shell" 2> /dev/null <<\_ASEOF
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then
+  emulate sh
+  NULLCMD=:
+  # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which
+  # is contrary to our usage.  Disable this feature.
+  alias -g '${1+"$@"}'='"$@"'
+  setopt NO_GLOB_SUBST
+else
+  case `(set -o) 2>/dev/null` in
+  *posix*) set -o posix ;;
+esac
+
+fi
+
+
+:
+(as_func_return () {
+  (exit $1)
+}
+as_func_success () {
+  as_func_return 0
+}
+as_func_failure () {
+  as_func_return 1
+}
+as_func_ret_success () {
+  return 0
+}
+as_func_ret_failure () {
+  return 1
+}
+
+exitcode=0
+if as_func_success; then
+  :
+else
+  exitcode=1
+  echo as_func_success failed.
+fi
+
+if as_func_failure; then
+  exitcode=1
+  echo as_func_failure succeeded.
+fi
+
+if as_func_ret_success; then
+  :
+else
+  exitcode=1
+  echo as_func_ret_success failed.
+fi
+
+if as_func_ret_failure; then
+  exitcode=1
+  echo as_func_ret_failure succeeded.
+fi
+
+if ( set x; as_func_ret_success y && test x = "$1" ); then
+  :
+else
+  exitcode=1
+  echo positional parameters were not saved.
+fi
+
+test $exitcode = 0) || { (exit 1); exit 1; }
+
+(
+  as_lineno_1=$LINENO
+  as_lineno_2=$LINENO
+  test "x$as_lineno_1" != "x$as_lineno_2" &&
+  test "x`expr $as_lineno_1 + 1`" = "x$as_lineno_2") || { (exit 1); exit 1; }
+
+_ASEOF
+}; then
+  break
+fi
+
+fi
+
+      done
+
+      if test "x$CONFIG_SHELL" != x; then
+  for as_var in BASH_ENV ENV
+        do ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var
+        done
+        export CONFIG_SHELL
+        exec "$CONFIG_SHELL" "$as_myself" ${1+"$@"}
+fi
+
+
+    if test $as_have_required = no; then
+  echo This script requires a shell more modern than all the
+      echo shells that I found on your system.  Please install a
+      echo modern shell, or manually run the script under such a
+      echo shell if you do have one.
+      { (exit 1); exit 1; }
+fi
+
+    
+fi
+
+fi
+
+
+
+(eval "as_func_return () {
+  (exit \$1)
+}
+as_func_success () {
+  as_func_return 0
+}
+as_func_failure () {
+  as_func_return 1
+}
+as_func_ret_success () {
+  return 0
+}
+as_func_ret_failure () {
+  return 1
+}
+
+exitcode=0
+if as_func_success; then
+  :
+else
+  exitcode=1
+  echo as_func_success failed.
+fi
+
+if as_func_failure; then
+  exitcode=1
+  echo as_func_failure succeeded.
+fi
+
+if as_func_ret_success; then
+  :
+else
+  exitcode=1
+  echo as_func_ret_success failed.
+fi
+
+if as_func_ret_failure; then
+  exitcode=1
+  echo as_func_ret_failure succeeded.
+fi
+
+if ( set x; as_func_ret_success y && test x = \"\$1\" ); then
+  :
+else
+  exitcode=1
+  echo positional parameters were not saved.
+fi
+
+test \$exitcode = 0") || {
+  echo No shell found that supports shell functions.
+  echo Please tell autoconf@gnu.org about your system,
+  echo including any error possibly output before this
+  echo message
+}
+
+
+
+  as_lineno_1=$LINENO
+  as_lineno_2=$LINENO
+  test "x$as_lineno_1" != "x$as_lineno_2" &&
+  test "x`expr $as_lineno_1 + 1`" = "x$as_lineno_2" || {
+
+  # Create $as_me.lineno as a copy of $as_myself, but with $LINENO
+  # uniformly replaced by the line number.  The first 'sed' inserts a
+  # line-number line after each line using $LINENO; the second 'sed'
+  # does the real work.  The second script uses 'N' to pair each
+  # line-number line with the line containing $LINENO, and appends
+  # trailing '-' during substitution so that $LINENO is not a special
+  # case at line end.
+  # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the
+  # scripts with optimization help from Paolo Bonzini.  Blame Lee
+  # E. McMahon (1931-1989) for sed's syntax.  :-)
+  sed -n '
+    p
+    /[$]LINENO/=
+  ' <$as_myself |
+    sed '
+      s/[$]LINENO.*/&-/
+      t lineno
+      b
+      :lineno
+      N
+      :loop
+      s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/
+      t loop
+      s/-\n.*//
+    ' >$as_me.lineno &&
+  chmod +x "$as_me.lineno" ||
+    { echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2
+   { (exit 1); exit 1; }; }
+
+  # Don't try to exec as it changes $[0], causing all sort of problems
+  # (the dirname of $[0] is not the place where we might find the
+  # original and so on.  Autoconf is especially sensitive to this).
+  . "./$as_me.lineno"
+  # Exit status is that of the last command.
+  exit
+}
+
+
+if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
+  as_dirname=dirname
+else
+  as_dirname=false
+fi
+
+ECHO_C= ECHO_N= ECHO_T=
+case `echo -n x` in
+-n*)
+  case `echo 'x\c'` in
+  *c*) ECHO_T='        ';;     # ECHO_T is single tab character.
+  *)   ECHO_C='\c';;
+  esac;;
+*)
+  ECHO_N='-n';;
+esac
+
+if expr a : '\(a\)' >/dev/null 2>&1 &&
+   test "X`expr 00001 : '.*\(...\)'`" = X001; then
+  as_expr=expr
+else
+  as_expr=false
+fi
+
+rm -f conf$$ conf$$.exe conf$$.file
+if test -d conf$$.dir; then
+  rm -f conf$$.dir/conf$$.file
+else
+  rm -f conf$$.dir
+  mkdir conf$$.dir
+fi
+echo >conf$$.file
+if ln -s conf$$.file conf$$ 2>/dev/null; then
+  as_ln_s='ln -s'
+  # ... but there are two gotchas:
+  # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
+  # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
+  # In both cases, we have to default to `cp -p'.
+  ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
+    as_ln_s='cp -p'
+elif ln conf$$.file conf$$ 2>/dev/null; then
+  as_ln_s=ln
+else
+  as_ln_s='cp -p'
+fi
+rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
+rmdir conf$$.dir 2>/dev/null
+
+if mkdir -p . 2>/dev/null; then
+  as_mkdir_p=:
+else
+  test -d ./-p && rmdir ./-p
+  as_mkdir_p=false
+fi
+
+if test -x / >/dev/null 2>&1; then
+  as_test_x='test -x'
+else
+  if ls -dL / >/dev/null 2>&1; then
+    as_ls_L_option=L
+  else
+    as_ls_L_option=
+  fi
+  as_test_x='
+    eval sh -c '\''
+      if test -d "$1"; then
+        test -d "$1/.";
+      else
+       case $1 in
+        -*)set "./$1";;
+       esac;
+       case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in
+       ???[sx]*):;;*)false;;esac;fi
+    '\'' sh
+  '
+fi
+as_executable_p=$as_test_x
+
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
+
+# Sed expression to map a string onto a valid variable name.
+as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
+
+
+
+exec 7<&0 </dev/null 6>&1
+
+# Name of the host.
+# hostname on some systems (SVR3.2, Linux) returns a bogus exit status,
+# so uname gets run too.
+ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q`
+
+#
+# Initializations.
+#
+ac_default_prefix=/usr/local
+ac_clean_files=
+ac_config_libobj_dir=.
+LIB@&t@OBJS=
+cross_compiling=no
+subdirs=
+MFLAGS=
+MAKEFLAGS=
+SHELL=${CONFIG_SHELL-/bin/sh}
+
+# Identity of this package.
+PACKAGE_NAME=
+PACKAGE_TARNAME=
+PACKAGE_VERSION=
+PACKAGE_STRING=
+PACKAGE_BUGREPORT=
+
+ac_unique_file="ircd/ircd.c"
+ac_default_prefix=$HOME
+# Factoring default headers for most tests.
+ac_includes_default="\
+#include <stdio.h>
+#ifdef HAVE_SYS_TYPES_H
+# include <sys/types.h>
+#endif
+#ifdef HAVE_SYS_STAT_H
+# include <sys/stat.h>
+#endif
+#ifdef STDC_HEADERS
+# include <stdlib.h>
+# include <stddef.h>
+#else
+# ifdef HAVE_STDLIB_H
+#  include <stdlib.h>
+# endif
+#endif
+#ifdef HAVE_STRING_H
+# if !defined STDC_HEADERS && defined HAVE_MEMORY_H
+#  include <memory.h>
+# endif
+# include <string.h>
+#endif
+#ifdef HAVE_STRINGS_H
+# include <strings.h>
+#endif
+#ifdef HAVE_INTTYPES_H
+# include <inttypes.h>
+#endif
+#ifdef HAVE_STDINT_H
+# include <stdint.h>
+#endif
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif"
+
+ac_subst_vars='SHELL
+PATH_SEPARATOR
+PACKAGE_NAME
+PACKAGE_TARNAME
+PACKAGE_VERSION
+PACKAGE_STRING
+PACKAGE_BUGREPORT
+exec_prefix
+prefix
+program_transform_name
+bindir
+sbindir
+libexecdir
+datarootdir
+datadir
+sysconfdir
+sharedstatedir
+localstatedir
+includedir
+oldincludedir
+docdir
+infodir
+htmldir
+dvidir
+pdfdir
+psdir
+libdir
+localedir
+mandir
+DEFS
+ECHO_C
+ECHO_N
+ECHO_T
+LIBS
+build_alias
+host_alias
+target_alias
+build
+build_cpu
+build_vendor
+build_os
+host
+host_cpu
+host_vendor
+host_os
+CC
+CFLAGS
+LDFLAGS
+CPPFLAGS
+ac_ct_CC
+EXEEXT
+OBJEXT
+CPP
+GREP
+EGREP
+AWK
+SET_MAKE
+INSTALL_PROGRAM
+INSTALL_SCRIPT
+INSTALL_DATA
+LN_S
+RMPROG
+SHPROG
+LEX
+LEX_OUTPUT_ROOT
+LEXLIB
+YACC
+YFLAGS
+ENGINE_C
+INSTALL_RULE
+SYMLINK
+IRCDMODE
+IRCDOWN
+IRCDGRP
+DPATH
+LIB@&t@OBJS
+LTLIBOBJS'
+ac_subst_files=''
+      ac_precious_vars='build_alias
+host_alias
+target_alias
+CC
+CFLAGS
+LDFLAGS
+LIBS
+CPPFLAGS
+CPP
+YACC
+YFLAGS'
+
+
+# Initialize some variables set by options.
+ac_init_help=
+ac_init_version=false
+# The variables have the same names as the options, with
+# dashes changed to underlines.
+cache_file=/dev/null
+exec_prefix=NONE
+no_create=
+no_recursion=
+prefix=NONE
+program_prefix=NONE
+program_suffix=NONE
+program_transform_name=s,x,x,
+silent=
+site=
+srcdir=
+verbose=
+x_includes=NONE
+x_libraries=NONE
+
+# Installation directory options.
+# These are left unexpanded so users can "make install exec_prefix=/foo"
+# and all the variables that are supposed to be based on exec_prefix
+# by default will actually change.
+# Use braces instead of parens because sh, perl, etc. also accept them.
+# (The list follows the same order as the GNU Coding Standards.)
+bindir='${exec_prefix}/bin'
+sbindir='${exec_prefix}/sbin'
+libexecdir='${exec_prefix}/libexec'
+datarootdir='${prefix}/share'
+datadir='${datarootdir}'
+sysconfdir='${prefix}/etc'
+sharedstatedir='${prefix}/com'
+localstatedir='${prefix}/var'
+includedir='${prefix}/include'
+oldincludedir='/usr/include'
+docdir='${datarootdir}/doc/${PACKAGE}'
+infodir='${datarootdir}/info'
+htmldir='${docdir}'
+dvidir='${docdir}'
+pdfdir='${docdir}'
+psdir='${docdir}'
+libdir='${exec_prefix}/lib'
+localedir='${datarootdir}/locale'
+mandir='${datarootdir}/man'
+
+ac_prev=
+ac_dashdash=
+for ac_option
+do
+  # If the previous option needs an argument, assign it.
+  if test -n "$ac_prev"; then
+    eval $ac_prev=\$ac_option
+    ac_prev=
+    continue
+  fi
+
+  case $ac_option in
+  *=*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;;
+  *)   ac_optarg=yes ;;
+  esac
+
+  # Accept the important Cygnus configure options, so we can diagnose typos.
+
+  case $ac_dashdash$ac_option in
+  --)
+    ac_dashdash=yes ;;
+
+  -bindir | --bindir | --bindi | --bind | --bin | --bi)
+    ac_prev=bindir ;;
+  -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*)
+    bindir=$ac_optarg ;;
+
+  -build | --build | --buil | --bui | --bu)
+    ac_prev=build_alias ;;
+  -build=* | --build=* | --buil=* | --bui=* | --bu=*)
+    build_alias=$ac_optarg ;;
+
+  -cache-file | --cache-file | --cache-fil | --cache-fi \
+  | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c)
+    ac_prev=cache_file ;;
+  -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \
+  | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*)
+    cache_file=$ac_optarg ;;
+
+  --config-cache | -C)
+    cache_file=config.cache ;;
+
+  -datadir | --datadir | --datadi | --datad)
+    ac_prev=datadir ;;
+  -datadir=* | --datadir=* | --datadi=* | --datad=*)
+    datadir=$ac_optarg ;;
+
+  -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \
+  | --dataroo | --dataro | --datar)
+    ac_prev=datarootdir ;;
+  -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \
+  | --dataroot=* | --dataroo=* | --dataro=* | --datar=*)
+    datarootdir=$ac_optarg ;;
+
+  -disable-* | --disable-*)
+    ac_feature=`expr "x$ac_option" : 'x-*disable-\(.*\)'`
+    # Reject names that are not valid shell variable names.
+    expr "x$ac_feature" : ".*[^-._$as_cr_alnum]" >/dev/null &&
+      { echo "$as_me: error: invalid feature name: $ac_feature" >&2
+   { (exit 1); exit 1; }; }
+    ac_feature=`echo $ac_feature | sed 's/[-.]/_/g'`
+    eval enable_$ac_feature=no ;;
+
+  -docdir | --docdir | --docdi | --doc | --do)
+    ac_prev=docdir ;;
+  -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*)
+    docdir=$ac_optarg ;;
+
+  -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv)
+    ac_prev=dvidir ;;
+  -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*)
+    dvidir=$ac_optarg ;;
+
+  -enable-* | --enable-*)
+    ac_feature=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'`
+    # Reject names that are not valid shell variable names.
+    expr "x$ac_feature" : ".*[^-._$as_cr_alnum]" >/dev/null &&
+      { echo "$as_me: error: invalid feature name: $ac_feature" >&2
+   { (exit 1); exit 1; }; }
+    ac_feature=`echo $ac_feature | sed 's/[-.]/_/g'`
+    eval enable_$ac_feature=\$ac_optarg ;;
+
+  -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \
+  | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \
+  | --exec | --exe | --ex)
+    ac_prev=exec_prefix ;;
+  -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \
+  | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \
+  | --exec=* | --exe=* | --ex=*)
+    exec_prefix=$ac_optarg ;;
+
+  -gas | --gas | --ga | --g)
+    # Obsolete; use --with-gas.
+    with_gas=yes ;;
+
+  -help | --help | --hel | --he | -h)
+    ac_init_help=long ;;
+  -help=r* | --help=r* | --hel=r* | --he=r* | -hr*)
+    ac_init_help=recursive ;;
+  -help=s* | --help=s* | --hel=s* | --he=s* | -hs*)
+    ac_init_help=short ;;
+
+  -host | --host | --hos | --ho)
+    ac_prev=host_alias ;;
+  -host=* | --host=* | --hos=* | --ho=*)
+    host_alias=$ac_optarg ;;
+
+  -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht)
+    ac_prev=htmldir ;;
+  -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \
+  | --ht=*)
+    htmldir=$ac_optarg ;;
+
+  -includedir | --includedir | --includedi | --included | --include \
+  | --includ | --inclu | --incl | --inc)
+    ac_prev=includedir ;;
+  -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \
+  | --includ=* | --inclu=* | --incl=* | --inc=*)
+    includedir=$ac_optarg ;;
+
+  -infodir | --infodir | --infodi | --infod | --info | --inf)
+    ac_prev=infodir ;;
+  -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*)
+    infodir=$ac_optarg ;;
+
+  -libdir | --libdir | --libdi | --libd)
+    ac_prev=libdir ;;
+  -libdir=* | --libdir=* | --libdi=* | --libd=*)
+    libdir=$ac_optarg ;;
+
+  -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \
+  | --libexe | --libex | --libe)
+    ac_prev=libexecdir ;;
+  -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \
+  | --libexe=* | --libex=* | --libe=*)
+    libexecdir=$ac_optarg ;;
+
+  -localedir | --localedir | --localedi | --localed | --locale)
+    ac_prev=localedir ;;
+  -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*)
+    localedir=$ac_optarg ;;
+
+  -localstatedir | --localstatedir | --localstatedi | --localstated \
+  | --localstate | --localstat | --localsta | --localst | --locals)
+    ac_prev=localstatedir ;;
+  -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \
+  | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*)
+    localstatedir=$ac_optarg ;;
+
+  -mandir | --mandir | --mandi | --mand | --man | --ma | --m)
+    ac_prev=mandir ;;
+  -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*)
+    mandir=$ac_optarg ;;
+
+  -nfp | --nfp | --nf)
+    # Obsolete; use --without-fp.
+    with_fp=no ;;
+
+  -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+  | --no-cr | --no-c | -n)
+    no_create=yes ;;
+
+  -no-recursion | --no-recursion | --no-recursio | --no-recursi \
+  | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r)
+    no_recursion=yes ;;
+
+  -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \
+  | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \
+  | --oldin | --oldi | --old | --ol | --o)
+    ac_prev=oldincludedir ;;
+  -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \
+  | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \
+  | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*)
+    oldincludedir=$ac_optarg ;;
+
+  -prefix | --prefix | --prefi | --pref | --pre | --pr | --p)
+    ac_prev=prefix ;;
+  -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*)
+    prefix=$ac_optarg ;;
+
+  -program-prefix | --program-prefix | --program-prefi | --program-pref \
+  | --program-pre | --program-pr | --program-p)
+    ac_prev=program_prefix ;;
+  -program-prefix=* | --program-prefix=* | --program-prefi=* \
+  | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*)
+    program_prefix=$ac_optarg ;;
+
+  -program-suffix | --program-suffix | --program-suffi | --program-suff \
+  | --program-suf | --program-su | --program-s)
+    ac_prev=program_suffix ;;
+  -program-suffix=* | --program-suffix=* | --program-suffi=* \
+  | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*)
+    program_suffix=$ac_optarg ;;
+
+  -program-transform-name | --program-transform-name \
+  | --program-transform-nam | --program-transform-na \
+  | --program-transform-n | --program-transform- \
+  | --program-transform | --program-transfor \
+  | --program-transfo | --program-transf \
+  | --program-trans | --program-tran \
+  | --progr-tra | --program-tr | --program-t)
+    ac_prev=program_transform_name ;;
+  -program-transform-name=* | --program-transform-name=* \
+  | --program-transform-nam=* | --program-transform-na=* \
+  | --program-transform-n=* | --program-transform-=* \
+  | --program-transform=* | --program-transfor=* \
+  | --program-transfo=* | --program-transf=* \
+  | --program-trans=* | --program-tran=* \
+  | --progr-tra=* | --program-tr=* | --program-t=*)
+    program_transform_name=$ac_optarg ;;
+
+  -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd)
+    ac_prev=pdfdir ;;
+  -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*)
+    pdfdir=$ac_optarg ;;
+
+  -psdir | --psdir | --psdi | --psd | --ps)
+    ac_prev=psdir ;;
+  -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*)
+    psdir=$ac_optarg ;;
+
+  -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+  | -silent | --silent | --silen | --sile | --sil)
+    silent=yes ;;
+
+  -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
+    ac_prev=sbindir ;;
+  -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
+  | --sbi=* | --sb=*)
+    sbindir=$ac_optarg ;;
+
+  -sharedstatedir | --sharedstatedir | --sharedstatedi \
+  | --sharedstated | --sharedstate | --sharedstat | --sharedsta \
+  | --sharedst | --shareds | --shared | --share | --shar \
+  | --sha | --sh)
+    ac_prev=sharedstatedir ;;
+  -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \
+  | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \
+  | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \
+  | --sha=* | --sh=*)
+    sharedstatedir=$ac_optarg ;;
+
+  -site | --site | --sit)
+    ac_prev=site ;;
+  -site=* | --site=* | --sit=*)
+    site=$ac_optarg ;;
+
+  -srcdir | --srcdir | --srcdi | --srcd | --src | --sr)
+    ac_prev=srcdir ;;
+  -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*)
+    srcdir=$ac_optarg ;;
+
+  -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \
+  | --syscon | --sysco | --sysc | --sys | --sy)
+    ac_prev=sysconfdir ;;
+  -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \
+  | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*)
+    sysconfdir=$ac_optarg ;;
+
+  -target | --target | --targe | --targ | --tar | --ta | --t)
+    ac_prev=target_alias ;;
+  -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*)
+    target_alias=$ac_optarg ;;
+
+  -v | -verbose | --verbose | --verbos | --verbo | --verb)
+    verbose=yes ;;
+
+  -version | --version | --versio | --versi | --vers | -V)
+    ac_init_version=: ;;
+
+  -with-* | --with-*)
+    ac_package=`expr "x$ac_option" : 'x-*with-\([^=]*\)'`
+    # Reject names that are not valid shell variable names.
+    expr "x$ac_package" : ".*[^-._$as_cr_alnum]" >/dev/null &&
+      { echo "$as_me: error: invalid package name: $ac_package" >&2
+   { (exit 1); exit 1; }; }
+    ac_package=`echo $ac_package | sed 's/[-.]/_/g'`
+    eval with_$ac_package=\$ac_optarg ;;
+
+  -without-* | --without-*)
+    ac_package=`expr "x$ac_option" : 'x-*without-\(.*\)'`
+    # Reject names that are not valid shell variable names.
+    expr "x$ac_package" : ".*[^-._$as_cr_alnum]" >/dev/null &&
+      { echo "$as_me: error: invalid package name: $ac_package" >&2
+   { (exit 1); exit 1; }; }
+    ac_package=`echo $ac_package | sed 's/[-.]/_/g'`
+    eval with_$ac_package=no ;;
+
+  --x)
+    # Obsolete; use --with-x.
+    with_x=yes ;;
+
+  -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \
+  | --x-incl | --x-inc | --x-in | --x-i)
+    ac_prev=x_includes ;;
+  -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \
+  | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*)
+    x_includes=$ac_optarg ;;
+
+  -x-libraries | --x-libraries | --x-librarie | --x-librari \
+  | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l)
+    ac_prev=x_libraries ;;
+  -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \
+  | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*)
+    x_libraries=$ac_optarg ;;
+
+  -*) { echo "$as_me: error: unrecognized option: $ac_option
+Try \`$0 --help' for more information." >&2
+   { (exit 1); exit 1; }; }
+    ;;
+
+  *=*)
+    ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='`
+    # Reject names that are not valid shell variable names.
+    expr "x$ac_envvar" : ".*[^_$as_cr_alnum]" >/dev/null &&
+      { echo "$as_me: error: invalid variable name: $ac_envvar" >&2
+   { (exit 1); exit 1; }; }
+    eval $ac_envvar=\$ac_optarg
+    export $ac_envvar ;;
+
+  *)
+    # FIXME: should be removed in autoconf 3.0.
+    echo "$as_me: WARNING: you should use --build, --host, --target" >&2
+    expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null &&
+      echo "$as_me: WARNING: invalid host type: $ac_option" >&2
+    : ${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}
+    ;;
+
+  esac
+done
+
+if test -n "$ac_prev"; then
+  ac_option=--`echo $ac_prev | sed 's/_/-/g'`
+  { echo "$as_me: error: missing argument to $ac_option" >&2
+   { (exit 1); exit 1; }; }
+fi
+
+# Be sure to have absolute directory names.
+for ac_var in  exec_prefix prefix bindir sbindir libexecdir datarootdir \
+               datadir sysconfdir sharedstatedir localstatedir includedir \
+               oldincludedir docdir infodir htmldir dvidir pdfdir psdir \
+               libdir localedir mandir
+do
+  eval ac_val=\$$ac_var
+  case $ac_val in
+    [\\/$]* | ?:[\\/]* )  continue;;
+    NONE | '' ) case $ac_var in *prefix ) continue;; esac;;
+  esac
+  { echo "$as_me: error: expected an absolute directory name for --$ac_var: $ac_val" >&2
+   { (exit 1); exit 1; }; }
+done
+
+# There might be people who depend on the old broken behavior: `$host'
+# used to hold the argument of --host etc.
+# FIXME: To remove some day.
+build=$build_alias
+host=$host_alias
+target=$target_alias
+
+# FIXME: To remove some day.
+if test "x$host_alias" != x; then
+  if test "x$build_alias" = x; then
+    cross_compiling=maybe
+    echo "$as_me: WARNING: If you wanted to set the --build type, don't use --host.
+    If a cross compiler is detected then cross compile mode will be used." >&2
+  elif test "x$build_alias" != "x$host_alias"; then
+    cross_compiling=yes
+  fi
+fi
+
+ac_tool_prefix=
+test -n "$host_alias" && ac_tool_prefix=$host_alias-
+
+test "$silent" = yes && exec 6>/dev/null
+
+
+ac_pwd=`pwd` && test -n "$ac_pwd" &&
+ac_ls_di=`ls -di .` &&
+ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` ||
+  { echo "$as_me: error: Working directory cannot be determined" >&2
+   { (exit 1); exit 1; }; }
+test "X$ac_ls_di" = "X$ac_pwd_ls_di" ||
+  { echo "$as_me: error: pwd does not report name of working directory" >&2
+   { (exit 1); exit 1; }; }
+
+
+# Find the source files, if location was not specified.
+if test -z "$srcdir"; then
+  ac_srcdir_defaulted=yes
+  # Try the directory containing this script, then the parent directory.
+  ac_confdir=`$as_dirname -- "$0" ||
+$as_expr X"$0" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+        X"$0" : 'X\(//\)[^/]' \| \
+        X"$0" : 'X\(//\)$' \| \
+        X"$0" : 'X\(/\)' \| . 2>/dev/null ||
+echo X"$0" |
+    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+           s//\1/
+           q
+         }
+         /^X\(\/\/\)[^/].*/{
+           s//\1/
+           q
+         }
+         /^X\(\/\/\)$/{
+           s//\1/
+           q
+         }
+         /^X\(\/\).*/{
+           s//\1/
+           q
+         }
+         s/.*/./; q'`
+  srcdir=$ac_confdir
+  if test ! -r "$srcdir/$ac_unique_file"; then
+    srcdir=..
+  fi
+else
+  ac_srcdir_defaulted=no
+fi
+if test ! -r "$srcdir/$ac_unique_file"; then
+  test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .."
+  { echo "$as_me: error: cannot find sources ($ac_unique_file) in $srcdir" >&2
+   { (exit 1); exit 1; }; }
+fi
+ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work"
+ac_abs_confdir=`(
+       cd "$srcdir" && test -r "./$ac_unique_file" || { echo "$as_me: error: $ac_msg" >&2
+   { (exit 1); exit 1; }; }
+       pwd)`
+# When building in place, set srcdir=.
+if test "$ac_abs_confdir" = "$ac_pwd"; then
+  srcdir=.
+fi
+# Remove unnecessary trailing slashes from srcdir.
+# Double slashes in file names in object file debugging info
+# mess up M-x gdb in Emacs.
+case $srcdir in
+*/) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;;
+esac
+for ac_var in $ac_precious_vars; do
+  eval ac_env_${ac_var}_set=\${${ac_var}+set}
+  eval ac_env_${ac_var}_value=\$${ac_var}
+  eval ac_cv_env_${ac_var}_set=\${${ac_var}+set}
+  eval ac_cv_env_${ac_var}_value=\$${ac_var}
+done
+
+#
+# Report the --help message.
+#
+if test "$ac_init_help" = "long"; then
+  # Omit some internal or obsolete options to make the list less imposing.
+  # This message is too long to be a string in the A/UX 3.1 sh.
+  cat <<_ACEOF
+\`configure' configures this package to adapt to many kinds of systems.
+
+Usage: $0 [OPTION]... [VAR=VALUE]...
+
+To assign environment variables (e.g., CC, CFLAGS...), specify them as
+VAR=VALUE.  See below for descriptions of some of the useful variables.
+
+Defaults for the options are specified in brackets.
+
+Configuration:
+  -h, --help              display this help and exit
+      --help=short        display options specific to this package
+      --help=recursive    display the short help of all the included packages
+  -V, --version           display version information and exit
+  -q, --quiet, --silent   do not print \`checking...' messages
+      --cache-file=FILE   cache test results in FILE [disabled]
+  -C, --config-cache      alias for \`--cache-file=config.cache'
+  -n, --no-create         do not create output files
+      --srcdir=DIR        find the sources in DIR [configure dir or \`..']
+
+Installation directories:
+  --prefix=PREFIX         install architecture-independent files in PREFIX
+                         [$ac_default_prefix]
+  --exec-prefix=EPREFIX   install architecture-dependent files in EPREFIX
+                         [PREFIX]
+
+By default, \`make install' will install all the files in
+\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc.  You can specify
+an installation prefix other than \`$ac_default_prefix' using \`--prefix',
+for instance \`--prefix=\$HOME'.
+
+For better control, use the options below.
+
+Fine tuning of the installation directories:
+  --bindir=DIR           user executables [EPREFIX/bin]
+  --sbindir=DIR          system admin executables [EPREFIX/sbin]
+  --libexecdir=DIR       program executables [EPREFIX/libexec]
+  --sysconfdir=DIR       read-only single-machine data [PREFIX/etc]
+  --sharedstatedir=DIR   modifiable architecture-independent data [PREFIX/com]
+  --localstatedir=DIR    modifiable single-machine data [PREFIX/var]
+  --libdir=DIR           object code libraries [EPREFIX/lib]
+  --includedir=DIR       C header files [PREFIX/include]
+  --oldincludedir=DIR    C header files for non-gcc [/usr/include]
+  --datarootdir=DIR      read-only arch.-independent data root [PREFIX/share]
+  --datadir=DIR          read-only architecture-independent data [DATAROOTDIR]
+  --infodir=DIR          info documentation [DATAROOTDIR/info]
+  --localedir=DIR        locale-dependent data [DATAROOTDIR/locale]
+  --mandir=DIR           man documentation [DATAROOTDIR/man]
+  --docdir=DIR           documentation root @<:@DATAROOTDIR/doc/PACKAGE@:>@
+  --htmldir=DIR          html documentation [DOCDIR]
+  --dvidir=DIR           dvi documentation [DOCDIR]
+  --pdfdir=DIR           pdf documentation [DOCDIR]
+  --psdir=DIR            ps documentation [DOCDIR]
+_ACEOF
+
+  cat <<\_ACEOF
+
+System types:
+  --build=BUILD     configure for building on BUILD [guessed]
+  --host=HOST       cross-compile to build programs to run on HOST [BUILD]
+_ACEOF
+fi
+
+if test -n "$ac_init_help"; then
+
+  cat <<\_ACEOF
+
+Optional Features:
+  --disable-FEATURE       do not include FEATURE (same as --enable-FEATURE=no)
+  --enable-FEATURE[=ARG]  include FEATURE [ARG=yes]
+  --enable-poll           Force poll to be used regardless of whether or not
+                          it is a system call
+  --enable-debug          Turn on debugging mode
+  --disable-asserts       Disable assertion checking
+  --enable-profile        Enable profiling support (add -pg to CFLAGS and LDFLAGS)
+  --enable-pedantic       Enable pedantic warnings (add -pedantic to CFLAGS)
+  --enable-warnings       Enable warnings (add -Wall to CFLAGS)
+  --disable-inlines       Disable inlining for a few critical functions
+  --disable-devpoll       Disable the /dev/poll-based engine
+  --disable-kqueue        Disable the kqueue-based engine
+  --disable-epoll         Disable the epoll-based engine
+  --enable-compat          Enables OGN-compat mode.
+  --enable-unstable          Enables unstable features.
+  --enable-gnutls          Enables GnuTLS ssl backend.
+  --enable-openssl          Enables OpenSSL ssl backend.
+
+Optional Packages:
+  --with-PACKAGE[=ARG]    use PACKAGE [ARG=yes]
+  --without-PACKAGE       do not use PACKAGE (same as --with-PACKAGE=no)
+  --with-leak-detect          Turn on the leak detector(requires patched boehm)
+  --without-ipv6          disable IPv6 support (default is autodetect)
+  --with-symlink=name     Name to give the symlink; if name is "no," no
+                          symlink will be created.
+  --with-mode=mode        Permissions (in octal) to give the binary
+  --with-owner=owner      Specify owner of the installed binary
+  --with-group=group      Specify group owner of the installed binary
+  --with-domain=domain    Domain name to use in local statistics gathering
+  --with-chroot=dir       Specify that the server will be operated under
+                          a different root directory given by dir.  See
+                          doc/readme.chroot for more information.
+  --with-dpath=dir        Directory for all server data files
+  --with-cpath=file       Set server configuration file
+  --with-lpath=file       Set the debugging log file
+  --with-maxcon=maxcon    Maximum number of connections server will accept
+
+Some influential environment variables:
+  CC          C compiler command
+  CFLAGS      C compiler flags
+  LDFLAGS     linker flags, e.g. -L<lib dir> if you have libraries in a
+              nonstandard directory <lib dir>
+  LIBS        libraries to pass to the linker, e.g. -l<library>
+  CPPFLAGS    C/C++/Objective C preprocessor flags, e.g. -I<include dir> if
+              you have headers in a nonstandard directory <include dir>
+  CPP         C preprocessor
+  YACC        The `Yet Another C Compiler' implementation to use. Defaults to
+              the first program found out of: `bison -y', `byacc', `yacc'.
+  YFLAGS      The list of arguments that will be passed by default to $YACC.
+              This script will default YFLAGS to the empty string to avoid a
+              default value of `-d' given by some make applications.
+
+Use these variables to override the choices made by `configure' or to help
+it to find libraries and programs with nonstandard names/locations.
+
+_ACEOF
+ac_status=$?
+fi
+
+if test "$ac_init_help" = "recursive"; then
+  # If there are subdirs, report their specific --help.
+  for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue
+    test -d "$ac_dir" || continue
+    ac_builddir=.
+
+case "$ac_dir" in
+.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
+*)
+  ac_dir_suffix=/`echo "$ac_dir" | sed 's,^\.[\\/],,'`
+  # A ".." for each directory in $ac_dir_suffix.
+  ac_top_builddir_sub=`echo "$ac_dir_suffix" | sed 's,/[^\\/]*,/..,g;s,/,,'`
+  case $ac_top_builddir_sub in
+  "") ac_top_builddir_sub=. ac_top_build_prefix= ;;
+  *)  ac_top_build_prefix=$ac_top_builddir_sub/ ;;
+  esac ;;
+esac
+ac_abs_top_builddir=$ac_pwd
+ac_abs_builddir=$ac_pwd$ac_dir_suffix
+# for backward compatibility:
+ac_top_builddir=$ac_top_build_prefix
+
+case $srcdir in
+  .)  # We are building in place.
+    ac_srcdir=.
+    ac_top_srcdir=$ac_top_builddir_sub
+    ac_abs_top_srcdir=$ac_pwd ;;
+  [\\/]* | ?:[\\/]* )  # Absolute name.
+    ac_srcdir=$srcdir$ac_dir_suffix;
+    ac_top_srcdir=$srcdir
+    ac_abs_top_srcdir=$srcdir ;;
+  *) # Relative name.
+    ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix
+    ac_top_srcdir=$ac_top_build_prefix$srcdir
+    ac_abs_top_srcdir=$ac_pwd/$srcdir ;;
+esac
+ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix
+
+    cd "$ac_dir" || { ac_status=$?; continue; }
+    # Check for guested configure.
+    if test -f "$ac_srcdir/configure.gnu"; then
+      echo &&
+      $SHELL "$ac_srcdir/configure.gnu" --help=recursive
+    elif test -f "$ac_srcdir/configure"; then
+      echo &&
+      $SHELL "$ac_srcdir/configure" --help=recursive
+    else
+      echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2
+    fi || ac_status=$?
+    cd "$ac_pwd" || { ac_status=$?; break; }
+  done
+fi
+
+test -n "$ac_init_help" && exit $ac_status
+if $ac_init_version; then
+  cat <<\_ACEOF
+configure
+generated by GNU Autoconf 2.61
+
+Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001,
+2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
+This configure script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it.
+_ACEOF
+  exit
+fi
+cat >config.log <<_ACEOF
+This file contains any messages produced by compilers while
+running configure, to aid debugging if configure makes a mistake.
+
+It was created by $as_me, which was
+generated by GNU Autoconf 2.61.  Invocation command line was
+
+  $ $0 $@
+
+_ACEOF
+exec 5>>config.log
+{
+cat <<_ASUNAME
+@%:@@%:@ --------- @%:@@%:@
+@%:@@%:@ Platform. @%:@@%:@
+@%:@@%:@ --------- @%:@@%:@
+
+hostname = `(hostname || uname -n) 2>/dev/null | sed 1q`
+uname -m = `(uname -m) 2>/dev/null || echo unknown`
+uname -r = `(uname -r) 2>/dev/null || echo unknown`
+uname -s = `(uname -s) 2>/dev/null || echo unknown`
+uname -v = `(uname -v) 2>/dev/null || echo unknown`
+
+/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown`
+/bin/uname -X     = `(/bin/uname -X) 2>/dev/null     || echo unknown`
+
+/bin/arch              = `(/bin/arch) 2>/dev/null              || echo unknown`
+/usr/bin/arch -k       = `(/usr/bin/arch -k) 2>/dev/null       || echo unknown`
+/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown`
+/usr/bin/hostinfo      = `(/usr/bin/hostinfo) 2>/dev/null      || echo unknown`
+/bin/machine           = `(/bin/machine) 2>/dev/null           || echo unknown`
+/usr/bin/oslevel       = `(/usr/bin/oslevel) 2>/dev/null       || echo unknown`
+/bin/universe          = `(/bin/universe) 2>/dev/null          || echo unknown`
+
+_ASUNAME
+
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  echo "PATH: $as_dir"
+done
+IFS=$as_save_IFS
+
+} >&5
+
+cat >&5 <<_ACEOF
+
+
+@%:@@%:@ ----------- @%:@@%:@
+@%:@@%:@ Core tests. @%:@@%:@
+@%:@@%:@ ----------- @%:@@%:@
+
+_ACEOF
+
+
+# Keep a trace of the command line.
+# Strip out --no-create and --no-recursion so they do not pile up.
+# Strip out --silent because we don't want to record it for future runs.
+# Also quote any args containing shell meta-characters.
+# Make two passes to allow for proper duplicate-argument suppression.
+ac_configure_args=
+ac_configure_args0=
+ac_configure_args1=
+ac_must_keep_next=false
+for ac_pass in 1 2
+do
+  for ac_arg
+  do
+    case $ac_arg in
+    -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;;
+    -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+    | -silent | --silent | --silen | --sile | --sil)
+      continue ;;
+    *\'*)
+      ac_arg=`echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;;
+    esac
+    case $ac_pass in
+    1) ac_configure_args0="$ac_configure_args0 '$ac_arg'" ;;
+    2)
+      ac_configure_args1="$ac_configure_args1 '$ac_arg'"
+      if test $ac_must_keep_next = true; then
+       ac_must_keep_next=false # Got value, back to normal.
+      else
+       case $ac_arg in
+         *=* | --config-cache | -C | -disable-* | --disable-* \
+         | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \
+         | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \
+         | -with-* | --with-* | -without-* | --without-* | --x)
+           case "$ac_configure_args0 " in
+             "$ac_configure_args1"*" '$ac_arg' "* ) continue ;;
+           esac
+           ;;
+         -* ) ac_must_keep_next=true ;;
+       esac
+      fi
+      ac_configure_args="$ac_configure_args '$ac_arg'"
+      ;;
+    esac
+  done
+done
+$as_unset ac_configure_args0 || test "${ac_configure_args0+set}" != set || { ac_configure_args0=; export ac_configure_args0; }
+$as_unset ac_configure_args1 || test "${ac_configure_args1+set}" != set || { ac_configure_args1=; export ac_configure_args1; }
+
+# When interrupted or exit'd, cleanup temporary files, and complete
+# config.log.  We remove comments because anyway the quotes in there
+# would cause problems or look ugly.
+# WARNING: Use '\'' to represent an apostrophe within the trap.
+# WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug.
+trap 'exit_status=$?
+  # Save into config.log some information that might help in debugging.
+  {
+    echo
+
+    cat <<\_ASBOX
+@%:@@%:@ ---------------- @%:@@%:@
+@%:@@%:@ Cache variables. @%:@@%:@
+@%:@@%:@ ---------------- @%:@@%:@
+_ASBOX
+    echo
+    # The following way of writing the cache mishandles newlines in values,
+(
+  for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do
+    eval ac_val=\$$ac_var
+    case $ac_val in #(
+    *${as_nl}*)
+      case $ac_var in #(
+      *_cv_*) { echo "$as_me:$LINENO: WARNING: Cache variable $ac_var contains a newline." >&5
+echo "$as_me: WARNING: Cache variable $ac_var contains a newline." >&2;} ;;
+      esac
+      case $ac_var in #(
+      _ | IFS | as_nl) ;; #(
+      *) $as_unset $ac_var ;;
+      esac ;;
+    esac
+  done
+  (set) 2>&1 |
+    case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #(
+    *${as_nl}ac_space=\ *)
+      sed -n \
+       "s/'\''/'\''\\\\'\'''\''/g;
+         s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p"
+      ;; #(
+    *)
+      sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p"
+      ;;
+    esac |
+    sort
+)
+    echo
+
+    cat <<\_ASBOX
+@%:@@%:@ ----------------- @%:@@%:@
+@%:@@%:@ Output variables. @%:@@%:@
+@%:@@%:@ ----------------- @%:@@%:@
+_ASBOX
+    echo
+    for ac_var in $ac_subst_vars
+    do
+      eval ac_val=\$$ac_var
+      case $ac_val in
+      *\'\''*) ac_val=`echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
+      esac
+      echo "$ac_var='\''$ac_val'\''"
+    done | sort
+    echo
+
+    if test -n "$ac_subst_files"; then
+      cat <<\_ASBOX
+@%:@@%:@ ------------------- @%:@@%:@
+@%:@@%:@ File substitutions. @%:@@%:@
+@%:@@%:@ ------------------- @%:@@%:@
+_ASBOX
+      echo
+      for ac_var in $ac_subst_files
+      do
+       eval ac_val=\$$ac_var
+       case $ac_val in
+       *\'\''*) ac_val=`echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
+       esac
+       echo "$ac_var='\''$ac_val'\''"
+      done | sort
+      echo
+    fi
+
+    if test -s confdefs.h; then
+      cat <<\_ASBOX
+@%:@@%:@ ----------- @%:@@%:@
+@%:@@%:@ confdefs.h. @%:@@%:@
+@%:@@%:@ ----------- @%:@@%:@
+_ASBOX
+      echo
+      cat confdefs.h
+      echo
+    fi
+    test "$ac_signal" != 0 &&
+      echo "$as_me: caught signal $ac_signal"
+    echo "$as_me: exit $exit_status"
+  } >&5
+  rm -f core *.core core.conftest.* &&
+    rm -f -r conftest* confdefs* conf$$* $ac_clean_files &&
+    exit $exit_status
+' 0
+for ac_signal in 1 2 13 15; do
+  trap 'ac_signal='$ac_signal'; { (exit 1); exit 1; }' $ac_signal
+done
+ac_signal=0
+
+# confdefs.h avoids OS command line length limits that DEFS can exceed.
+rm -f -r conftest* confdefs.h
+
+# Predefined preprocessor variables.
+
+cat >>confdefs.h <<_ACEOF
+@%:@define PACKAGE_NAME "$PACKAGE_NAME"
+_ACEOF
+
+
+cat >>confdefs.h <<_ACEOF
+@%:@define PACKAGE_TARNAME "$PACKAGE_TARNAME"
+_ACEOF
+
+
+cat >>confdefs.h <<_ACEOF
+@%:@define PACKAGE_VERSION "$PACKAGE_VERSION"
+_ACEOF
+
+
+cat >>confdefs.h <<_ACEOF
+@%:@define PACKAGE_STRING "$PACKAGE_STRING"
+_ACEOF
+
+
+cat >>confdefs.h <<_ACEOF
+@%:@define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT"
+_ACEOF
+
+
+# Let the site file select an alternate cache file if it wants to.
+# Prefer explicitly selected file to automatically selected ones.
+if test -n "$CONFIG_SITE"; then
+  set x "$CONFIG_SITE"
+elif test "x$prefix" != xNONE; then
+  set x "$prefix/share/config.site" "$prefix/etc/config.site"
+else
+  set x "$ac_default_prefix/share/config.site" \
+       "$ac_default_prefix/etc/config.site"
+fi
+shift
+for ac_site_file
+do
+  if test -r "$ac_site_file"; then
+    { echo "$as_me:$LINENO: loading site script $ac_site_file" >&5
+echo "$as_me: loading site script $ac_site_file" >&6;}
+    sed 's/^/| /' "$ac_site_file" >&5
+    . "$ac_site_file"
+  fi
+done
+
+if test -r "$cache_file"; then
+  # Some versions of bash will fail to source /dev/null (special
+  # files actually), so we avoid doing that.
+  if test -f "$cache_file"; then
+    { echo "$as_me:$LINENO: loading cache $cache_file" >&5
+echo "$as_me: loading cache $cache_file" >&6;}
+    case $cache_file in
+      [\\/]* | ?:[\\/]* ) . "$cache_file";;
+      *)                      . "./$cache_file";;
+    esac
+  fi
+else
+  { echo "$as_me:$LINENO: creating cache $cache_file" >&5
+echo "$as_me: creating cache $cache_file" >&6;}
+  >$cache_file
+fi
+
+# Check that the precious variables saved in the cache have kept the same
+# value.
+ac_cache_corrupted=false
+for ac_var in $ac_precious_vars; do
+  eval ac_old_set=\$ac_cv_env_${ac_var}_set
+  eval ac_new_set=\$ac_env_${ac_var}_set
+  eval ac_old_val=\$ac_cv_env_${ac_var}_value
+  eval ac_new_val=\$ac_env_${ac_var}_value
+  case $ac_old_set,$ac_new_set in
+    set,)
+      { echo "$as_me:$LINENO: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5
+echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;}
+      ac_cache_corrupted=: ;;
+    ,set)
+      { echo "$as_me:$LINENO: error: \`$ac_var' was not set in the previous run" >&5
+echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;}
+      ac_cache_corrupted=: ;;
+    ,);;
+    *)
+      if test "x$ac_old_val" != "x$ac_new_val"; then
+       { echo "$as_me:$LINENO: error: \`$ac_var' has changed since the previous run:" >&5
+echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;}
+       { echo "$as_me:$LINENO:   former value:  $ac_old_val" >&5
+echo "$as_me:   former value:  $ac_old_val" >&2;}
+       { echo "$as_me:$LINENO:   current value: $ac_new_val" >&5
+echo "$as_me:   current value: $ac_new_val" >&2;}
+       ac_cache_corrupted=:
+      fi;;
+  esac
+  # Pass precious variables to config.status.
+  if test "$ac_new_set" = set; then
+    case $ac_new_val in
+    *\'*) ac_arg=$ac_var=`echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;;
+    *) ac_arg=$ac_var=$ac_new_val ;;
+    esac
+    case " $ac_configure_args " in
+      *" '$ac_arg' "*) ;; # Avoid dups.  Use of quotes ensures accuracy.
+      *) ac_configure_args="$ac_configure_args '$ac_arg'" ;;
+    esac
+  fi
+done
+if $ac_cache_corrupted; then
+  { echo "$as_me:$LINENO: error: changes in the environment can compromise the build" >&5
+echo "$as_me: error: changes in the environment can compromise the build" >&2;}
+  { { echo "$as_me:$LINENO: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&5
+echo "$as_me: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&2;}
+   { (exit 1); exit 1; }; }
+fi
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+
+
+{ echo "$as_me:$LINENO: checking for installation prefix" >&5
+echo $ECHO_N "checking for installation prefix... $ECHO_C" >&6; }
+if test "${unet_cv_prefix+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  unet_cv_prefix=$HOME
+fi
+
+if test x"$prefix" != xNONE; then
+    unet_cv_prefix=$prefix
+fi
+{ echo "$as_me:$LINENO: result: $unet_cv_prefix" >&5
+echo "${ECHO_T}$unet_cv_prefix" >&6; }
+ac_default_prefix=$unet_cv_prefix
+
+ac_config_headers="$ac_config_headers config.h"
+
+
+
+
+ac_aux_dir=
+for ac_dir in "$srcdir" "$srcdir/.." "$srcdir/../.."; do
+  if test -f "$ac_dir/install-sh"; then
+    ac_aux_dir=$ac_dir
+    ac_install_sh="$ac_aux_dir/install-sh -c"
+    break
+  elif test -f "$ac_dir/install.sh"; then
+    ac_aux_dir=$ac_dir
+    ac_install_sh="$ac_aux_dir/install.sh -c"
+    break
+  elif test -f "$ac_dir/shtool"; then
+    ac_aux_dir=$ac_dir
+    ac_install_sh="$ac_aux_dir/shtool install -c"
+    break
+  fi
+done
+if test -z "$ac_aux_dir"; then
+  { { echo "$as_me:$LINENO: error: cannot find install-sh or install.sh in \"$srcdir\" \"$srcdir/..\" \"$srcdir/../..\"" >&5
+echo "$as_me: error: cannot find install-sh or install.sh in \"$srcdir\" \"$srcdir/..\" \"$srcdir/../..\"" >&2;}
+   { (exit 1); exit 1; }; }
+fi
+
+# These three variables are undocumented and unsupported,
+# and are intended to be withdrawn in a future Autoconf release.
+# They can cause serious problems if a builder's source tree is in a directory
+# whose full name contains unusual characters.
+ac_config_guess="$SHELL $ac_aux_dir/config.guess"  # Please don't use this var.
+ac_config_sub="$SHELL $ac_aux_dir/config.sub"  # Please don't use this var.
+ac_configure="$SHELL $ac_aux_dir/configure"  # Please don't use this var.
+
+
+# Make sure we can run config.sub.
+$SHELL "$ac_aux_dir/config.sub" sun4 >/dev/null 2>&1 ||
+  { { echo "$as_me:$LINENO: error: cannot run $SHELL $ac_aux_dir/config.sub" >&5
+echo "$as_me: error: cannot run $SHELL $ac_aux_dir/config.sub" >&2;}
+   { (exit 1); exit 1; }; }
+
+{ echo "$as_me:$LINENO: checking build system type" >&5
+echo $ECHO_N "checking build system type... $ECHO_C" >&6; }
+if test "${ac_cv_build+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_build_alias=$build_alias
+test "x$ac_build_alias" = x &&
+  ac_build_alias=`$SHELL "$ac_aux_dir/config.guess"`
+test "x$ac_build_alias" = x &&
+  { { echo "$as_me:$LINENO: error: cannot guess build type; you must specify one" >&5
+echo "$as_me: error: cannot guess build type; you must specify one" >&2;}
+   { (exit 1); exit 1; }; }
+ac_cv_build=`$SHELL "$ac_aux_dir/config.sub" $ac_build_alias` ||
+  { { echo "$as_me:$LINENO: error: $SHELL $ac_aux_dir/config.sub $ac_build_alias failed" >&5
+echo "$as_me: error: $SHELL $ac_aux_dir/config.sub $ac_build_alias failed" >&2;}
+   { (exit 1); exit 1; }; }
+
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_build" >&5
+echo "${ECHO_T}$ac_cv_build" >&6; }
+case $ac_cv_build in
+*-*-*) ;;
+*) { { echo "$as_me:$LINENO: error: invalid value of canonical build" >&5
+echo "$as_me: error: invalid value of canonical build" >&2;}
+   { (exit 1); exit 1; }; };;
+esac
+build=$ac_cv_build
+ac_save_IFS=$IFS; IFS='-'
+set x $ac_cv_build
+shift
+build_cpu=$1
+build_vendor=$2
+shift; shift
+# Remember, the first character of IFS is used to create $*,
+# except with old shells:
+build_os=$*
+IFS=$ac_save_IFS
+case $build_os in *\ *) build_os=`echo "$build_os" | sed 's/ /-/g'`;; esac
+
+
+{ echo "$as_me:$LINENO: checking host system type" >&5
+echo $ECHO_N "checking host system type... $ECHO_C" >&6; }
+if test "${ac_cv_host+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if test "x$host_alias" = x; then
+  ac_cv_host=$ac_cv_build
+else
+  ac_cv_host=`$SHELL "$ac_aux_dir/config.sub" $host_alias` ||
+    { { echo "$as_me:$LINENO: error: $SHELL $ac_aux_dir/config.sub $host_alias failed" >&5
+echo "$as_me: error: $SHELL $ac_aux_dir/config.sub $host_alias failed" >&2;}
+   { (exit 1); exit 1; }; }
+fi
+
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_host" >&5
+echo "${ECHO_T}$ac_cv_host" >&6; }
+case $ac_cv_host in
+*-*-*) ;;
+*) { { echo "$as_me:$LINENO: error: invalid value of canonical host" >&5
+echo "$as_me: error: invalid value of canonical host" >&2;}
+   { (exit 1); exit 1; }; };;
+esac
+host=$ac_cv_host
+ac_save_IFS=$IFS; IFS='-'
+set x $ac_cv_host
+shift
+host_cpu=$1
+host_vendor=$2
+shift; shift
+# Remember, the first character of IFS is used to create $*,
+# except with old shells:
+host_os=$*
+IFS=$ac_save_IFS
+case $host_os in *\ *) host_os=`echo "$host_os" | sed 's/ /-/g'`;; esac
+
+
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+if test -n "$ac_tool_prefix"; then
+  # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args.
+set dummy ${ac_tool_prefix}gcc; ac_word=$2
+{ echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
+if test "${ac_cv_prog_CC+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_CC="${ac_tool_prefix}gcc"
+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+  { echo "$as_me:$LINENO: result: $CC" >&5
+echo "${ECHO_T}$CC" >&6; }
+else
+  { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_CC"; then
+  ac_ct_CC=$CC
+  # Extract the first word of "gcc", so it can be a program name with args.
+set dummy gcc; ac_word=$2
+{ echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
+if test "${ac_cv_prog_ac_ct_CC+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if test -n "$ac_ct_CC"; then
+  ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_ac_ct_CC="gcc"
+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+  { echo "$as_me:$LINENO: result: $ac_ct_CC" >&5
+echo "${ECHO_T}$ac_ct_CC" >&6; }
+else
+  { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+fi
+
+  if test "x$ac_ct_CC" = x; then
+    CC=""
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ echo "$as_me:$LINENO: WARNING: In the future, Autoconf will not detect cross-tools
+whose name does not start with the host triplet.  If you think this
+configuration is useful to you, please write to autoconf@gnu.org." >&5
+echo "$as_me: WARNING: In the future, Autoconf will not detect cross-tools
+whose name does not start with the host triplet.  If you think this
+configuration is useful to you, please write to autoconf@gnu.org." >&2;}
+ac_tool_warned=yes ;;
+esac
+    CC=$ac_ct_CC
+  fi
+else
+  CC="$ac_cv_prog_CC"
+fi
+
+if test -z "$CC"; then
+          if test -n "$ac_tool_prefix"; then
+    # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args.
+set dummy ${ac_tool_prefix}cc; ac_word=$2
+{ echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
+if test "${ac_cv_prog_CC+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_CC="${ac_tool_prefix}cc"
+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+  { echo "$as_me:$LINENO: result: $CC" >&5
+echo "${ECHO_T}$CC" >&6; }
+else
+  { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+fi
+
+
+  fi
+fi
+if test -z "$CC"; then
+  # Extract the first word of "cc", so it can be a program name with args.
+set dummy cc; ac_word=$2
+{ echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
+if test "${ac_cv_prog_CC+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+  ac_prog_rejected=no
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then
+       ac_prog_rejected=yes
+       continue
+     fi
+    ac_cv_prog_CC="cc"
+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+IFS=$as_save_IFS
+
+if test $ac_prog_rejected = yes; then
+  # We found a bogon in the path, so make sure we never use it.
+  set dummy $ac_cv_prog_CC
+  shift
+  if test $@%:@ != 0; then
+    # We chose a different compiler from the bogus one.
+    # However, it has the same basename, so the bogon will be chosen
+    # first if we set CC to just the basename; use the full file name.
+    shift
+    ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@"
+  fi
+fi
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+  { echo "$as_me:$LINENO: result: $CC" >&5
+echo "${ECHO_T}$CC" >&6; }
+else
+  { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+fi
+
+
+fi
+if test -z "$CC"; then
+  if test -n "$ac_tool_prefix"; then
+  for ac_prog in cl.exe
+  do
+    # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
+set dummy $ac_tool_prefix$ac_prog; ac_word=$2
+{ echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
+if test "${ac_cv_prog_CC+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_CC="$ac_tool_prefix$ac_prog"
+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+  { echo "$as_me:$LINENO: result: $CC" >&5
+echo "${ECHO_T}$CC" >&6; }
+else
+  { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+fi
+
+
+    test -n "$CC" && break
+  done
+fi
+if test -z "$CC"; then
+  ac_ct_CC=$CC
+  for ac_prog in cl.exe
+do
+  # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
+if test "${ac_cv_prog_ac_ct_CC+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if test -n "$ac_ct_CC"; then
+  ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_ac_ct_CC="$ac_prog"
+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+  { echo "$as_me:$LINENO: result: $ac_ct_CC" >&5
+echo "${ECHO_T}$ac_ct_CC" >&6; }
+else
+  { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+fi
+
+
+  test -n "$ac_ct_CC" && break
+done
+
+  if test "x$ac_ct_CC" = x; then
+    CC=""
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ echo "$as_me:$LINENO: WARNING: In the future, Autoconf will not detect cross-tools
+whose name does not start with the host triplet.  If you think this
+configuration is useful to you, please write to autoconf@gnu.org." >&5
+echo "$as_me: WARNING: In the future, Autoconf will not detect cross-tools
+whose name does not start with the host triplet.  If you think this
+configuration is useful to you, please write to autoconf@gnu.org." >&2;}
+ac_tool_warned=yes ;;
+esac
+    CC=$ac_ct_CC
+  fi
+fi
+
+fi
+
+
+test -z "$CC" && { { echo "$as_me:$LINENO: error: no acceptable C compiler found in \$PATH
+See \`config.log' for more details." >&5
+echo "$as_me: error: no acceptable C compiler found in \$PATH
+See \`config.log' for more details." >&2;}
+   { (exit 1); exit 1; }; }
+
+# Provide some information about the compiler.
+echo "$as_me:$LINENO: checking for C compiler version" >&5
+ac_compiler=`set X $ac_compile; echo $2`
+{ (ac_try="$ac_compiler --version >&5"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compiler --version >&5") 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }
+{ (ac_try="$ac_compiler -v >&5"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compiler -v >&5") 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }
+{ (ac_try="$ac_compiler -V >&5"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compiler -V >&5") 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }
+
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files a.out a.exe b.out"
+# Try to create an executable without -o first, disregard a.out.
+# It will help us diagnose broken compilers, and finding out an intuition
+# of exeext.
+{ echo "$as_me:$LINENO: checking for C compiler default output file name" >&5
+echo $ECHO_N "checking for C compiler default output file name... $ECHO_C" >&6; }
+ac_link_default=`echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'`
+#
+# List of possible output files, starting from the most likely.
+# The algorithm is not robust to junk in `.', hence go to wildcards (a.*)
+# only as a last resort.  b.out is created by i960 compilers.
+ac_files='a_out.exe a.exe conftest.exe a.out conftest a.* conftest.* b.out'
+#
+# The IRIX 6 linker writes into existing files which may not be
+# executable, retaining their permissions.  Remove them first so a
+# subsequent execution test works.
+ac_rmfiles=
+for ac_file in $ac_files
+do
+  case $ac_file in
+    *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.o | *.obj ) ;;
+    * ) ac_rmfiles="$ac_rmfiles $ac_file";;
+  esac
+done
+rm -f $ac_rmfiles
+
+if { (ac_try="$ac_link_default"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link_default") 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; then
+  # Autoconf-2.13 could set the ac_cv_exeext variable to `no'.
+# So ignore a value of `no', otherwise this would lead to `EXEEXT = no'
+# in a Makefile.  We should not override ac_cv_exeext if it was cached,
+# so that the user can short-circuit this test for compilers unknown to
+# Autoconf.
+for ac_file in $ac_files ''
+do
+  test -f "$ac_file" || continue
+  case $ac_file in
+    *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.o | *.obj )
+       ;;
+    [ab].out )
+       # We found the default executable, but exeext='' is most
+       # certainly right.
+       break;;
+    *.* )
+        if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no;
+       then :; else
+          ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
+       fi
+       # We set ac_cv_exeext here because the later test for it is not
+       # safe: cross compilers may not add the suffix if given an `-o'
+       # argument, so we may need to know it at that point already.
+       # Even if this section looks crufty: it has the advantage of
+       # actually working.
+       break;;
+    * )
+       break;;
+  esac
+done
+test "$ac_cv_exeext" = no && ac_cv_exeext=
+
+else
+  ac_file=''
+fi
+
+{ echo "$as_me:$LINENO: result: $ac_file" >&5
+echo "${ECHO_T}$ac_file" >&6; }
+if test -z "$ac_file"; then
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+{ { echo "$as_me:$LINENO: error: C compiler cannot create executables
+See \`config.log' for more details." >&5
+echo "$as_me: error: C compiler cannot create executables
+See \`config.log' for more details." >&2;}
+   { (exit 77); exit 77; }; }
+fi
+
+ac_exeext=$ac_cv_exeext
+
+# Check that the compiler produces executables we can run.  If not, either
+# the compiler is broken, or we cross compile.
+{ echo "$as_me:$LINENO: checking whether the C compiler works" >&5
+echo $ECHO_N "checking whether the C compiler works... $ECHO_C" >&6; }
+# FIXME: These cross compiler hacks should be removed for Autoconf 3.0
+# If not cross compiling, check that we can run a simple program.
+if test "$cross_compiling" != yes; then
+  if { ac_try='./$ac_file'
+  { (case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_try") 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+    cross_compiling=no
+  else
+    if test "$cross_compiling" = maybe; then
+       cross_compiling=yes
+    else
+       { { echo "$as_me:$LINENO: error: cannot run C compiled programs.
+If you meant to cross compile, use \`--host'.
+See \`config.log' for more details." >&5
+echo "$as_me: error: cannot run C compiled programs.
+If you meant to cross compile, use \`--host'.
+See \`config.log' for more details." >&2;}
+   { (exit 1); exit 1; }; }
+    fi
+  fi
+fi
+{ echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6; }
+
+rm -f a.out a.exe conftest$ac_cv_exeext b.out
+ac_clean_files=$ac_clean_files_save
+# Check that the compiler produces executables we can run.  If not, either
+# the compiler is broken, or we cross compile.
+{ echo "$as_me:$LINENO: checking whether we are cross compiling" >&5
+echo $ECHO_N "checking whether we are cross compiling... $ECHO_C" >&6; }
+{ echo "$as_me:$LINENO: result: $cross_compiling" >&5
+echo "${ECHO_T}$cross_compiling" >&6; }
+
+{ echo "$as_me:$LINENO: checking for suffix of executables" >&5
+echo $ECHO_N "checking for suffix of executables... $ECHO_C" >&6; }
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; then
+  # If both `conftest.exe' and `conftest' are `present' (well, observable)
+# catch `conftest.exe'.  For instance with Cygwin, `ls conftest' will
+# work properly (i.e., refer to `conftest.exe'), while it won't with
+# `rm'.
+for ac_file in conftest.exe conftest conftest.*; do
+  test -f "$ac_file" || continue
+  case $ac_file in
+    *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.o | *.obj ) ;;
+    *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
+         break;;
+    * ) break;;
+  esac
+done
+else
+  { { echo "$as_me:$LINENO: error: cannot compute suffix of executables: cannot compile and link
+See \`config.log' for more details." >&5
+echo "$as_me: error: cannot compute suffix of executables: cannot compile and link
+See \`config.log' for more details." >&2;}
+   { (exit 1); exit 1; }; }
+fi
+
+rm -f conftest$ac_cv_exeext
+{ echo "$as_me:$LINENO: result: $ac_cv_exeext" >&5
+echo "${ECHO_T}$ac_cv_exeext" >&6; }
+
+rm -f conftest.$ac_ext
+EXEEXT=$ac_cv_exeext
+ac_exeext=$EXEEXT
+{ echo "$as_me:$LINENO: checking for suffix of object files" >&5
+echo $ECHO_N "checking for suffix of object files... $ECHO_C" >&6; }
+if test "${ac_cv_objext+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.o conftest.obj
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; then
+  for ac_file in conftest.o conftest.obj conftest.*; do
+  test -f "$ac_file" || continue;
+  case $ac_file in
+    *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf ) ;;
+    *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'`
+       break;;
+  esac
+done
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+{ { echo "$as_me:$LINENO: error: cannot compute suffix of object files: cannot compile
+See \`config.log' for more details." >&5
+echo "$as_me: error: cannot compute suffix of object files: cannot compile
+See \`config.log' for more details." >&2;}
+   { (exit 1); exit 1; }; }
+fi
+
+rm -f conftest.$ac_cv_objext conftest.$ac_ext
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_objext" >&5
+echo "${ECHO_T}$ac_cv_objext" >&6; }
+OBJEXT=$ac_cv_objext
+ac_objext=$OBJEXT
+{ echo "$as_me:$LINENO: checking whether we are using the GNU C compiler" >&5
+echo $ECHO_N "checking whether we are using the GNU C compiler... $ECHO_C" >&6; }
+if test "${ac_cv_c_compiler_gnu+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+int
+main ()
+{
+#ifndef __GNUC__
+       choke me
+#endif
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_compiler_gnu=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_compiler_gnu=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ac_cv_c_compiler_gnu=$ac_compiler_gnu
+
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_c_compiler_gnu" >&5
+echo "${ECHO_T}$ac_cv_c_compiler_gnu" >&6; }
+GCC=`test $ac_compiler_gnu = yes && echo yes`
+ac_test_CFLAGS=${CFLAGS+set}
+ac_save_CFLAGS=$CFLAGS
+{ echo "$as_me:$LINENO: checking whether $CC accepts -g" >&5
+echo $ECHO_N "checking whether $CC accepts -g... $ECHO_C" >&6; }
+if test "${ac_cv_prog_cc_g+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_save_c_werror_flag=$ac_c_werror_flag
+   ac_c_werror_flag=yes
+   ac_cv_prog_cc_g=no
+   CFLAGS="-g"
+   cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_cv_prog_cc_g=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       CFLAGS=""
+      cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  :
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_c_werror_flag=$ac_save_c_werror_flag
+        CFLAGS="-g"
+        cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_cv_prog_cc_g=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+   ac_c_werror_flag=$ac_save_c_werror_flag
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_prog_cc_g" >&5
+echo "${ECHO_T}$ac_cv_prog_cc_g" >&6; }
+if test "$ac_test_CFLAGS" = set; then
+  CFLAGS=$ac_save_CFLAGS
+elif test $ac_cv_prog_cc_g = yes; then
+  if test "$GCC" = yes; then
+    CFLAGS="-g -O2"
+  else
+    CFLAGS="-g"
+  fi
+else
+  if test "$GCC" = yes; then
+    CFLAGS="-O2"
+  else
+    CFLAGS=
+  fi
+fi
+{ echo "$as_me:$LINENO: checking for $CC option to accept ISO C89" >&5
+echo $ECHO_N "checking for $CC option to accept ISO C89... $ECHO_C" >&6; }
+if test "${ac_cv_prog_cc_c89+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_cv_prog_cc_c89=no
+ac_save_CC=$CC
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <stdarg.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+/* Most of the following tests are stolen from RCS 5.7's src/conf.sh.  */
+struct buf { int x; };
+FILE * (*rcsopen) (struct buf *, struct stat *, int);
+static char *e (p, i)
+     char **p;
+     int i;
+{
+  return p[i];
+}
+static char *f (char * (*g) (char **, int), char **p, ...)
+{
+  char *s;
+  va_list v;
+  va_start (v,p);
+  s = g (p, va_arg (v,int));
+  va_end (v);
+  return s;
+}
+
+/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default.  It has
+   function prototypes and stuff, but not '\xHH' hex character constants.
+   These don't provoke an error unfortunately, instead are silently treated
+   as 'x'.  The following induces an error, until -std is added to get
+   proper ANSI mode.  Curiously '\x00'!='x' always comes out true, for an
+   array size at least.  It's necessary to write '\x00'==0 to get something
+   that's true only with -std.  */
+int osf4_cc_array ['\x00' == 0 ? 1 : -1];
+
+/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters
+   inside strings and character constants.  */
+#define FOO(x) 'x'
+int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1];
+
+int test (int i, double x);
+struct s1 {int (*f) (int a);};
+struct s2 {int (*f) (double a);};
+int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int);
+int argc;
+char **argv;
+int
+main ()
+{
+return f (e, argv, 0) != argv[0]  ||  f (e, argv, 1) != argv[1];
+  ;
+  return 0;
+}
+_ACEOF
+for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \
+       -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__"
+do
+  CC="$ac_save_CC $ac_arg"
+  rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_cv_prog_cc_c89=$ac_arg
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       
+fi
+
+rm -f core conftest.err conftest.$ac_objext 
+  test "x$ac_cv_prog_cc_c89" != "xno" && break
+done
+rm -f conftest.$ac_ext
+CC=$ac_save_CC
+
+fi
+# AC_CACHE_VAL
+case "x$ac_cv_prog_cc_c89" in
+  x)
+    { echo "$as_me:$LINENO: result: none needed" >&5
+echo "${ECHO_T}none needed" >&6; } ;;
+  xno)
+    { echo "$as_me:$LINENO: result: unsupported" >&5
+echo "${ECHO_T}unsupported" >&6; } ;;
+  *)
+    CC="$CC $ac_cv_prog_cc_c89"
+    { echo "$as_me:$LINENO: result: $ac_cv_prog_cc_c89" >&5
+echo "${ECHO_T}$ac_cv_prog_cc_c89" >&6; } ;;
+esac
+
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+if test -n "$ac_tool_prefix"; then
+  # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args.
+set dummy ${ac_tool_prefix}gcc; ac_word=$2
+{ echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
+if test "${ac_cv_prog_CC+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_CC="${ac_tool_prefix}gcc"
+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+  { echo "$as_me:$LINENO: result: $CC" >&5
+echo "${ECHO_T}$CC" >&6; }
+else
+  { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_CC"; then
+  ac_ct_CC=$CC
+  # Extract the first word of "gcc", so it can be a program name with args.
+set dummy gcc; ac_word=$2
+{ echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
+if test "${ac_cv_prog_ac_ct_CC+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if test -n "$ac_ct_CC"; then
+  ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_ac_ct_CC="gcc"
+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+  { echo "$as_me:$LINENO: result: $ac_ct_CC" >&5
+echo "${ECHO_T}$ac_ct_CC" >&6; }
+else
+  { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+fi
+
+  if test "x$ac_ct_CC" = x; then
+    CC=""
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ echo "$as_me:$LINENO: WARNING: In the future, Autoconf will not detect cross-tools
+whose name does not start with the host triplet.  If you think this
+configuration is useful to you, please write to autoconf@gnu.org." >&5
+echo "$as_me: WARNING: In the future, Autoconf will not detect cross-tools
+whose name does not start with the host triplet.  If you think this
+configuration is useful to you, please write to autoconf@gnu.org." >&2;}
+ac_tool_warned=yes ;;
+esac
+    CC=$ac_ct_CC
+  fi
+else
+  CC="$ac_cv_prog_CC"
+fi
+
+if test -z "$CC"; then
+          if test -n "$ac_tool_prefix"; then
+    # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args.
+set dummy ${ac_tool_prefix}cc; ac_word=$2
+{ echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
+if test "${ac_cv_prog_CC+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_CC="${ac_tool_prefix}cc"
+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+  { echo "$as_me:$LINENO: result: $CC" >&5
+echo "${ECHO_T}$CC" >&6; }
+else
+  { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+fi
+
+
+  fi
+fi
+if test -z "$CC"; then
+  # Extract the first word of "cc", so it can be a program name with args.
+set dummy cc; ac_word=$2
+{ echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
+if test "${ac_cv_prog_CC+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+  ac_prog_rejected=no
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then
+       ac_prog_rejected=yes
+       continue
+     fi
+    ac_cv_prog_CC="cc"
+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+IFS=$as_save_IFS
+
+if test $ac_prog_rejected = yes; then
+  # We found a bogon in the path, so make sure we never use it.
+  set dummy $ac_cv_prog_CC
+  shift
+  if test $@%:@ != 0; then
+    # We chose a different compiler from the bogus one.
+    # However, it has the same basename, so the bogon will be chosen
+    # first if we set CC to just the basename; use the full file name.
+    shift
+    ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@"
+  fi
+fi
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+  { echo "$as_me:$LINENO: result: $CC" >&5
+echo "${ECHO_T}$CC" >&6; }
+else
+  { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+fi
+
+
+fi
+if test -z "$CC"; then
+  if test -n "$ac_tool_prefix"; then
+  for ac_prog in cl.exe
+  do
+    # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
+set dummy $ac_tool_prefix$ac_prog; ac_word=$2
+{ echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
+if test "${ac_cv_prog_CC+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_CC="$ac_tool_prefix$ac_prog"
+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+  { echo "$as_me:$LINENO: result: $CC" >&5
+echo "${ECHO_T}$CC" >&6; }
+else
+  { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+fi
+
+
+    test -n "$CC" && break
+  done
+fi
+if test -z "$CC"; then
+  ac_ct_CC=$CC
+  for ac_prog in cl.exe
+do
+  # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
+if test "${ac_cv_prog_ac_ct_CC+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if test -n "$ac_ct_CC"; then
+  ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_ac_ct_CC="$ac_prog"
+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+  { echo "$as_me:$LINENO: result: $ac_ct_CC" >&5
+echo "${ECHO_T}$ac_ct_CC" >&6; }
+else
+  { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+fi
+
+
+  test -n "$ac_ct_CC" && break
+done
+
+  if test "x$ac_ct_CC" = x; then
+    CC=""
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ echo "$as_me:$LINENO: WARNING: In the future, Autoconf will not detect cross-tools
+whose name does not start with the host triplet.  If you think this
+configuration is useful to you, please write to autoconf@gnu.org." >&5
+echo "$as_me: WARNING: In the future, Autoconf will not detect cross-tools
+whose name does not start with the host triplet.  If you think this
+configuration is useful to you, please write to autoconf@gnu.org." >&2;}
+ac_tool_warned=yes ;;
+esac
+    CC=$ac_ct_CC
+  fi
+fi
+
+fi
+
+
+test -z "$CC" && { { echo "$as_me:$LINENO: error: no acceptable C compiler found in \$PATH
+See \`config.log' for more details." >&5
+echo "$as_me: error: no acceptable C compiler found in \$PATH
+See \`config.log' for more details." >&2;}
+   { (exit 1); exit 1; }; }
+
+# Provide some information about the compiler.
+echo "$as_me:$LINENO: checking for C compiler version" >&5
+ac_compiler=`set X $ac_compile; echo $2`
+{ (ac_try="$ac_compiler --version >&5"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compiler --version >&5") 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }
+{ (ac_try="$ac_compiler -v >&5"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compiler -v >&5") 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }
+{ (ac_try="$ac_compiler -V >&5"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compiler -V >&5") 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }
+
+{ echo "$as_me:$LINENO: checking whether we are using the GNU C compiler" >&5
+echo $ECHO_N "checking whether we are using the GNU C compiler... $ECHO_C" >&6; }
+if test "${ac_cv_c_compiler_gnu+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+int
+main ()
+{
+#ifndef __GNUC__
+       choke me
+#endif
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_compiler_gnu=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_compiler_gnu=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ac_cv_c_compiler_gnu=$ac_compiler_gnu
+
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_c_compiler_gnu" >&5
+echo "${ECHO_T}$ac_cv_c_compiler_gnu" >&6; }
+GCC=`test $ac_compiler_gnu = yes && echo yes`
+ac_test_CFLAGS=${CFLAGS+set}
+ac_save_CFLAGS=$CFLAGS
+{ echo "$as_me:$LINENO: checking whether $CC accepts -g" >&5
+echo $ECHO_N "checking whether $CC accepts -g... $ECHO_C" >&6; }
+if test "${ac_cv_prog_cc_g+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_save_c_werror_flag=$ac_c_werror_flag
+   ac_c_werror_flag=yes
+   ac_cv_prog_cc_g=no
+   CFLAGS="-g"
+   cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_cv_prog_cc_g=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       CFLAGS=""
+      cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  :
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_c_werror_flag=$ac_save_c_werror_flag
+        CFLAGS="-g"
+        cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_cv_prog_cc_g=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+   ac_c_werror_flag=$ac_save_c_werror_flag
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_prog_cc_g" >&5
+echo "${ECHO_T}$ac_cv_prog_cc_g" >&6; }
+if test "$ac_test_CFLAGS" = set; then
+  CFLAGS=$ac_save_CFLAGS
+elif test $ac_cv_prog_cc_g = yes; then
+  if test "$GCC" = yes; then
+    CFLAGS="-g -O2"
+  else
+    CFLAGS="-g"
+  fi
+else
+  if test "$GCC" = yes; then
+    CFLAGS="-O2"
+  else
+    CFLAGS=
+  fi
+fi
+{ echo "$as_me:$LINENO: checking for $CC option to accept ISO C89" >&5
+echo $ECHO_N "checking for $CC option to accept ISO C89... $ECHO_C" >&6; }
+if test "${ac_cv_prog_cc_c89+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_cv_prog_cc_c89=no
+ac_save_CC=$CC
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <stdarg.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+/* Most of the following tests are stolen from RCS 5.7's src/conf.sh.  */
+struct buf { int x; };
+FILE * (*rcsopen) (struct buf *, struct stat *, int);
+static char *e (p, i)
+     char **p;
+     int i;
+{
+  return p[i];
+}
+static char *f (char * (*g) (char **, int), char **p, ...)
+{
+  char *s;
+  va_list v;
+  va_start (v,p);
+  s = g (p, va_arg (v,int));
+  va_end (v);
+  return s;
+}
+
+/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default.  It has
+   function prototypes and stuff, but not '\xHH' hex character constants.
+   These don't provoke an error unfortunately, instead are silently treated
+   as 'x'.  The following induces an error, until -std is added to get
+   proper ANSI mode.  Curiously '\x00'!='x' always comes out true, for an
+   array size at least.  It's necessary to write '\x00'==0 to get something
+   that's true only with -std.  */
+int osf4_cc_array ['\x00' == 0 ? 1 : -1];
+
+/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters
+   inside strings and character constants.  */
+#define FOO(x) 'x'
+int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1];
+
+int test (int i, double x);
+struct s1 {int (*f) (int a);};
+struct s2 {int (*f) (double a);};
+int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int);
+int argc;
+char **argv;
+int
+main ()
+{
+return f (e, argv, 0) != argv[0]  ||  f (e, argv, 1) != argv[1];
+  ;
+  return 0;
+}
+_ACEOF
+for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \
+       -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__"
+do
+  CC="$ac_save_CC $ac_arg"
+  rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_cv_prog_cc_c89=$ac_arg
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       
+fi
+
+rm -f core conftest.err conftest.$ac_objext 
+  test "x$ac_cv_prog_cc_c89" != "xno" && break
+done
+rm -f conftest.$ac_ext
+CC=$ac_save_CC
+
+fi
+# AC_CACHE_VAL
+case "x$ac_cv_prog_cc_c89" in
+  x)
+    { echo "$as_me:$LINENO: result: none needed" >&5
+echo "${ECHO_T}none needed" >&6; } ;;
+  xno)
+    { echo "$as_me:$LINENO: result: unsupported" >&5
+echo "${ECHO_T}unsupported" >&6; } ;;
+  *)
+    CC="$CC $ac_cv_prog_cc_c89"
+    { echo "$as_me:$LINENO: result: $ac_cv_prog_cc_c89" >&5
+echo "${ECHO_T}$ac_cv_prog_cc_c89" >&6; } ;;
+esac
+
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+am_cv_prog_cc_stdc=$ac_cv_prog_cc_stdc
+
+
+
+
+{ echo "$as_me:$LINENO: checking for library containing crypt" >&5
+echo $ECHO_N "checking for library containing crypt... $ECHO_C" >&6; }
+if test "${ac_cv_search_crypt+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_func_search_save_LIBS=$LIBS
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char crypt ();
+int
+main ()
+{
+return crypt ();
+  ;
+  return 0;
+}
+_ACEOF
+for ac_lib in '' descrypt crypt; do
+  if test -z "$ac_lib"; then
+    ac_res="none required"
+  else
+    ac_res=-l$ac_lib
+    LIBS="-l$ac_lib  $ac_func_search_save_LIBS"
+  fi
+  rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext &&
+       $as_test_x conftest$ac_exeext; then
+  ac_cv_search_crypt=$ac_res
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext 
+  if test "${ac_cv_search_crypt+set}" = set; then
+  break
+fi
+done
+if test "${ac_cv_search_crypt+set}" = set; then
+  :
+else
+  ac_cv_search_crypt=no
+fi
+rm conftest.$ac_ext
+LIBS=$ac_func_search_save_LIBS
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_search_crypt" >&5
+echo "${ECHO_T}$ac_cv_search_crypt" >&6; }
+ac_res=$ac_cv_search_crypt
+if test "$ac_res" != no; then
+  test "$ac_res" = "none required" || LIBS="$ac_res $LIBS"
+  
+else
+  { { echo "$as_me:$LINENO: error: Unable to find library containing crypt()" >&5
+echo "$as_me: error: Unable to find library containing crypt()" >&2;}
+   { (exit 1); exit 1; }; }
+fi
+
+
+
+   # Most operating systems have gethostbyname() in the default searched
+   # libraries (i.e. libc):
+   { echo "$as_me:$LINENO: checking for gethostbyname" >&5
+echo $ECHO_N "checking for gethostbyname... $ECHO_C" >&6; }
+if test "${ac_cv_func_gethostbyname+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+/* Define gethostbyname to an innocuous variant, in case <limits.h> declares gethostbyname.
+   For example, HP-UX 11i <limits.h> declares gettimeofday.  */
+#define gethostbyname innocuous_gethostbyname
+
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char gethostbyname (); below.
+    Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+    <limits.h> exists even on freestanding compilers.  */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef gethostbyname
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char gethostbyname ();
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined __stub_gethostbyname || defined __stub___gethostbyname
+choke me
+#endif
+
+int
+main ()
+{
+return gethostbyname ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext &&
+       $as_test_x conftest$ac_exeext; then
+  ac_cv_func_gethostbyname=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_func_gethostbyname=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_func_gethostbyname" >&5
+echo "${ECHO_T}$ac_cv_func_gethostbyname" >&6; }
+if test $ac_cv_func_gethostbyname = yes; then
+  :
+else
+  # Some OSes (eg. Solaris) place it in libnsl:
+     
+{ echo "$as_me:$LINENO: checking for gethostbyname in -lnsl" >&5
+echo $ECHO_N "checking for gethostbyname in -lnsl... $ECHO_C" >&6; }
+if test "${ac_cv_lib_nsl_gethostbyname+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lnsl  $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char gethostbyname ();
+int
+main ()
+{
+return gethostbyname ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext &&
+       $as_test_x conftest$ac_exeext; then
+  ac_cv_lib_nsl_gethostbyname=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_lib_nsl_gethostbyname=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_lib_nsl_gethostbyname" >&5
+echo "${ECHO_T}$ac_cv_lib_nsl_gethostbyname" >&6; }
+if test $ac_cv_lib_nsl_gethostbyname = yes; then
+  cat >>confdefs.h <<_ACEOF
+@%:@define HAVE_LIBNSL 1
+_ACEOF
+
+  LIBS="-lnsl $LIBS"
+
+else
+  # Some strange OSes (SINIX) have it in libsocket:
+       
+{ echo "$as_me:$LINENO: checking for gethostbyname in -lsocket" >&5
+echo $ECHO_N "checking for gethostbyname in -lsocket... $ECHO_C" >&6; }
+if test "${ac_cv_lib_socket_gethostbyname+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lsocket  $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char gethostbyname ();
+int
+main ()
+{
+return gethostbyname ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext &&
+       $as_test_x conftest$ac_exeext; then
+  ac_cv_lib_socket_gethostbyname=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_lib_socket_gethostbyname=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_lib_socket_gethostbyname" >&5
+echo "${ECHO_T}$ac_cv_lib_socket_gethostbyname" >&6; }
+if test $ac_cv_lib_socket_gethostbyname = yes; then
+  cat >>confdefs.h <<_ACEOF
+@%:@define HAVE_LIBSOCKET 1
+_ACEOF
+
+  LIBS="-lsocket $LIBS"
+
+else
+  # Unfortunately libsocket sometimes depends on libnsl.
+          # AC_CHECK_LIB's API is essentially broken so the following
+          # ugliness is necessary:
+          { echo "$as_me:$LINENO: checking for gethostbyname in -lsocket" >&5
+echo $ECHO_N "checking for gethostbyname in -lsocket... $ECHO_C" >&6; }
+if test "${ac_cv_lib_socket_gethostbyname+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lsocket -lnsl $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char gethostbyname ();
+int
+main ()
+{
+return gethostbyname ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext &&
+       $as_test_x conftest$ac_exeext; then
+  ac_cv_lib_socket_gethostbyname=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_lib_socket_gethostbyname=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_lib_socket_gethostbyname" >&5
+echo "${ECHO_T}$ac_cv_lib_socket_gethostbyname" >&6; }
+if test $ac_cv_lib_socket_gethostbyname = yes; then
+  LIBS="-lsocket -lnsl $LIBS"
+else
+  
+{ echo "$as_me:$LINENO: checking for gethostbyname in -lresolv" >&5
+echo $ECHO_N "checking for gethostbyname in -lresolv... $ECHO_C" >&6; }
+if test "${ac_cv_lib_resolv_gethostbyname+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lresolv  $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char gethostbyname ();
+int
+main ()
+{
+return gethostbyname ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext &&
+       $as_test_x conftest$ac_exeext; then
+  ac_cv_lib_resolv_gethostbyname=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_lib_resolv_gethostbyname=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_lib_resolv_gethostbyname" >&5
+echo "${ECHO_T}$ac_cv_lib_resolv_gethostbyname" >&6; }
+if test $ac_cv_lib_resolv_gethostbyname = yes; then
+  cat >>confdefs.h <<_ACEOF
+@%:@define HAVE_LIBRESOLV 1
+_ACEOF
+
+  LIBS="-lresolv $LIBS"
+
+fi
+
+fi
+
+       
+fi
+
+     
+fi
+
+   
+fi
+
+  { echo "$as_me:$LINENO: checking for socket" >&5
+echo $ECHO_N "checking for socket... $ECHO_C" >&6; }
+if test "${ac_cv_func_socket+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+/* Define socket to an innocuous variant, in case <limits.h> declares socket.
+   For example, HP-UX 11i <limits.h> declares gettimeofday.  */
+#define socket innocuous_socket
+
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char socket (); below.
+    Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+    <limits.h> exists even on freestanding compilers.  */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef socket
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char socket ();
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined __stub_socket || defined __stub___socket
+choke me
+#endif
+
+int
+main ()
+{
+return socket ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext &&
+       $as_test_x conftest$ac_exeext; then
+  ac_cv_func_socket=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_func_socket=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_func_socket" >&5
+echo "${ECHO_T}$ac_cv_func_socket" >&6; }
+if test $ac_cv_func_socket = yes; then
+  :
+else
+  
+{ echo "$as_me:$LINENO: checking for socket in -lsocket" >&5
+echo $ECHO_N "checking for socket in -lsocket... $ECHO_C" >&6; }
+if test "${ac_cv_lib_socket_socket+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lsocket  $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char socket ();
+int
+main ()
+{
+return socket ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext &&
+       $as_test_x conftest$ac_exeext; then
+  ac_cv_lib_socket_socket=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_lib_socket_socket=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_lib_socket_socket" >&5
+echo "${ECHO_T}$ac_cv_lib_socket_socket" >&6; }
+if test $ac_cv_lib_socket_socket = yes; then
+  cat >>confdefs.h <<_ACEOF
+@%:@define HAVE_LIBSOCKET 1
+_ACEOF
+
+  LIBS="-lsocket $LIBS"
+
+else
+  { echo "$as_me:$LINENO: checking for socket in -lsocket" >&5
+echo $ECHO_N "checking for socket in -lsocket... $ECHO_C" >&6; }
+if test "${ac_cv_lib_socket_socket+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lsocket -lnsl $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char socket ();
+int
+main ()
+{
+return socket ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext &&
+       $as_test_x conftest$ac_exeext; then
+  ac_cv_lib_socket_socket=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_lib_socket_socket=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_lib_socket_socket" >&5
+echo "${ECHO_T}$ac_cv_lib_socket_socket" >&6; }
+if test $ac_cv_lib_socket_socket = yes; then
+  LIBS="-lsocket -lnsl $LIBS"
+fi
+
+fi
+
+fi
+
+  
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+{ echo "$as_me:$LINENO: checking how to run the C preprocessor" >&5
+echo $ECHO_N "checking how to run the C preprocessor... $ECHO_C" >&6; }
+# On Suns, sometimes $CPP names a directory.
+if test -n "$CPP" && test -d "$CPP"; then
+  CPP=
+fi
+if test -z "$CPP"; then
+  if test "${ac_cv_prog_CPP+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+      # Double quotes because CPP needs to be expanded
+    for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp"
+    do
+      ac_preproc_ok=false
+for ac_c_preproc_warn_flag in '' yes
+do
+  # Use a header file that comes with gcc, so configuring glibc
+  # with a fresh cross-compiler works.
+  # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+  # <limits.h> exists even on freestanding compilers.
+  # On the NeXT, cc -E runs the code through the compiler's parser,
+  # not just through cpp. "Syntax error" is here to catch this case.
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+@%:@ifdef __STDC__
+@%:@ include <limits.h>
+@%:@else
+@%:@ include <assert.h>
+@%:@endif
+                    Syntax error
+_ACEOF
+if { (ac_try="$ac_cpp conftest.$ac_ext"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } >/dev/null && {
+        test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       }; then
+  :
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+  # Broken: fails on valid input.
+continue
+fi
+
+rm -f conftest.err conftest.$ac_ext
+
+  # OK, works on sane cases.  Now check whether nonexistent headers
+  # can be detected and how.
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+@%:@include <ac_nonexistent.h>
+_ACEOF
+if { (ac_try="$ac_cpp conftest.$ac_ext"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } >/dev/null && {
+        test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       }; then
+  # Broken: success on invalid input.
+continue
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+  # Passes both tests.
+ac_preproc_ok=:
+break
+fi
+
+rm -f conftest.err conftest.$ac_ext
+
+done
+# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
+rm -f conftest.err conftest.$ac_ext
+if $ac_preproc_ok; then
+  break
+fi
+
+    done
+    ac_cv_prog_CPP=$CPP
+  
+fi
+  CPP=$ac_cv_prog_CPP
+else
+  ac_cv_prog_CPP=$CPP
+fi
+{ echo "$as_me:$LINENO: result: $CPP" >&5
+echo "${ECHO_T}$CPP" >&6; }
+ac_preproc_ok=false
+for ac_c_preproc_warn_flag in '' yes
+do
+  # Use a header file that comes with gcc, so configuring glibc
+  # with a fresh cross-compiler works.
+  # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+  # <limits.h> exists even on freestanding compilers.
+  # On the NeXT, cc -E runs the code through the compiler's parser,
+  # not just through cpp. "Syntax error" is here to catch this case.
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+@%:@ifdef __STDC__
+@%:@ include <limits.h>
+@%:@else
+@%:@ include <assert.h>
+@%:@endif
+                    Syntax error
+_ACEOF
+if { (ac_try="$ac_cpp conftest.$ac_ext"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } >/dev/null && {
+        test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       }; then
+  :
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+  # Broken: fails on valid input.
+continue
+fi
+
+rm -f conftest.err conftest.$ac_ext
+
+  # OK, works on sane cases.  Now check whether nonexistent headers
+  # can be detected and how.
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+@%:@include <ac_nonexistent.h>
+_ACEOF
+if { (ac_try="$ac_cpp conftest.$ac_ext"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } >/dev/null && {
+        test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       }; then
+  # Broken: success on invalid input.
+continue
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+  # Passes both tests.
+ac_preproc_ok=:
+break
+fi
+
+rm -f conftest.err conftest.$ac_ext
+
+done
+# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
+rm -f conftest.err conftest.$ac_ext
+if $ac_preproc_ok; then
+  :
+else
+  { { echo "$as_me:$LINENO: error: C preprocessor \"$CPP\" fails sanity check
+See \`config.log' for more details." >&5
+echo "$as_me: error: C preprocessor \"$CPP\" fails sanity check
+See \`config.log' for more details." >&2;}
+   { (exit 1); exit 1; }; }
+fi
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+{ echo "$as_me:$LINENO: checking for grep that handles long lines and -e" >&5
+echo $ECHO_N "checking for grep that handles long lines and -e... $ECHO_C" >&6; }
+if test "${ac_cv_path_GREP+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  # Extract the first word of "grep ggrep" to use in msg output
+if test -z "$GREP"; then
+set dummy grep ggrep; ac_prog_name=$2
+if test "${ac_cv_path_GREP+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_path_GREP_found=false
+# Loop through the user's path and test for each of PROGNAME-LIST
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_prog in grep ggrep; do
+  for ac_exec_ext in '' $ac_executable_extensions; do
+    ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext"
+    { test -f "$ac_path_GREP" && $as_test_x "$ac_path_GREP"; } || continue
+    # Check for GNU ac_path_GREP and select it if it is found.
+  # Check for GNU $ac_path_GREP
+case `"$ac_path_GREP" --version 2>&1` in
+*GNU*)
+  ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;;
+*)
+  ac_count=0
+  echo $ECHO_N "0123456789$ECHO_C" >"conftest.in"
+  while :
+  do
+    cat "conftest.in" "conftest.in" >"conftest.tmp"
+    mv "conftest.tmp" "conftest.in"
+    cp "conftest.in" "conftest.nl"
+    echo 'GREP' >> "conftest.nl"
+    "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break
+    diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
+    ac_count=`expr $ac_count + 1`
+    if test $ac_count -gt ${ac_path_GREP_max-0}; then
+      # Best one so far, save it but keep looking for a better one
+      ac_cv_path_GREP="$ac_path_GREP"
+      ac_path_GREP_max=$ac_count
+    fi
+    # 10*(2^10) chars as input seems more than enough
+    test $ac_count -gt 10 && break
+  done
+  rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
+esac
+
+
+    $ac_path_GREP_found && break 3
+  done
+done
+
+done
+IFS=$as_save_IFS
+
+
+fi
+
+GREP="$ac_cv_path_GREP"
+if test -z "$GREP"; then
+  { { echo "$as_me:$LINENO: error: no acceptable $ac_prog_name could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" >&5
+echo "$as_me: error: no acceptable $ac_prog_name could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" >&2;}
+   { (exit 1); exit 1; }; }
+fi
+
+else
+  ac_cv_path_GREP=$GREP
+fi
+
+
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_path_GREP" >&5
+echo "${ECHO_T}$ac_cv_path_GREP" >&6; }
+ GREP="$ac_cv_path_GREP"
+
+{ echo "$as_me:$LINENO: checking for egrep" >&5
+echo $ECHO_N "checking for egrep... $ECHO_C" >&6; }
+if test "${ac_cv_path_EGREP+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if echo a | $GREP -E '(a|b)' >/dev/null 2>&1
+   then ac_cv_path_EGREP="$GREP -E"
+   else
+     # Extract the first word of "egrep" to use in msg output
+if test -z "$EGREP"; then
+set dummy egrep; ac_prog_name=$2
+if test "${ac_cv_path_EGREP+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_path_EGREP_found=false
+# Loop through the user's path and test for each of PROGNAME-LIST
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_prog in egrep; do
+  for ac_exec_ext in '' $ac_executable_extensions; do
+    ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext"
+    { test -f "$ac_path_EGREP" && $as_test_x "$ac_path_EGREP"; } || continue
+    # Check for GNU ac_path_EGREP and select it if it is found.
+  # Check for GNU $ac_path_EGREP
+case `"$ac_path_EGREP" --version 2>&1` in
+*GNU*)
+  ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;;
+*)
+  ac_count=0
+  echo $ECHO_N "0123456789$ECHO_C" >"conftest.in"
+  while :
+  do
+    cat "conftest.in" "conftest.in" >"conftest.tmp"
+    mv "conftest.tmp" "conftest.in"
+    cp "conftest.in" "conftest.nl"
+    echo 'EGREP' >> "conftest.nl"
+    "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break
+    diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
+    ac_count=`expr $ac_count + 1`
+    if test $ac_count -gt ${ac_path_EGREP_max-0}; then
+      # Best one so far, save it but keep looking for a better one
+      ac_cv_path_EGREP="$ac_path_EGREP"
+      ac_path_EGREP_max=$ac_count
+    fi
+    # 10*(2^10) chars as input seems more than enough
+    test $ac_count -gt 10 && break
+  done
+  rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
+esac
+
+
+    $ac_path_EGREP_found && break 3
+  done
+done
+
+done
+IFS=$as_save_IFS
+
+
+fi
+
+EGREP="$ac_cv_path_EGREP"
+if test -z "$EGREP"; then
+  { { echo "$as_me:$LINENO: error: no acceptable $ac_prog_name could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" >&5
+echo "$as_me: error: no acceptable $ac_prog_name could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" >&2;}
+   { (exit 1); exit 1; }; }
+fi
+
+else
+  ac_cv_path_EGREP=$EGREP
+fi
+
+
+   fi
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_path_EGREP" >&5
+echo "${ECHO_T}$ac_cv_path_EGREP" >&6; }
+ EGREP="$ac_cv_path_EGREP"
+
+{ echo "$as_me:$LINENO: checking for ANSI C header files" >&5
+echo $ECHO_N "checking for ANSI C header files... $ECHO_C" >&6; }
+if test "${ac_cv_header_stdc+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <float.h>
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_cv_header_stdc=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_header_stdc=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
+if test $ac_cv_header_stdc = yes; then
+  # SunOS 4.x string.h does not declare mem*, contrary to ANSI.
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <string.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  $EGREP "memchr" >/dev/null 2>&1; then
+  :
+else
+  ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+  # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI.
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <stdlib.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  $EGREP "free" >/dev/null 2>&1; then
+  :
+else
+  ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+  # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi.
+  if test "$cross_compiling" = yes; then
+  :
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <ctype.h>
+#include <stdlib.h>
+#if ((' ' & 0x0FF) == 0x020)
+# define ISLOWER(c) ('a' <= (c) && (c) <= 'z')
+# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c))
+#else
+# define ISLOWER(c) \
+                  (('a' <= (c) && (c) <= 'i') \
+                    || ('j' <= (c) && (c) <= 'r') \
+                    || ('s' <= (c) && (c) <= 'z'))
+# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c))
+#endif
+
+#define XOR(e, f) (((e) && !(f)) || (!(e) && (f)))
+int
+main ()
+{
+  int i;
+  for (i = 0; i < 256; i++)
+    if (XOR (islower (i), ISLOWER (i))
+       || toupper (i) != TOUPPER (i))
+      return 2;
+  return 0;
+}
+_ACEOF
+rm -f conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
+  { (case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_try") 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  :
+else
+  echo "$as_me: program exited with status $ac_status" >&5
+echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+( exit $ac_status )
+ac_cv_header_stdc=no
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+fi
+
+
+fi
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_header_stdc" >&5
+echo "${ECHO_T}$ac_cv_header_stdc" >&6; }
+if test $ac_cv_header_stdc = yes; then
+  
+cat >>confdefs.h <<\_ACEOF
+@%:@define STDC_HEADERS 1
+_ACEOF
+
+fi
+
+# On IRIX 5.3, sys/types and inttypes.h are conflicting.
+
+
+
+
+
+
+
+
+
+for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \
+                 inttypes.h stdint.h unistd.h
+do
+as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
+{ echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; }
+if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+
+@%:@include <$ac_header>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  eval "$as_ac_Header=yes"
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       eval "$as_ac_Header=no"
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+ac_res=`eval echo '${'$as_ac_Header'}'`
+              { echo "$as_me:$LINENO: result: $ac_res" >&5
+echo "${ECHO_T}$ac_res" >&6; }
+if test `eval echo '${'$as_ac_Header'}'` = yes; then
+  cat >>confdefs.h <<_ACEOF
+@%:@define `echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+fi
+
+done
+
+
+
+
+
+
+
+
+
+
+
+
+for ac_header in crypt.h poll.h inttypes.h stdint.h sys/devpoll.h sys/epoll.h sys/event.h sys/param.h sys/resource.h sys/socket.h
+do
+as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
+if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
+  { echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; }
+if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+fi
+ac_res=`eval echo '${'$as_ac_Header'}'`
+              { echo "$as_me:$LINENO: result: $ac_res" >&5
+echo "${ECHO_T}$ac_res" >&6; }
+else
+  # Is the header compilable?
+{ echo "$as_me:$LINENO: checking $ac_header usability" >&5
+echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6; }
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+@%:@include <$ac_header>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_header_compiler=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_header_compiler=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+{ echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
+echo "${ECHO_T}$ac_header_compiler" >&6; }
+
+# Is the header present?
+{ echo "$as_me:$LINENO: checking $ac_header presence" >&5
+echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6; }
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+@%:@include <$ac_header>
+_ACEOF
+if { (ac_try="$ac_cpp conftest.$ac_ext"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } >/dev/null && {
+        test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       }; then
+  ac_header_preproc=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+  ac_header_preproc=no
+fi
+
+rm -f conftest.err conftest.$ac_ext
+{ echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
+echo "${ECHO_T}$ac_header_preproc" >&6; }
+
+# So?  What about this header?
+case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
+  yes:no: )
+    { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5
+echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;}
+    ac_header_preproc=yes
+    ;;
+  no:yes:* )
+    { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5
+echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header:     check for missing prerequisite headers?" >&5
+echo "$as_me: WARNING: $ac_header:     check for missing prerequisite headers?" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5
+echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&5
+echo "$as_me: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5
+echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;}
+    
+    ;;
+esac
+{ echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; }
+if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  eval "$as_ac_Header=\$ac_header_preproc"
+fi
+ac_res=`eval echo '${'$as_ac_Header'}'`
+              { echo "$as_me:$LINENO: result: $ac_res" >&5
+echo "${ECHO_T}$ac_res" >&6; }
+
+fi
+if test `eval echo '${'$as_ac_Header'}'` = yes; then
+  cat >>confdefs.h <<_ACEOF
+@%:@define `echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+fi
+
+done
+
+
+{ echo "$as_me:$LINENO: checking whether byte ordering is bigendian" >&5
+echo $ECHO_N "checking whether byte ordering is bigendian... $ECHO_C" >&6; }
+if test "${ac_cv_c_bigendian+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  # See if sys/param.h defines the BYTE_ORDER macro.
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <sys/types.h>
+#include <sys/param.h>
+
+int
+main ()
+{
+#if  ! (defined BYTE_ORDER && defined BIG_ENDIAN && defined LITTLE_ENDIAN \
+       && BYTE_ORDER && BIG_ENDIAN && LITTLE_ENDIAN)
+ bogus endian macros
+#endif
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  # It does; now see whether it defined to BIG_ENDIAN or not.
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <sys/types.h>
+#include <sys/param.h>
+
+int
+main ()
+{
+#if BYTE_ORDER != BIG_ENDIAN
+ not big endian
+#endif
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_cv_c_bigendian=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_c_bigendian=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       # It does not; compile a test program.
+if test "$cross_compiling" = yes; then
+  # try to guess the endianness by grepping values into an object file
+  ac_cv_c_bigendian=unknown
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+short int ascii_mm[] = { 0x4249, 0x4765, 0x6E44, 0x6961, 0x6E53, 0x7953, 0 };
+short int ascii_ii[] = { 0x694C, 0x5454, 0x656C, 0x6E45, 0x6944, 0x6E61, 0 };
+void _ascii () { char *s = (char *) ascii_mm; s = (char *) ascii_ii; }
+short int ebcdic_ii[] = { 0x89D3, 0xE3E3, 0x8593, 0x95C5, 0x89C4, 0x9581, 0 };
+short int ebcdic_mm[] = { 0xC2C9, 0xC785, 0x95C4, 0x8981, 0x95E2, 0xA8E2, 0 };
+void _ebcdic () { char *s = (char *) ebcdic_mm; s = (char *) ebcdic_ii; }
+int
+main ()
+{
+ _ascii (); _ebcdic (); 
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  if grep BIGenDianSyS conftest.$ac_objext >/dev/null ; then
+  ac_cv_c_bigendian=yes
+fi
+if grep LiTTleEnDian conftest.$ac_objext >/dev/null ; then
+  if test "$ac_cv_c_bigendian" = unknown; then
+    ac_cv_c_bigendian=no
+  else
+    # finding both strings is unlikely to happen, but who knows?
+    ac_cv_c_bigendian=unknown
+  fi
+fi
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+int
+main ()
+{
+
+  /* Are we little or big endian?  From Harbison&Steele.  */
+  union
+  {
+    long int l;
+    char c[sizeof (long int)];
+  } u;
+  u.l = 1;
+  return u.c[sizeof (long int) - 1] == 1;
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
+  { (case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_try") 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_c_bigendian=no
+else
+  echo "$as_me: program exited with status $ac_status" >&5
+echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+( exit $ac_status )
+ac_cv_c_bigendian=yes
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+fi
+
+
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_c_bigendian" >&5
+echo "${ECHO_T}$ac_cv_c_bigendian" >&6; }
+case $ac_cv_c_bigendian in
+  yes)
+    
+cat >>confdefs.h <<\_ACEOF
+@%:@define WORDS_BIGENDIAN 1
+_ACEOF
+ ;;
+  no)
+     ;;
+  *)
+    { { echo "$as_me:$LINENO: error: unknown endianness
+presetting ac_cv_c_bigendian=no (or yes) will help" >&5
+echo "$as_me: error: unknown endianness
+presetting ac_cv_c_bigendian=no (or yes) will help" >&2;}
+   { (exit 1); exit 1; }; } ;;
+esac
+
+{ echo "$as_me:$LINENO: checking for size_t" >&5
+echo $ECHO_N "checking for size_t... $ECHO_C" >&6; }
+if test "${ac_cv_type_size_t+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+typedef size_t ac__type_new_;
+int
+main ()
+{
+if ((ac__type_new_ *) 0)
+  return 0;
+if (sizeof (ac__type_new_))
+  return 0;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_cv_type_size_t=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_type_size_t=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_type_size_t" >&5
+echo "${ECHO_T}$ac_cv_type_size_t" >&6; }
+if test $ac_cv_type_size_t = yes; then
+  :
+else
+  
+cat >>confdefs.h <<_ACEOF
+@%:@define size_t unsigned int
+_ACEOF
+
+fi
+
+{ echo "$as_me:$LINENO: checking whether time.h and sys/time.h may both be included" >&5
+echo $ECHO_N "checking whether time.h and sys/time.h may both be included... $ECHO_C" >&6; }
+if test "${ac_cv_header_time+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <sys/types.h>
+#include <sys/time.h>
+#include <time.h>
+
+int
+main ()
+{
+if ((struct tm *) 0)
+return 0;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_cv_header_time=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_header_time=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_header_time" >&5
+echo "${ECHO_T}$ac_cv_header_time" >&6; }
+if test $ac_cv_header_time = yes; then
+  
+cat >>confdefs.h <<\_ACEOF
+@%:@define TIME_WITH_SYS_TIME 1
+_ACEOF
+
+fi
+
+{ echo "$as_me:$LINENO: checking whether struct tm is in sys/time.h or time.h" >&5
+echo $ECHO_N "checking whether struct tm is in sys/time.h or time.h... $ECHO_C" >&6; }
+if test "${ac_cv_struct_tm+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <sys/types.h>
+#include <time.h>
+
+int
+main ()
+{
+struct tm tm;
+                                    int *p = &tm.tm_sec;
+                                    return !p;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_cv_struct_tm=time.h
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_struct_tm=sys/time.h
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_struct_tm" >&5
+echo "${ECHO_T}$ac_cv_struct_tm" >&6; }
+if test $ac_cv_struct_tm = sys/time.h; then
+  
+cat >>confdefs.h <<\_ACEOF
+@%:@define TM_IN_SYS_TIME 1
+_ACEOF
+
+fi
+
+{ echo "$as_me:$LINENO: checking for uid_t in sys/types.h" >&5
+echo $ECHO_N "checking for uid_t in sys/types.h... $ECHO_C" >&6; }
+if test "${ac_cv_type_uid_t+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <sys/types.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  $EGREP "uid_t" >/dev/null 2>&1; then
+  ac_cv_type_uid_t=yes
+else
+  ac_cv_type_uid_t=no
+fi
+rm -f conftest*
+
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_type_uid_t" >&5
+echo "${ECHO_T}$ac_cv_type_uid_t" >&6; }
+if test $ac_cv_type_uid_t = no; then
+  
+cat >>confdefs.h <<\_ACEOF
+@%:@define uid_t int
+_ACEOF
+
+  
+cat >>confdefs.h <<\_ACEOF
+@%:@define gid_t int
+_ACEOF
+
+fi
+
+{ echo "$as_me:$LINENO: checking for short" >&5
+echo $ECHO_N "checking for short... $ECHO_C" >&6; }
+if test "${ac_cv_type_short+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+typedef short ac__type_new_;
+int
+main ()
+{
+if ((ac__type_new_ *) 0)
+  return 0;
+if (sizeof (ac__type_new_))
+  return 0;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_cv_type_short=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_type_short=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_type_short" >&5
+echo "${ECHO_T}$ac_cv_type_short" >&6; }
+
+# The cast to long int works around a bug in the HP C Compiler
+# version HP92453-01 B.11.11.23709.GP, which incorrectly rejects
+# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'.
+# This bug is HP SR number 8606223364.
+{ echo "$as_me:$LINENO: checking size of short" >&5
+echo $ECHO_N "checking size of short... $ECHO_C" >&6; }
+if test "${ac_cv_sizeof_short+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if test "$cross_compiling" = yes; then
+  # Depending upon the size, compute the lo and hi bounds.
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+   typedef short ac__type_sizeof_;
+int
+main ()
+{
+static int test_array @<:@1 - 2 * !(((long int) (sizeof (ac__type_sizeof_))) >= 0)@:>@;
+test_array @<:@0@:>@ = 0
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_lo=0 ac_mid=0
+  while :; do
+    cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+   typedef short ac__type_sizeof_;
+int
+main ()
+{
+static int test_array @<:@1 - 2 * !(((long int) (sizeof (ac__type_sizeof_))) <= $ac_mid)@:>@;
+test_array @<:@0@:>@ = 0
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_hi=$ac_mid; break
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_lo=`expr $ac_mid + 1`
+                       if test $ac_lo -le $ac_mid; then
+                         ac_lo= ac_hi=
+                         break
+                       fi
+                       ac_mid=`expr 2 '*' $ac_mid + 1`
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+  done
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+   typedef short ac__type_sizeof_;
+int
+main ()
+{
+static int test_array @<:@1 - 2 * !(((long int) (sizeof (ac__type_sizeof_))) < 0)@:>@;
+test_array @<:@0@:>@ = 0
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_hi=-1 ac_mid=-1
+  while :; do
+    cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+   typedef short ac__type_sizeof_;
+int
+main ()
+{
+static int test_array @<:@1 - 2 * !(((long int) (sizeof (ac__type_sizeof_))) >= $ac_mid)@:>@;
+test_array @<:@0@:>@ = 0
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_lo=$ac_mid; break
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_hi=`expr '(' $ac_mid ')' - 1`
+                       if test $ac_mid -le $ac_hi; then
+                         ac_lo= ac_hi=
+                         break
+                       fi
+                       ac_mid=`expr 2 '*' $ac_mid`
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+  done
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_lo= ac_hi=
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+# Binary search between lo and hi bounds.
+while test "x$ac_lo" != "x$ac_hi"; do
+  ac_mid=`expr '(' $ac_hi - $ac_lo ')' / 2 + $ac_lo`
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+   typedef short ac__type_sizeof_;
+int
+main ()
+{
+static int test_array @<:@1 - 2 * !(((long int) (sizeof (ac__type_sizeof_))) <= $ac_mid)@:>@;
+test_array @<:@0@:>@ = 0
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_hi=$ac_mid
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_lo=`expr '(' $ac_mid ')' + 1`
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+done
+case $ac_lo in
+?*) ac_cv_sizeof_short=$ac_lo;;
+'') if test "$ac_cv_type_short" = yes; then
+     { { echo "$as_me:$LINENO: error: cannot compute sizeof (short)
+See \`config.log' for more details." >&5
+echo "$as_me: error: cannot compute sizeof (short)
+See \`config.log' for more details." >&2;}
+   { (exit 77); exit 77; }; }
+   else
+     ac_cv_sizeof_short=0
+   fi ;;
+esac
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+   typedef short ac__type_sizeof_;
+static long int longval () { return (long int) (sizeof (ac__type_sizeof_)); }
+static unsigned long int ulongval () { return (long int) (sizeof (ac__type_sizeof_)); }
+@%:@include <stdio.h>
+@%:@include <stdlib.h>
+int
+main ()
+{
+
+  FILE *f = fopen ("conftest.val", "w");
+  if (! f)
+    return 1;
+  if (((long int) (sizeof (ac__type_sizeof_))) < 0)
+    {
+      long int i = longval ();
+      if (i != ((long int) (sizeof (ac__type_sizeof_))))
+       return 1;
+      fprintf (f, "%ld\n", i);
+    }
+  else
+    {
+      unsigned long int i = ulongval ();
+      if (i != ((long int) (sizeof (ac__type_sizeof_))))
+       return 1;
+      fprintf (f, "%lu\n", i);
+    }
+  return ferror (f) || fclose (f) != 0;
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
+  { (case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_try") 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_sizeof_short=`cat conftest.val`
+else
+  echo "$as_me: program exited with status $ac_status" >&5
+echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+( exit $ac_status )
+if test "$ac_cv_type_short" = yes; then
+     { { echo "$as_me:$LINENO: error: cannot compute sizeof (short)
+See \`config.log' for more details." >&5
+echo "$as_me: error: cannot compute sizeof (short)
+See \`config.log' for more details." >&2;}
+   { (exit 77); exit 77; }; }
+   else
+     ac_cv_sizeof_short=0
+   fi
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f conftest.val
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_sizeof_short" >&5
+echo "${ECHO_T}$ac_cv_sizeof_short" >&6; }
+
+
+
+cat >>confdefs.h <<_ACEOF
+@%:@define SIZEOF_SHORT $ac_cv_sizeof_short
+_ACEOF
+
+
+{ echo "$as_me:$LINENO: checking for int" >&5
+echo $ECHO_N "checking for int... $ECHO_C" >&6; }
+if test "${ac_cv_type_int+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+typedef int ac__type_new_;
+int
+main ()
+{
+if ((ac__type_new_ *) 0)
+  return 0;
+if (sizeof (ac__type_new_))
+  return 0;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_cv_type_int=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_type_int=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_type_int" >&5
+echo "${ECHO_T}$ac_cv_type_int" >&6; }
+
+# The cast to long int works around a bug in the HP C Compiler
+# version HP92453-01 B.11.11.23709.GP, which incorrectly rejects
+# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'.
+# This bug is HP SR number 8606223364.
+{ echo "$as_me:$LINENO: checking size of int" >&5
+echo $ECHO_N "checking size of int... $ECHO_C" >&6; }
+if test "${ac_cv_sizeof_int+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if test "$cross_compiling" = yes; then
+  # Depending upon the size, compute the lo and hi bounds.
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+   typedef int ac__type_sizeof_;
+int
+main ()
+{
+static int test_array @<:@1 - 2 * !(((long int) (sizeof (ac__type_sizeof_))) >= 0)@:>@;
+test_array @<:@0@:>@ = 0
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_lo=0 ac_mid=0
+  while :; do
+    cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+   typedef int ac__type_sizeof_;
+int
+main ()
+{
+static int test_array @<:@1 - 2 * !(((long int) (sizeof (ac__type_sizeof_))) <= $ac_mid)@:>@;
+test_array @<:@0@:>@ = 0
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_hi=$ac_mid; break
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_lo=`expr $ac_mid + 1`
+                       if test $ac_lo -le $ac_mid; then
+                         ac_lo= ac_hi=
+                         break
+                       fi
+                       ac_mid=`expr 2 '*' $ac_mid + 1`
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+  done
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+   typedef int ac__type_sizeof_;
+int
+main ()
+{
+static int test_array @<:@1 - 2 * !(((long int) (sizeof (ac__type_sizeof_))) < 0)@:>@;
+test_array @<:@0@:>@ = 0
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_hi=-1 ac_mid=-1
+  while :; do
+    cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+   typedef int ac__type_sizeof_;
+int
+main ()
+{
+static int test_array @<:@1 - 2 * !(((long int) (sizeof (ac__type_sizeof_))) >= $ac_mid)@:>@;
+test_array @<:@0@:>@ = 0
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_lo=$ac_mid; break
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_hi=`expr '(' $ac_mid ')' - 1`
+                       if test $ac_mid -le $ac_hi; then
+                         ac_lo= ac_hi=
+                         break
+                       fi
+                       ac_mid=`expr 2 '*' $ac_mid`
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+  done
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_lo= ac_hi=
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+# Binary search between lo and hi bounds.
+while test "x$ac_lo" != "x$ac_hi"; do
+  ac_mid=`expr '(' $ac_hi - $ac_lo ')' / 2 + $ac_lo`
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+   typedef int ac__type_sizeof_;
+int
+main ()
+{
+static int test_array @<:@1 - 2 * !(((long int) (sizeof (ac__type_sizeof_))) <= $ac_mid)@:>@;
+test_array @<:@0@:>@ = 0
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_hi=$ac_mid
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_lo=`expr '(' $ac_mid ')' + 1`
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+done
+case $ac_lo in
+?*) ac_cv_sizeof_int=$ac_lo;;
+'') if test "$ac_cv_type_int" = yes; then
+     { { echo "$as_me:$LINENO: error: cannot compute sizeof (int)
+See \`config.log' for more details." >&5
+echo "$as_me: error: cannot compute sizeof (int)
+See \`config.log' for more details." >&2;}
+   { (exit 77); exit 77; }; }
+   else
+     ac_cv_sizeof_int=0
+   fi ;;
+esac
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+   typedef int ac__type_sizeof_;
+static long int longval () { return (long int) (sizeof (ac__type_sizeof_)); }
+static unsigned long int ulongval () { return (long int) (sizeof (ac__type_sizeof_)); }
+@%:@include <stdio.h>
+@%:@include <stdlib.h>
+int
+main ()
+{
+
+  FILE *f = fopen ("conftest.val", "w");
+  if (! f)
+    return 1;
+  if (((long int) (sizeof (ac__type_sizeof_))) < 0)
+    {
+      long int i = longval ();
+      if (i != ((long int) (sizeof (ac__type_sizeof_))))
+       return 1;
+      fprintf (f, "%ld\n", i);
+    }
+  else
+    {
+      unsigned long int i = ulongval ();
+      if (i != ((long int) (sizeof (ac__type_sizeof_))))
+       return 1;
+      fprintf (f, "%lu\n", i);
+    }
+  return ferror (f) || fclose (f) != 0;
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
+  { (case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_try") 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_sizeof_int=`cat conftest.val`
+else
+  echo "$as_me: program exited with status $ac_status" >&5
+echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+( exit $ac_status )
+if test "$ac_cv_type_int" = yes; then
+     { { echo "$as_me:$LINENO: error: cannot compute sizeof (int)
+See \`config.log' for more details." >&5
+echo "$as_me: error: cannot compute sizeof (int)
+See \`config.log' for more details." >&2;}
+   { (exit 77); exit 77; }; }
+   else
+     ac_cv_sizeof_int=0
+   fi
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f conftest.val
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_sizeof_int" >&5
+echo "${ECHO_T}$ac_cv_sizeof_int" >&6; }
+
+
+
+cat >>confdefs.h <<_ACEOF
+@%:@define SIZEOF_INT $ac_cv_sizeof_int
+_ACEOF
+
+
+{ echo "$as_me:$LINENO: checking for long" >&5
+echo $ECHO_N "checking for long... $ECHO_C" >&6; }
+if test "${ac_cv_type_long+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+typedef long ac__type_new_;
+int
+main ()
+{
+if ((ac__type_new_ *) 0)
+  return 0;
+if (sizeof (ac__type_new_))
+  return 0;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_cv_type_long=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_type_long=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_type_long" >&5
+echo "${ECHO_T}$ac_cv_type_long" >&6; }
+
+# The cast to long int works around a bug in the HP C Compiler
+# version HP92453-01 B.11.11.23709.GP, which incorrectly rejects
+# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'.
+# This bug is HP SR number 8606223364.
+{ echo "$as_me:$LINENO: checking size of long" >&5
+echo $ECHO_N "checking size of long... $ECHO_C" >&6; }
+if test "${ac_cv_sizeof_long+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if test "$cross_compiling" = yes; then
+  # Depending upon the size, compute the lo and hi bounds.
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+   typedef long ac__type_sizeof_;
+int
+main ()
+{
+static int test_array @<:@1 - 2 * !(((long int) (sizeof (ac__type_sizeof_))) >= 0)@:>@;
+test_array @<:@0@:>@ = 0
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_lo=0 ac_mid=0
+  while :; do
+    cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+   typedef long ac__type_sizeof_;
+int
+main ()
+{
+static int test_array @<:@1 - 2 * !(((long int) (sizeof (ac__type_sizeof_))) <= $ac_mid)@:>@;
+test_array @<:@0@:>@ = 0
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_hi=$ac_mid; break
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_lo=`expr $ac_mid + 1`
+                       if test $ac_lo -le $ac_mid; then
+                         ac_lo= ac_hi=
+                         break
+                       fi
+                       ac_mid=`expr 2 '*' $ac_mid + 1`
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+  done
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+   typedef long ac__type_sizeof_;
+int
+main ()
+{
+static int test_array @<:@1 - 2 * !(((long int) (sizeof (ac__type_sizeof_))) < 0)@:>@;
+test_array @<:@0@:>@ = 0
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_hi=-1 ac_mid=-1
+  while :; do
+    cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+   typedef long ac__type_sizeof_;
+int
+main ()
+{
+static int test_array @<:@1 - 2 * !(((long int) (sizeof (ac__type_sizeof_))) >= $ac_mid)@:>@;
+test_array @<:@0@:>@ = 0
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_lo=$ac_mid; break
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_hi=`expr '(' $ac_mid ')' - 1`
+                       if test $ac_mid -le $ac_hi; then
+                         ac_lo= ac_hi=
+                         break
+                       fi
+                       ac_mid=`expr 2 '*' $ac_mid`
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+  done
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_lo= ac_hi=
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+# Binary search between lo and hi bounds.
+while test "x$ac_lo" != "x$ac_hi"; do
+  ac_mid=`expr '(' $ac_hi - $ac_lo ')' / 2 + $ac_lo`
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+   typedef long ac__type_sizeof_;
+int
+main ()
+{
+static int test_array @<:@1 - 2 * !(((long int) (sizeof (ac__type_sizeof_))) <= $ac_mid)@:>@;
+test_array @<:@0@:>@ = 0
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_hi=$ac_mid
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_lo=`expr '(' $ac_mid ')' + 1`
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+done
+case $ac_lo in
+?*) ac_cv_sizeof_long=$ac_lo;;
+'') if test "$ac_cv_type_long" = yes; then
+     { { echo "$as_me:$LINENO: error: cannot compute sizeof (long)
+See \`config.log' for more details." >&5
+echo "$as_me: error: cannot compute sizeof (long)
+See \`config.log' for more details." >&2;}
+   { (exit 77); exit 77; }; }
+   else
+     ac_cv_sizeof_long=0
+   fi ;;
+esac
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+   typedef long ac__type_sizeof_;
+static long int longval () { return (long int) (sizeof (ac__type_sizeof_)); }
+static unsigned long int ulongval () { return (long int) (sizeof (ac__type_sizeof_)); }
+@%:@include <stdio.h>
+@%:@include <stdlib.h>
+int
+main ()
+{
+
+  FILE *f = fopen ("conftest.val", "w");
+  if (! f)
+    return 1;
+  if (((long int) (sizeof (ac__type_sizeof_))) < 0)
+    {
+      long int i = longval ();
+      if (i != ((long int) (sizeof (ac__type_sizeof_))))
+       return 1;
+      fprintf (f, "%ld\n", i);
+    }
+  else
+    {
+      unsigned long int i = ulongval ();
+      if (i != ((long int) (sizeof (ac__type_sizeof_))))
+       return 1;
+      fprintf (f, "%lu\n", i);
+    }
+  return ferror (f) || fclose (f) != 0;
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
+  { (case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_try") 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_sizeof_long=`cat conftest.val`
+else
+  echo "$as_me: program exited with status $ac_status" >&5
+echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+( exit $ac_status )
+if test "$ac_cv_type_long" = yes; then
+     { { echo "$as_me:$LINENO: error: cannot compute sizeof (long)
+See \`config.log' for more details." >&5
+echo "$as_me: error: cannot compute sizeof (long)
+See \`config.log' for more details." >&2;}
+   { (exit 77); exit 77; }; }
+   else
+     ac_cv_sizeof_long=0
+   fi
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f conftest.val
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_sizeof_long" >&5
+echo "${ECHO_T}$ac_cv_sizeof_long" >&6; }
+
+
+
+cat >>confdefs.h <<_ACEOF
+@%:@define SIZEOF_LONG $ac_cv_sizeof_long
+_ACEOF
+
+
+{ echo "$as_me:$LINENO: checking for void *" >&5
+echo $ECHO_N "checking for void *... $ECHO_C" >&6; }
+if test "${ac_cv_type_void_p+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+typedef void * ac__type_new_;
+int
+main ()
+{
+if ((ac__type_new_ *) 0)
+  return 0;
+if (sizeof (ac__type_new_))
+  return 0;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_cv_type_void_p=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_type_void_p=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_type_void_p" >&5
+echo "${ECHO_T}$ac_cv_type_void_p" >&6; }
+
+# The cast to long int works around a bug in the HP C Compiler
+# version HP92453-01 B.11.11.23709.GP, which incorrectly rejects
+# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'.
+# This bug is HP SR number 8606223364.
+{ echo "$as_me:$LINENO: checking size of void *" >&5
+echo $ECHO_N "checking size of void *... $ECHO_C" >&6; }
+if test "${ac_cv_sizeof_void_p+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if test "$cross_compiling" = yes; then
+  # Depending upon the size, compute the lo and hi bounds.
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+   typedef void * ac__type_sizeof_;
+int
+main ()
+{
+static int test_array @<:@1 - 2 * !(((long int) (sizeof (ac__type_sizeof_))) >= 0)@:>@;
+test_array @<:@0@:>@ = 0
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_lo=0 ac_mid=0
+  while :; do
+    cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+   typedef void * ac__type_sizeof_;
+int
+main ()
+{
+static int test_array @<:@1 - 2 * !(((long int) (sizeof (ac__type_sizeof_))) <= $ac_mid)@:>@;
+test_array @<:@0@:>@ = 0
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_hi=$ac_mid; break
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_lo=`expr $ac_mid + 1`
+                       if test $ac_lo -le $ac_mid; then
+                         ac_lo= ac_hi=
+                         break
+                       fi
+                       ac_mid=`expr 2 '*' $ac_mid + 1`
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+  done
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+   typedef void * ac__type_sizeof_;
+int
+main ()
+{
+static int test_array @<:@1 - 2 * !(((long int) (sizeof (ac__type_sizeof_))) < 0)@:>@;
+test_array @<:@0@:>@ = 0
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_hi=-1 ac_mid=-1
+  while :; do
+    cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+   typedef void * ac__type_sizeof_;
+int
+main ()
+{
+static int test_array @<:@1 - 2 * !(((long int) (sizeof (ac__type_sizeof_))) >= $ac_mid)@:>@;
+test_array @<:@0@:>@ = 0
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_lo=$ac_mid; break
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_hi=`expr '(' $ac_mid ')' - 1`
+                       if test $ac_mid -le $ac_hi; then
+                         ac_lo= ac_hi=
+                         break
+                       fi
+                       ac_mid=`expr 2 '*' $ac_mid`
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+  done
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_lo= ac_hi=
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+# Binary search between lo and hi bounds.
+while test "x$ac_lo" != "x$ac_hi"; do
+  ac_mid=`expr '(' $ac_hi - $ac_lo ')' / 2 + $ac_lo`
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+   typedef void * ac__type_sizeof_;
+int
+main ()
+{
+static int test_array @<:@1 - 2 * !(((long int) (sizeof (ac__type_sizeof_))) <= $ac_mid)@:>@;
+test_array @<:@0@:>@ = 0
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_hi=$ac_mid
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_lo=`expr '(' $ac_mid ')' + 1`
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+done
+case $ac_lo in
+?*) ac_cv_sizeof_void_p=$ac_lo;;
+'') if test "$ac_cv_type_void_p" = yes; then
+     { { echo "$as_me:$LINENO: error: cannot compute sizeof (void *)
+See \`config.log' for more details." >&5
+echo "$as_me: error: cannot compute sizeof (void *)
+See \`config.log' for more details." >&2;}
+   { (exit 77); exit 77; }; }
+   else
+     ac_cv_sizeof_void_p=0
+   fi ;;
+esac
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+   typedef void * ac__type_sizeof_;
+static long int longval () { return (long int) (sizeof (ac__type_sizeof_)); }
+static unsigned long int ulongval () { return (long int) (sizeof (ac__type_sizeof_)); }
+@%:@include <stdio.h>
+@%:@include <stdlib.h>
+int
+main ()
+{
+
+  FILE *f = fopen ("conftest.val", "w");
+  if (! f)
+    return 1;
+  if (((long int) (sizeof (ac__type_sizeof_))) < 0)
+    {
+      long int i = longval ();
+      if (i != ((long int) (sizeof (ac__type_sizeof_))))
+       return 1;
+      fprintf (f, "%ld\n", i);
+    }
+  else
+    {
+      unsigned long int i = ulongval ();
+      if (i != ((long int) (sizeof (ac__type_sizeof_))))
+       return 1;
+      fprintf (f, "%lu\n", i);
+    }
+  return ferror (f) || fclose (f) != 0;
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
+  { (case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_try") 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_sizeof_void_p=`cat conftest.val`
+else
+  echo "$as_me: program exited with status $ac_status" >&5
+echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+( exit $ac_status )
+if test "$ac_cv_type_void_p" = yes; then
+     { { echo "$as_me:$LINENO: error: cannot compute sizeof (void *)
+See \`config.log' for more details." >&5
+echo "$as_me: error: cannot compute sizeof (void *)
+See \`config.log' for more details." >&2;}
+   { (exit 77); exit 77; }; }
+   else
+     ac_cv_sizeof_void_p=0
+   fi
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f conftest.val
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_sizeof_void_p" >&5
+echo "${ECHO_T}$ac_cv_sizeof_void_p" >&6; }
+
+
+
+cat >>confdefs.h <<_ACEOF
+@%:@define SIZEOF_VOID_P $ac_cv_sizeof_void_p
+_ACEOF
+
+
+{ echo "$as_me:$LINENO: checking for int64_t" >&5
+echo $ECHO_N "checking for int64_t... $ECHO_C" >&6; }
+if test "${ac_cv_type_int64_t+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+typedef int64_t ac__type_new_;
+int
+main ()
+{
+if ((ac__type_new_ *) 0)
+  return 0;
+if (sizeof (ac__type_new_))
+  return 0;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_cv_type_int64_t=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_type_int64_t=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_type_int64_t" >&5
+echo "${ECHO_T}$ac_cv_type_int64_t" >&6; }
+
+# The cast to long int works around a bug in the HP C Compiler
+# version HP92453-01 B.11.11.23709.GP, which incorrectly rejects
+# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'.
+# This bug is HP SR number 8606223364.
+{ echo "$as_me:$LINENO: checking size of int64_t" >&5
+echo $ECHO_N "checking size of int64_t... $ECHO_C" >&6; }
+if test "${ac_cv_sizeof_int64_t+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if test "$cross_compiling" = yes; then
+  # Depending upon the size, compute the lo and hi bounds.
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+   typedef int64_t ac__type_sizeof_;
+int
+main ()
+{
+static int test_array @<:@1 - 2 * !(((long int) (sizeof (ac__type_sizeof_))) >= 0)@:>@;
+test_array @<:@0@:>@ = 0
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_lo=0 ac_mid=0
+  while :; do
+    cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+   typedef int64_t ac__type_sizeof_;
+int
+main ()
+{
+static int test_array @<:@1 - 2 * !(((long int) (sizeof (ac__type_sizeof_))) <= $ac_mid)@:>@;
+test_array @<:@0@:>@ = 0
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_hi=$ac_mid; break
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_lo=`expr $ac_mid + 1`
+                       if test $ac_lo -le $ac_mid; then
+                         ac_lo= ac_hi=
+                         break
+                       fi
+                       ac_mid=`expr 2 '*' $ac_mid + 1`
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+  done
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+   typedef int64_t ac__type_sizeof_;
+int
+main ()
+{
+static int test_array @<:@1 - 2 * !(((long int) (sizeof (ac__type_sizeof_))) < 0)@:>@;
+test_array @<:@0@:>@ = 0
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_hi=-1 ac_mid=-1
+  while :; do
+    cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+   typedef int64_t ac__type_sizeof_;
+int
+main ()
+{
+static int test_array @<:@1 - 2 * !(((long int) (sizeof (ac__type_sizeof_))) >= $ac_mid)@:>@;
+test_array @<:@0@:>@ = 0
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_lo=$ac_mid; break
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_hi=`expr '(' $ac_mid ')' - 1`
+                       if test $ac_mid -le $ac_hi; then
+                         ac_lo= ac_hi=
+                         break
+                       fi
+                       ac_mid=`expr 2 '*' $ac_mid`
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+  done
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_lo= ac_hi=
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+# Binary search between lo and hi bounds.
+while test "x$ac_lo" != "x$ac_hi"; do
+  ac_mid=`expr '(' $ac_hi - $ac_lo ')' / 2 + $ac_lo`
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+   typedef int64_t ac__type_sizeof_;
+int
+main ()
+{
+static int test_array @<:@1 - 2 * !(((long int) (sizeof (ac__type_sizeof_))) <= $ac_mid)@:>@;
+test_array @<:@0@:>@ = 0
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_hi=$ac_mid
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_lo=`expr '(' $ac_mid ')' + 1`
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+done
+case $ac_lo in
+?*) ac_cv_sizeof_int64_t=$ac_lo;;
+'') if test "$ac_cv_type_int64_t" = yes; then
+     { { echo "$as_me:$LINENO: error: cannot compute sizeof (int64_t)
+See \`config.log' for more details." >&5
+echo "$as_me: error: cannot compute sizeof (int64_t)
+See \`config.log' for more details." >&2;}
+   { (exit 77); exit 77; }; }
+   else
+     ac_cv_sizeof_int64_t=0
+   fi ;;
+esac
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+   typedef int64_t ac__type_sizeof_;
+static long int longval () { return (long int) (sizeof (ac__type_sizeof_)); }
+static unsigned long int ulongval () { return (long int) (sizeof (ac__type_sizeof_)); }
+@%:@include <stdio.h>
+@%:@include <stdlib.h>
+int
+main ()
+{
+
+  FILE *f = fopen ("conftest.val", "w");
+  if (! f)
+    return 1;
+  if (((long int) (sizeof (ac__type_sizeof_))) < 0)
+    {
+      long int i = longval ();
+      if (i != ((long int) (sizeof (ac__type_sizeof_))))
+       return 1;
+      fprintf (f, "%ld\n", i);
+    }
+  else
+    {
+      unsigned long int i = ulongval ();
+      if (i != ((long int) (sizeof (ac__type_sizeof_))))
+       return 1;
+      fprintf (f, "%lu\n", i);
+    }
+  return ferror (f) || fclose (f) != 0;
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
+  { (case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_try") 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_sizeof_int64_t=`cat conftest.val`
+else
+  echo "$as_me: program exited with status $ac_status" >&5
+echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+( exit $ac_status )
+if test "$ac_cv_type_int64_t" = yes; then
+     { { echo "$as_me:$LINENO: error: cannot compute sizeof (int64_t)
+See \`config.log' for more details." >&5
+echo "$as_me: error: cannot compute sizeof (int64_t)
+See \`config.log' for more details." >&2;}
+   { (exit 77); exit 77; }; }
+   else
+     ac_cv_sizeof_int64_t=0
+   fi
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f conftest.val
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_sizeof_int64_t" >&5
+echo "${ECHO_T}$ac_cv_sizeof_int64_t" >&6; }
+
+
+
+cat >>confdefs.h <<_ACEOF
+@%:@define SIZEOF_INT64_T $ac_cv_sizeof_int64_t
+_ACEOF
+
+
+{ echo "$as_me:$LINENO: checking for long long" >&5
+echo $ECHO_N "checking for long long... $ECHO_C" >&6; }
+if test "${ac_cv_type_long_long+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+typedef long long ac__type_new_;
+int
+main ()
+{
+if ((ac__type_new_ *) 0)
+  return 0;
+if (sizeof (ac__type_new_))
+  return 0;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_cv_type_long_long=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_type_long_long=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_type_long_long" >&5
+echo "${ECHO_T}$ac_cv_type_long_long" >&6; }
+
+# The cast to long int works around a bug in the HP C Compiler
+# version HP92453-01 B.11.11.23709.GP, which incorrectly rejects
+# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'.
+# This bug is HP SR number 8606223364.
+{ echo "$as_me:$LINENO: checking size of long long" >&5
+echo $ECHO_N "checking size of long long... $ECHO_C" >&6; }
+if test "${ac_cv_sizeof_long_long+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if test "$cross_compiling" = yes; then
+  # Depending upon the size, compute the lo and hi bounds.
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+   typedef long long ac__type_sizeof_;
+int
+main ()
+{
+static int test_array @<:@1 - 2 * !(((long int) (sizeof (ac__type_sizeof_))) >= 0)@:>@;
+test_array @<:@0@:>@ = 0
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_lo=0 ac_mid=0
+  while :; do
+    cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+   typedef long long ac__type_sizeof_;
+int
+main ()
+{
+static int test_array @<:@1 - 2 * !(((long int) (sizeof (ac__type_sizeof_))) <= $ac_mid)@:>@;
+test_array @<:@0@:>@ = 0
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_hi=$ac_mid; break
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_lo=`expr $ac_mid + 1`
+                       if test $ac_lo -le $ac_mid; then
+                         ac_lo= ac_hi=
+                         break
+                       fi
+                       ac_mid=`expr 2 '*' $ac_mid + 1`
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+  done
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+   typedef long long ac__type_sizeof_;
+int
+main ()
+{
+static int test_array @<:@1 - 2 * !(((long int) (sizeof (ac__type_sizeof_))) < 0)@:>@;
+test_array @<:@0@:>@ = 0
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_hi=-1 ac_mid=-1
+  while :; do
+    cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+   typedef long long ac__type_sizeof_;
+int
+main ()
+{
+static int test_array @<:@1 - 2 * !(((long int) (sizeof (ac__type_sizeof_))) >= $ac_mid)@:>@;
+test_array @<:@0@:>@ = 0
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_lo=$ac_mid; break
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_hi=`expr '(' $ac_mid ')' - 1`
+                       if test $ac_mid -le $ac_hi; then
+                         ac_lo= ac_hi=
+                         break
+                       fi
+                       ac_mid=`expr 2 '*' $ac_mid`
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+  done
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_lo= ac_hi=
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+# Binary search between lo and hi bounds.
+while test "x$ac_lo" != "x$ac_hi"; do
+  ac_mid=`expr '(' $ac_hi - $ac_lo ')' / 2 + $ac_lo`
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+   typedef long long ac__type_sizeof_;
+int
+main ()
+{
+static int test_array @<:@1 - 2 * !(((long int) (sizeof (ac__type_sizeof_))) <= $ac_mid)@:>@;
+test_array @<:@0@:>@ = 0
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_hi=$ac_mid
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_lo=`expr '(' $ac_mid ')' + 1`
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+done
+case $ac_lo in
+?*) ac_cv_sizeof_long_long=$ac_lo;;
+'') if test "$ac_cv_type_long_long" = yes; then
+     { { echo "$as_me:$LINENO: error: cannot compute sizeof (long long)
+See \`config.log' for more details." >&5
+echo "$as_me: error: cannot compute sizeof (long long)
+See \`config.log' for more details." >&2;}
+   { (exit 77); exit 77; }; }
+   else
+     ac_cv_sizeof_long_long=0
+   fi ;;
+esac
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+   typedef long long ac__type_sizeof_;
+static long int longval () { return (long int) (sizeof (ac__type_sizeof_)); }
+static unsigned long int ulongval () { return (long int) (sizeof (ac__type_sizeof_)); }
+@%:@include <stdio.h>
+@%:@include <stdlib.h>
+int
+main ()
+{
+
+  FILE *f = fopen ("conftest.val", "w");
+  if (! f)
+    return 1;
+  if (((long int) (sizeof (ac__type_sizeof_))) < 0)
+    {
+      long int i = longval ();
+      if (i != ((long int) (sizeof (ac__type_sizeof_))))
+       return 1;
+      fprintf (f, "%ld\n", i);
+    }
+  else
+    {
+      unsigned long int i = ulongval ();
+      if (i != ((long int) (sizeof (ac__type_sizeof_))))
+       return 1;
+      fprintf (f, "%lu\n", i);
+    }
+  return ferror (f) || fclose (f) != 0;
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
+  { (case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_try") 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_sizeof_long_long=`cat conftest.val`
+else
+  echo "$as_me: program exited with status $ac_status" >&5
+echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+( exit $ac_status )
+if test "$ac_cv_type_long_long" = yes; then
+     { { echo "$as_me:$LINENO: error: cannot compute sizeof (long long)
+See \`config.log' for more details." >&5
+echo "$as_me: error: cannot compute sizeof (long long)
+See \`config.log' for more details." >&2;}
+   { (exit 77); exit 77; }; }
+   else
+     ac_cv_sizeof_long_long=0
+   fi
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f conftest.val
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_sizeof_long_long" >&5
+echo "${ECHO_T}$ac_cv_sizeof_long_long" >&6; }
+
+
+
+cat >>confdefs.h <<_ACEOF
+@%:@define SIZEOF_LONG_LONG $ac_cv_sizeof_long_long
+_ACEOF
+
+
+if test "$ac_cv_sizeof_int" = 2 ; then
+  { echo "$as_me:$LINENO: checking for int16_t" >&5
+echo $ECHO_N "checking for int16_t... $ECHO_C" >&6; }
+if test "${ac_cv_type_int16_t+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+typedef int16_t ac__type_new_;
+int
+main ()
+{
+if ((ac__type_new_ *) 0)
+  return 0;
+if (sizeof (ac__type_new_))
+  return 0;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_cv_type_int16_t=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_type_int16_t=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_type_int16_t" >&5
+echo "${ECHO_T}$ac_cv_type_int16_t" >&6; }
+if test $ac_cv_type_int16_t = yes; then
+  :
+else
+  
+cat >>confdefs.h <<_ACEOF
+@%:@define int16_t int
+_ACEOF
+
+fi
+
+  { echo "$as_me:$LINENO: checking for uint16_t" >&5
+echo $ECHO_N "checking for uint16_t... $ECHO_C" >&6; }
+if test "${ac_cv_type_uint16_t+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+typedef uint16_t ac__type_new_;
+int
+main ()
+{
+if ((ac__type_new_ *) 0)
+  return 0;
+if (sizeof (ac__type_new_))
+  return 0;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_cv_type_uint16_t=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_type_uint16_t=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_type_uint16_t" >&5
+echo "${ECHO_T}$ac_cv_type_uint16_t" >&6; }
+if test $ac_cv_type_uint16_t = yes; then
+  :
+else
+  
+cat >>confdefs.h <<_ACEOF
+@%:@define uint16_t unsigned int
+_ACEOF
+
+fi
+
+elif test "$ac_cv_sizeof_short" = 2 ; then
+  { echo "$as_me:$LINENO: checking for int16_t" >&5
+echo $ECHO_N "checking for int16_t... $ECHO_C" >&6; }
+if test "${ac_cv_type_int16_t+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+typedef int16_t ac__type_new_;
+int
+main ()
+{
+if ((ac__type_new_ *) 0)
+  return 0;
+if (sizeof (ac__type_new_))
+  return 0;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_cv_type_int16_t=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_type_int16_t=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_type_int16_t" >&5
+echo "${ECHO_T}$ac_cv_type_int16_t" >&6; }
+if test $ac_cv_type_int16_t = yes; then
+  :
+else
+  
+cat >>confdefs.h <<_ACEOF
+@%:@define int16_t short
+_ACEOF
+
+fi
+
+  { echo "$as_me:$LINENO: checking for uint16_t" >&5
+echo $ECHO_N "checking for uint16_t... $ECHO_C" >&6; }
+if test "${ac_cv_type_uint16_t+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+typedef uint16_t ac__type_new_;
+int
+main ()
+{
+if ((ac__type_new_ *) 0)
+  return 0;
+if (sizeof (ac__type_new_))
+  return 0;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_cv_type_uint16_t=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_type_uint16_t=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_type_uint16_t" >&5
+echo "${ECHO_T}$ac_cv_type_uint16_t" >&6; }
+if test $ac_cv_type_uint16_t = yes; then
+  :
+else
+  
+cat >>confdefs.h <<_ACEOF
+@%:@define uint16_t unsigned short
+_ACEOF
+
+fi
+
+else
+  { { echo "$as_me:$LINENO: error: Cannot find a type with size of 16 bits" >&5
+echo "$as_me: error: Cannot find a type with size of 16 bits" >&2;}
+   { (exit 1); exit 1; }; }
+fi
+if test "$ac_cv_sizeof_int" = 4 ; then
+  { echo "$as_me:$LINENO: checking for int32_t" >&5
+echo $ECHO_N "checking for int32_t... $ECHO_C" >&6; }
+if test "${ac_cv_type_int32_t+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+typedef int32_t ac__type_new_;
+int
+main ()
+{
+if ((ac__type_new_ *) 0)
+  return 0;
+if (sizeof (ac__type_new_))
+  return 0;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_cv_type_int32_t=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_type_int32_t=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_type_int32_t" >&5
+echo "${ECHO_T}$ac_cv_type_int32_t" >&6; }
+if test $ac_cv_type_int32_t = yes; then
+  :
+else
+  
+cat >>confdefs.h <<_ACEOF
+@%:@define int32_t int
+_ACEOF
+
+fi
+
+  { echo "$as_me:$LINENO: checking for uint32_t" >&5
+echo $ECHO_N "checking for uint32_t... $ECHO_C" >&6; }
+if test "${ac_cv_type_uint32_t+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+typedef uint32_t ac__type_new_;
+int
+main ()
+{
+if ((ac__type_new_ *) 0)
+  return 0;
+if (sizeof (ac__type_new_))
+  return 0;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_cv_type_uint32_t=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_type_uint32_t=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_type_uint32_t" >&5
+echo "${ECHO_T}$ac_cv_type_uint32_t" >&6; }
+if test $ac_cv_type_uint32_t = yes; then
+  :
+else
+  
+cat >>confdefs.h <<_ACEOF
+@%:@define uint32_t unsigned int
+_ACEOF
+
+fi
+
+elif test "$ac_cv_sizeof_short" = 4 ; then
+  { echo "$as_me:$LINENO: checking for int32_t" >&5
+echo $ECHO_N "checking for int32_t... $ECHO_C" >&6; }
+if test "${ac_cv_type_int32_t+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+typedef int32_t ac__type_new_;
+int
+main ()
+{
+if ((ac__type_new_ *) 0)
+  return 0;
+if (sizeof (ac__type_new_))
+  return 0;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_cv_type_int32_t=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_type_int32_t=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_type_int32_t" >&5
+echo "${ECHO_T}$ac_cv_type_int32_t" >&6; }
+if test $ac_cv_type_int32_t = yes; then
+  :
+else
+  
+cat >>confdefs.h <<_ACEOF
+@%:@define int32_t short
+_ACEOF
+
+fi
+
+  { echo "$as_me:$LINENO: checking for uint32_t" >&5
+echo $ECHO_N "checking for uint32_t... $ECHO_C" >&6; }
+if test "${ac_cv_type_uint32_t+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+typedef uint32_t ac__type_new_;
+int
+main ()
+{
+if ((ac__type_new_ *) 0)
+  return 0;
+if (sizeof (ac__type_new_))
+  return 0;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_cv_type_uint32_t=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_type_uint32_t=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_type_uint32_t" >&5
+echo "${ECHO_T}$ac_cv_type_uint32_t" >&6; }
+if test $ac_cv_type_uint32_t = yes; then
+  :
+else
+  
+cat >>confdefs.h <<_ACEOF
+@%:@define uint32_t unsigned short
+_ACEOF
+
+fi
+
+elif test "$ac_cv_sizeof_long" = 4 ; then
+  { echo "$as_me:$LINENO: checking for int32_t" >&5
+echo $ECHO_N "checking for int32_t... $ECHO_C" >&6; }
+if test "${ac_cv_type_int32_t+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+typedef int32_t ac__type_new_;
+int
+main ()
+{
+if ((ac__type_new_ *) 0)
+  return 0;
+if (sizeof (ac__type_new_))
+  return 0;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_cv_type_int32_t=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_type_int32_t=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_type_int32_t" >&5
+echo "${ECHO_T}$ac_cv_type_int32_t" >&6; }
+if test $ac_cv_type_int32_t = yes; then
+  :
+else
+  
+cat >>confdefs.h <<_ACEOF
+@%:@define int32_t long
+_ACEOF
+
+fi
+
+  { echo "$as_me:$LINENO: checking for uint32_t" >&5
+echo $ECHO_N "checking for uint32_t... $ECHO_C" >&6; }
+if test "${ac_cv_type_uint32_t+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+typedef uint32_t ac__type_new_;
+int
+main ()
+{
+if ((ac__type_new_ *) 0)
+  return 0;
+if (sizeof (ac__type_new_))
+  return 0;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_cv_type_uint32_t=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_type_uint32_t=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_type_uint32_t" >&5
+echo "${ECHO_T}$ac_cv_type_uint32_t" >&6; }
+if test $ac_cv_type_uint32_t = yes; then
+  :
+else
+  
+cat >>confdefs.h <<_ACEOF
+@%:@define uint32_t unsigned long
+_ACEOF
+
+fi
+
+else
+  { { echo "$as_me:$LINENO: error: Cannot find a type with size of 32 bits" >&5
+echo "$as_me: error: Cannot find a type with size of 32 bits" >&2;}
+   { (exit 1); exit 1; }; }
+fi
+if test "$ac_cv_sizeof_int64_t" = 8 ; then
+  { echo "$as_me:$LINENO: checking for int64_t" >&5
+echo $ECHO_N "checking for int64_t... $ECHO_C" >&6; }
+if test "${ac_cv_type_int64_t+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+typedef int64_t ac__type_new_;
+int
+main ()
+{
+if ((ac__type_new_ *) 0)
+  return 0;
+if (sizeof (ac__type_new_))
+  return 0;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_cv_type_int64_t=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_type_int64_t=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_type_int64_t" >&5
+echo "${ECHO_T}$ac_cv_type_int64_t" >&6; }
+
+  { echo "$as_me:$LINENO: checking for uint64_t" >&5
+echo $ECHO_N "checking for uint64_t... $ECHO_C" >&6; }
+if test "${ac_cv_type_uint64_t+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+typedef uint64_t ac__type_new_;
+int
+main ()
+{
+if ((ac__type_new_ *) 0)
+  return 0;
+if (sizeof (ac__type_new_))
+  return 0;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_cv_type_uint64_t=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_type_uint64_t=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_type_uint64_t" >&5
+echo "${ECHO_T}$ac_cv_type_uint64_t" >&6; }
+
+elif test "$ac_cv_sizeof_long_long" = 8 ; then
+  { echo "$as_me:$LINENO: checking for int64_t" >&5
+echo $ECHO_N "checking for int64_t... $ECHO_C" >&6; }
+if test "${ac_cv_type_int64_t+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+typedef int64_t ac__type_new_;
+int
+main ()
+{
+if ((ac__type_new_ *) 0)
+  return 0;
+if (sizeof (ac__type_new_))
+  return 0;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_cv_type_int64_t=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_type_int64_t=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_type_int64_t" >&5
+echo "${ECHO_T}$ac_cv_type_int64_t" >&6; }
+if test $ac_cv_type_int64_t = yes; then
+  :
+else
+  
+cat >>confdefs.h <<_ACEOF
+@%:@define int64_t long long
+_ACEOF
+
+fi
+
+  { echo "$as_me:$LINENO: checking for uint64_t" >&5
+echo $ECHO_N "checking for uint64_t... $ECHO_C" >&6; }
+if test "${ac_cv_type_uint64_t+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+typedef uint64_t ac__type_new_;
+int
+main ()
+{
+if ((ac__type_new_ *) 0)
+  return 0;
+if (sizeof (ac__type_new_))
+  return 0;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_cv_type_uint64_t=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_type_uint64_t=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_type_uint64_t" >&5
+echo "${ECHO_T}$ac_cv_type_uint64_t" >&6; }
+if test $ac_cv_type_uint64_t = yes; then
+  :
+else
+  
+cat >>confdefs.h <<_ACEOF
+@%:@define uint64_t unsigned long long
+_ACEOF
+
+fi
+
+else
+  { { echo "$as_me:$LINENO: error: Cannot find a type with size of 64 bits" >&5
+echo "$as_me: error: Cannot find a type with size of 64 bits" >&2;}
+   { (exit 1); exit 1; }; }
+fi
+{ echo "$as_me:$LINENO: checking for struct sockaddr_in6" >&5
+echo $ECHO_N "checking for struct sockaddr_in6... $ECHO_C" >&6; }
+if test "${ac_cv_type_struct_sockaddr_in6+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <sys/types.h>
+#include <netinet/in.h>
+
+typedef struct sockaddr_in6 ac__type_new_;
+int
+main ()
+{
+if ((ac__type_new_ *) 0)
+  return 0;
+if (sizeof (ac__type_new_))
+  return 0;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_cv_type_struct_sockaddr_in6=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_type_struct_sockaddr_in6=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_type_struct_sockaddr_in6" >&5
+echo "${ECHO_T}$ac_cv_type_struct_sockaddr_in6" >&6; }
+if test $ac_cv_type_struct_sockaddr_in6 = yes; then
+  unet_have_sockaddr_in6="yes"
+else
+  unet_have_sockaddr_in6="no"
+fi
+
+
+{ echo "$as_me:$LINENO: checking for socklen_t" >&5
+echo $ECHO_N "checking for socklen_t... $ECHO_C" >&6; }
+if test "${ac_cv_type_socklen_t+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <sys/types.h>
+#include<sys/socket.h>
+
+typedef socklen_t ac__type_new_;
+int
+main ()
+{
+if ((ac__type_new_ *) 0)
+  return 0;
+if (sizeof (ac__type_new_))
+  return 0;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_cv_type_socklen_t=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_type_socklen_t=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_type_socklen_t" >&5
+echo "${ECHO_T}$ac_cv_type_socklen_t" >&6; }
+if test $ac_cv_type_socklen_t = yes; then
+  :
+else
+  
+  { echo "$as_me:$LINENO: checking for socklen_t equivalent" >&5
+echo $ECHO_N "checking for socklen_t equivalent... $ECHO_C" >&6; }
+  if test "${curl_cv_socklen_t_equiv+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  
+    curl_cv_socklen_t_equiv=
+    for arg2 in "struct sockaddr" void ; do
+      for t in int size_t unsigned long "unsigned long" ; do
+        cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <sys/types.h>
+#include <sys/socket.h>
+int getpeername (int $arg2 *, $t *);
+int
+main ()
+{
+$t len;
+  getpeername(0, 0, &len);
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  curl_cv_socklen_t_equiv="$t"
+  break
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+      done
+    done
+  
+fi
+
+  { echo "$as_me:$LINENO: result: $curl_cv_socklen_t_equiv" >&5
+echo "${ECHO_T}$curl_cv_socklen_t_equiv" >&6; }
+  
+cat >>confdefs.h <<_ACEOF
+@%:@define socklen_t $curl_cv_socklen_t_equiv
+_ACEOF
+
+fi
+
+
+
+
+
+
+for ac_func in kqueue setrlimit getrusage times
+do
+as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
+{ echo "$as_me:$LINENO: checking for $ac_func" >&5
+echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6; }
+if { as_var=$as_ac_var; eval "test \"\${$as_var+set}\" = set"; }; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+/* Define $ac_func to an innocuous variant, in case <limits.h> declares $ac_func.
+   For example, HP-UX 11i <limits.h> declares gettimeofday.  */
+#define $ac_func innocuous_$ac_func
+
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char $ac_func (); below.
+    Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+    <limits.h> exists even on freestanding compilers.  */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef $ac_func
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char $ac_func ();
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined __stub_$ac_func || defined __stub___$ac_func
+choke me
+#endif
+
+int
+main ()
+{
+return $ac_func ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext &&
+       $as_test_x conftest$ac_exeext; then
+  eval "$as_ac_var=yes"
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       eval "$as_ac_var=no"
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+fi
+ac_res=`eval echo '${'$as_ac_var'}'`
+              { echo "$as_me:$LINENO: result: $ac_res" >&5
+echo "${ECHO_T}$ac_res" >&6; }
+if test `eval echo '${'$as_ac_var'}'` = yes; then
+  cat >>confdefs.h <<_ACEOF
+@%:@define `echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+fi
+done
+
+
+{ echo "$as_me:$LINENO: checking for donuts" >&5
+echo $ECHO_N "checking for donuts... $ECHO_C" >&6; }
+{ echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6; }
+
+for ac_prog in gawk mawk nawk awk
+do
+  # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
+if test "${ac_cv_prog_AWK+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if test -n "$AWK"; then
+  ac_cv_prog_AWK="$AWK" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_AWK="$ac_prog"
+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+IFS=$as_save_IFS
+
+fi
+fi
+AWK=$ac_cv_prog_AWK
+if test -n "$AWK"; then
+  { echo "$as_me:$LINENO: result: $AWK" >&5
+echo "${ECHO_T}$AWK" >&6; }
+else
+  { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+fi
+
+
+  test -n "$AWK" && break
+done
+
+{ echo "$as_me:$LINENO: checking whether ${MAKE-make} sets \$(MAKE)" >&5
+echo $ECHO_N "checking whether ${MAKE-make} sets \$(MAKE)... $ECHO_C" >&6; }
+set x ${MAKE-make}; ac_make=`echo "$2" | sed 's/+/p/g; s/[^a-zA-Z0-9_]/_/g'`
+if { as_var=ac_cv_prog_make_${ac_make}_set; eval "test \"\${$as_var+set}\" = set"; }; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.make <<\_ACEOF
+SHELL = /bin/sh
+all:
+       @echo '@@@%%%=$(MAKE)=@@@%%%'
+_ACEOF
+# GNU make sometimes prints "make[1]: Entering...", which would confuse us.
+case `${MAKE-make} -f conftest.make 2>/dev/null` in
+  *@@@%%%=?*=@@@%%%*)
+    eval ac_cv_prog_make_${ac_make}_set=yes;;
+  *)
+    eval ac_cv_prog_make_${ac_make}_set=no;;
+esac
+rm -f conftest.make
+fi
+if eval test \$ac_cv_prog_make_${ac_make}_set = yes; then
+  { echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6; }
+  SET_MAKE=
+else
+  { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+  SET_MAKE="MAKE=${MAKE-make}"
+fi
+
+# Find a good install program.  We prefer a C program (faster),
+# so one script is as good as another.  But avoid the broken or
+# incompatible versions:
+# SysV /etc/install, /usr/sbin/install
+# SunOS /usr/etc/install
+# IRIX /sbin/install
+# AIX /bin/install
+# AmigaOS /C/install, which installs bootblocks on floppy discs
+# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag
+# AFS /usr/afsws/bin/install, which mishandles nonexistent args
+# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff"
+# OS/2's system install, which has a completely different semantic
+# ./install, which can be erroneously created by make from ./install.sh.
+{ echo "$as_me:$LINENO: checking for a BSD-compatible install" >&5
+echo $ECHO_N "checking for a BSD-compatible install... $ECHO_C" >&6; }
+if test -z "$INSTALL"; then
+if test "${ac_cv_path_install+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  # Account for people who put trailing slashes in PATH elements.
+case $as_dir/ in
+  ./ | .// | /cC/* | \
+  /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \
+  ?:\\/os2\\/install\\/* | ?:\\/OS2\\/INSTALL\\/* | \
+  /usr/ucb/* ) ;;
+  *)
+    # OSF1 and SCO ODT 3.0 have their own names for install.
+    # Don't use installbsd from OSF since it installs stuff as root
+    # by default.
+    for ac_prog in ginstall scoinst install; do
+      for ac_exec_ext in '' $ac_executable_extensions; do
+       if { test -f "$as_dir/$ac_prog$ac_exec_ext" && $as_test_x "$as_dir/$ac_prog$ac_exec_ext"; }; then
+         if test $ac_prog = install &&
+           grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then
+           # AIX install.  It has an incompatible calling convention.
+           :
+         elif test $ac_prog = install &&
+           grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then
+           # program-specific install script used by HP pwplus--don't use.
+           :
+         else
+           ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c"
+           break 3
+         fi
+       fi
+      done
+    done
+    ;;
+esac
+done
+IFS=$as_save_IFS
+
+
+fi
+  if test "${ac_cv_path_install+set}" = set; then
+    INSTALL=$ac_cv_path_install
+  else
+    # As a last resort, use the slow shell script.  Don't cache a
+    # value for INSTALL within a source directory, because that will
+    # break other packages using the cache if that directory is
+    # removed, or if the value is a relative name.
+    INSTALL=$ac_install_sh
+  fi
+fi
+{ echo "$as_me:$LINENO: result: $INSTALL" >&5
+echo "${ECHO_T}$INSTALL" >&6; }
+
+# Use test -z because SunOS4 sh mishandles braces in ${var-val}.
+# It thinks the first close brace ends the variable substitution.
+test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}'
+
+test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}'
+
+test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644'
+
+{ echo "$as_me:$LINENO: checking whether ln -s works" >&5
+echo $ECHO_N "checking whether ln -s works... $ECHO_C" >&6; }
+LN_S=$as_ln_s
+if test "$LN_S" = "ln -s"; then
+  { echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6; }
+else
+  { echo "$as_me:$LINENO: result: no, using $LN_S" >&5
+echo "${ECHO_T}no, using $LN_S" >&6; }
+fi
+
+for ac_prog in rm
+do
+  # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
+if test "${ac_cv_path_RMPROG+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  case $RMPROG in
+  [\\/]* | ?:[\\/]*)
+  ac_cv_path_RMPROG="$RMPROG" # Let the user override the test with a path.
+  ;;
+  *)
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_path_RMPROG="$as_dir/$ac_word$ac_exec_ext"
+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+IFS=$as_save_IFS
+
+  ;;
+esac
+fi
+RMPROG=$ac_cv_path_RMPROG
+if test -n "$RMPROG"; then
+  { echo "$as_me:$LINENO: result: $RMPROG" >&5
+echo "${ECHO_T}$RMPROG" >&6; }
+else
+  { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+fi
+
+
+  test -n "$RMPROG" && break
+done
+test -n "$RMPROG" || RMPROG="/bin/rm"
+
+for ac_prog in sh
+do
+  # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
+if test "${ac_cv_path_SHPROG+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  case $SHPROG in
+  [\\/]* | ?:[\\/]*)
+  ac_cv_path_SHPROG="$SHPROG" # Let the user override the test with a path.
+  ;;
+  *)
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_path_SHPROG="$as_dir/$ac_word$ac_exec_ext"
+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+IFS=$as_save_IFS
+
+  ;;
+esac
+fi
+SHPROG=$ac_cv_path_SHPROG
+if test -n "$SHPROG"; then
+  { echo "$as_me:$LINENO: result: $SHPROG" >&5
+echo "${ECHO_T}$SHPROG" >&6; }
+else
+  { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+fi
+
+
+  test -n "$SHPROG" && break
+done
+test -n "$SHPROG" || SHPROG="/bin/sh"
+
+
+for ac_prog in flex lex
+do
+  # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
+if test "${ac_cv_prog_LEX+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if test -n "$LEX"; then
+  ac_cv_prog_LEX="$LEX" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_LEX="$ac_prog"
+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+IFS=$as_save_IFS
+
+fi
+fi
+LEX=$ac_cv_prog_LEX
+if test -n "$LEX"; then
+  { echo "$as_me:$LINENO: result: $LEX" >&5
+echo "${ECHO_T}$LEX" >&6; }
+else
+  { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+fi
+
+
+  test -n "$LEX" && break
+done
+test -n "$LEX" || LEX=":"
+
+if test "x$LEX" != "x:"; then
+  cat >conftest.l <<_ACEOF
+%%
+a { ECHO; }
+b { REJECT; }
+c { yymore (); }
+d { yyless (1); }
+e { yyless (input () != 0); }
+f { unput (yytext[0]); }
+. { BEGIN INITIAL; }
+%%
+#ifdef YYTEXT_POINTER
+extern char *yytext;
+#endif
+int
+main (void)
+{
+  return ! yylex () + ! yywrap ();
+}
+_ACEOF
+{ (ac_try="$LEX conftest.l"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$LEX conftest.l") 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }
+{ echo "$as_me:$LINENO: checking lex output file root" >&5
+echo $ECHO_N "checking lex output file root... $ECHO_C" >&6; }
+if test "${ac_cv_prog_lex_root+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  
+if test -f lex.yy.c; then
+  ac_cv_prog_lex_root=lex.yy
+elif test -f lexyy.c; then
+  ac_cv_prog_lex_root=lexyy
+else
+  { { echo "$as_me:$LINENO: error: cannot find output from $LEX; giving up" >&5
+echo "$as_me: error: cannot find output from $LEX; giving up" >&2;}
+   { (exit 1); exit 1; }; }
+fi
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_prog_lex_root" >&5
+echo "${ECHO_T}$ac_cv_prog_lex_root" >&6; }
+LEX_OUTPUT_ROOT=$ac_cv_prog_lex_root
+
+if test -z "${LEXLIB+set}"; then
+  { echo "$as_me:$LINENO: checking lex library" >&5
+echo $ECHO_N "checking lex library... $ECHO_C" >&6; }
+if test "${ac_cv_lib_lex+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  
+    ac_save_LIBS=$LIBS
+    ac_cv_lib_lex='none needed'
+    for ac_lib in '' -lfl -ll; do
+      LIBS="$ac_lib $ac_save_LIBS"
+      cat >conftest.$ac_ext <<_ACEOF
+`cat $LEX_OUTPUT_ROOT.c`
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext &&
+       $as_test_x conftest$ac_exeext; then
+  ac_cv_lib_lex=$ac_lib
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+      test "$ac_cv_lib_lex" != 'none needed' && break
+    done
+    LIBS=$ac_save_LIBS
+  
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_lib_lex" >&5
+echo "${ECHO_T}$ac_cv_lib_lex" >&6; }
+  test "$ac_cv_lib_lex" != 'none needed' && LEXLIB=$ac_cv_lib_lex
+fi
+
+
+{ echo "$as_me:$LINENO: checking whether yytext is a pointer" >&5
+echo $ECHO_N "checking whether yytext is a pointer... $ECHO_C" >&6; }
+if test "${ac_cv_prog_lex_yytext_pointer+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  # POSIX says lex can declare yytext either as a pointer or an array; the
+# default is implementation-dependent.  Figure out which it is, since
+# not all implementations provide the %pointer and %array declarations.
+ac_cv_prog_lex_yytext_pointer=no
+ac_save_LIBS=$LIBS
+LIBS="$LEXLIB $ac_save_LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+#define YYTEXT_POINTER 1
+`cat $LEX_OUTPUT_ROOT.c`
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext &&
+       $as_test_x conftest$ac_exeext; then
+  ac_cv_prog_lex_yytext_pointer=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_save_LIBS
+
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_prog_lex_yytext_pointer" >&5
+echo "${ECHO_T}$ac_cv_prog_lex_yytext_pointer" >&6; }
+if test $ac_cv_prog_lex_yytext_pointer = yes; then
+  
+cat >>confdefs.h <<\_ACEOF
+@%:@define YYTEXT_POINTER 1
+_ACEOF
+
+fi
+rm -f conftest.l $LEX_OUTPUT_ROOT.c
+
+fi
+if test "$LEX" = ":" ; then
+  { { echo "$as_me:$LINENO: error: Cannot find flex." >&5
+echo "$as_me: error: Cannot find flex." >&2;}
+   { (exit 1); exit 1; }; }
+elif echo "" | $LEX -V -v --version > /dev/null 2>&1 ; then
+  :
+else
+  { { echo "$as_me:$LINENO: error: Cannot use $LEX as flex." >&5
+echo "$as_me: error: Cannot use $LEX as flex." >&2;}
+   { (exit 1); exit 1; }; }
+fi
+
+for ac_prog in 'bison -y' byacc
+do
+  # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
+if test "${ac_cv_prog_YACC+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if test -n "$YACC"; then
+  ac_cv_prog_YACC="$YACC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_YACC="$ac_prog"
+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+IFS=$as_save_IFS
+
+fi
+fi
+YACC=$ac_cv_prog_YACC
+if test -n "$YACC"; then
+  { echo "$as_me:$LINENO: result: $YACC" >&5
+echo "${ECHO_T}$YACC" >&6; }
+else
+  { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+fi
+
+
+  test -n "$YACC" && break
+done
+test -n "$YACC" || YACC="yacc"
+
+if test "$YACC" = ":" ; then
+  { { echo "$as_me:$LINENO: error: Cannot find yacc." >&5
+echo "$as_me: error: Cannot find yacc." >&2;}
+   { (exit 1); exit 1; }; }
+elif echo "" | $YACC -V -v --version > /dev/null 2>&1 ; then
+  :
+else
+  { echo "$as_me:$LINENO: WARNING: $YACC may not work as yacc." >&5
+echo "$as_me: WARNING: $YACC may not work as yacc." >&2;}
+fi
+
+{ echo "$as_me:$LINENO: checking for posix non-blocking" >&5
+echo $ECHO_N "checking for posix non-blocking... $ECHO_C" >&6; }
+if test "${unet_cv_sys_nonblocking_posix+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if test "$cross_compiling" = yes; then
+  { { echo "$as_me:$LINENO: error: cannot run test program while cross compiling
+See \`config.log' for more details." >&5
+echo "$as_me: error: cannot run test program while cross compiling
+See \`config.log' for more details." >&2;}
+   { (exit 1); exit 1; }; }
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <sys/file.h>
+#include <signal.h>
+$ac_cv_type_signal alarmed() { exit(1); }
+int main(void)
+{
+  char b[12];
+  struct sockaddr x;
+  size_t l = sizeof(x);
+  int f = socket(AF_INET, SOCK_DGRAM, 0);
+  if (f >= 0 && !(fcntl(f, F_SETFL, O_NONBLOCK)))
+  {
+    signal(SIGALRM, alarmed);
+    alarm(2);
+    recvfrom(f, b, 12, 0, &x, &l);
+    alarm(0);
+    exit(0);
+  }
+  exit(1);
+}
+_ACEOF
+rm -f conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
+  { (case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_try") 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  unet_cv_sys_nonblocking_posix=yes
+else
+  echo "$as_me: program exited with status $ac_status" >&5
+echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+( exit $ac_status )
+unet_cv_sys_nonblocking_posix=no
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+fi
+
+
+fi
+{ echo "$as_me:$LINENO: result: $unet_cv_sys_nonblocking_posix" >&5
+echo "${ECHO_T}$unet_cv_sys_nonblocking_posix" >&6; }
+if test $unet_cv_sys_nonblocking_posix = yes; then
+  
+cat >>confdefs.h <<\_ACEOF
+@%:@define NBLOCK_POSIX 
+_ACEOF
+
+else
+{ echo "$as_me:$LINENO: checking for bsd non-blocking" >&5
+echo $ECHO_N "checking for bsd non-blocking... $ECHO_C" >&6; }
+if test "${unet_cv_sys_nonblocking_bsd+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if test "$cross_compiling" = yes; then
+  { { echo "$as_me:$LINENO: error: cannot run test program while cross compiling
+See \`config.log' for more details." >&5
+echo "$as_me: error: cannot run test program while cross compiling
+See \`config.log' for more details." >&2;}
+   { (exit 1); exit 1; }; }
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <sys/file.h>
+#include <signal.h>
+$ac_cv_type_signal alarmed() { exit(1); }
+int main(void)
+{
+  char b[12];
+  struct sockaddr x;
+  size_t l = sizeof(x);
+  int f = socket(AF_INET, SOCK_DGRAM, 0);
+  if (f >= 0 && !(fcntl(f, F_SETFL, O_NDELAY)))
+  {
+    signal(SIGALRM, alarmed);
+    alarm(2);
+    recvfrom(f, b, 12, 0, &x, &l);
+    alarm(0);
+    exit(0);
+  }
+  exit(1);
+}
+_ACEOF
+rm -f conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
+  { (case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_try") 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  unet_cv_sys_nonblocking_bsd=yes
+else
+  echo "$as_me: program exited with status $ac_status" >&5
+echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+( exit $ac_status )
+unet_cv_sys_nonblocking_bsd=no
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+fi
+
+
+fi
+{ echo "$as_me:$LINENO: result: $unet_cv_sys_nonblocking_bsd" >&5
+echo "${ECHO_T}$unet_cv_sys_nonblocking_bsd" >&6; }
+if test $unet_cv_sys_nonblocking_bsd = yes; then
+  
+cat >>confdefs.h <<\_ACEOF
+@%:@define NBLOCK_BSD 
+_ACEOF
+
+else
+  
+cat >>confdefs.h <<\_ACEOF
+@%:@define NBLOCK_SYSV 
+_ACEOF
+
+fi
+fi
+{ echo "$as_me:$LINENO: checking for posix signals" >&5
+echo $ECHO_N "checking for posix signals... $ECHO_C" >&6; }
+if test "${unet_cv_sys_signal_posix+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <signal.h>
+int
+main ()
+{
+sigaction(SIGTERM, (struct sigaction *)0L, (struct sigaction *)0L)
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  unet_cv_sys_signal_posix=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       unet_cv_sys_signal_posix=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ echo "$as_me:$LINENO: result: $unet_cv_sys_signal_posix" >&5
+echo "${ECHO_T}$unet_cv_sys_signal_posix" >&6; }
+if test $unet_cv_sys_signal_posix = yes; then
+  
+cat >>confdefs.h <<\_ACEOF
+@%:@define POSIX_SIGNALS 
+_ACEOF
+
+else
+{ echo "$as_me:$LINENO: checking for bsd reliable signals" >&5
+echo $ECHO_N "checking for bsd reliable signals... $ECHO_C" >&6; }
+if test "${unet_cv_sys_signal_bsd+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if test "$cross_compiling" = yes; then
+  { { echo "$as_me:$LINENO: error: cannot run test program while cross compiling
+See \`config.log' for more details." >&5
+echo "$as_me: error: cannot run test program while cross compiling
+See \`config.log' for more details." >&2;}
+   { (exit 1); exit 1; }; }
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <signal.h>
+int calls = 0;
+$ac_cv_type_signal handler()
+{
+  if (calls) return;
+  calls++;
+  kill(getpid(), SIGTERM);
+  sleep(1);
+}
+int main(void)
+{
+  signal(SIGTERM, handler);
+  kill(getpid(), SIGTERM);
+  exit (0);
+}
+_ACEOF
+rm -f conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
+  { (case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_try") 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  unet_cv_sys_signal_bsd=yes
+else
+  echo "$as_me: program exited with status $ac_status" >&5
+echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+( exit $ac_status )
+unet_cv_sys_signal_bsd=no
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+fi
+
+
+fi
+{ echo "$as_me:$LINENO: result: $unet_cv_sys_signal_bsd" >&5
+echo "${ECHO_T}$unet_cv_sys_signal_bsd" >&6; }
+if test $unet_cv_sys_signal_bsd = yes; then
+  
+cat >>confdefs.h <<\_ACEOF
+@%:@define BSD_RELIABLE_SIGNALS 
+_ACEOF
+
+else
+  
+cat >>confdefs.h <<\_ACEOF
+@%:@define SYSV_UNRELIABLE_SIGNALS 
+_ACEOF
+
+fi
+fi
+
+{ echo "$as_me:$LINENO: checking for OS-dependent information" >&5
+echo $ECHO_N "checking for OS-dependent information... $ECHO_C" >&6; }
+case "$host" in
+    *-linux*)
+       { echo "$as_me:$LINENO: result: Linux ($host) found." >&5
+echo "${ECHO_T}Linux ($host) found." >&6; }
+       unet_poll_syscall=yes
+       ;;
+
+    *-solaris*)
+       { echo "$as_me:$LINENO: result: Solaris ($host) found." >&5
+echo "${ECHO_T}Solaris ($host) found." >&6; }
+       if test x"$ac_cv_header_poll_h" = xyes; then
+           unet_poll_syscall=yes
+       else
+           unet_poll_syscall=no
+       fi
+        
+cat >>confdefs.h <<\_ACEOF
+@%:@define IRCU_SOLARIS 1
+_ACEOF
+
+       ;;
+
+    *-sunos*)
+       { echo "$as_me:$LINENO: result: Solaris ($host) found." >&5
+echo "${ECHO_T}Solaris ($host) found." >&6; }
+       unet_poll_syscall=no
+       ;;
+
+    *-openbsd*)
+       { echo "$as_me:$LINENO: result: OpenBSD ($host) found." >&5
+echo "${ECHO_T}OpenBSD ($host) found." >&6; }
+       if test x"$ac_cv_header_poll_h" = xyes; then
+           unet_poll_syscall=yes
+       else
+           unet_poll_syscall=no
+       fi
+       ;;
+
+    *-*bsd*)
+       { echo "$as_me:$LINENO: result: Generic BSD ($host) found." >&5
+echo "${ECHO_T}Generic BSD ($host) found." >&6; }
+       if test x"$ac_cv_header_poll_h" = xyes; then
+           unet_poll_syscall=yes
+       else
+           unet_poll_syscall=no
+       fi
+       ;;
+
+    *-darwin*)
+       { echo "$as_me:$LINENO: result: Darwin (Mac OS X) ($host) found." >&5
+echo "${ECHO_T}Darwin (Mac OS X) ($host) found." >&6; }
+       unet_poll_syscall=no
+       
+cat >>confdefs.h <<\_ACEOF
+@%:@define _DARWIN_C_SOURCE 1
+_ACEOF
+
+       ;;
+
+    *)
+       { echo "$as_me:$LINENO: result: Unknown system type $host found." >&5
+echo "${ECHO_T}Unknown system type $host found." >&6; }
+       { echo "$as_me:$LINENO: WARNING: Unknown OS type; using generic routines." >&5
+echo "$as_me: WARNING: Unknown OS type; using generic routines." >&2;}
+       unet_poll_syscall=no
+       ;;
+esac
+
+{ echo "$as_me:$LINENO: checking whether to enable use of poll()" >&5
+echo $ECHO_N "checking whether to enable use of poll()... $ECHO_C" >&6; }
+# Check whether --enable-poll was given.
+if test "${enable_poll+set}" = set; then
+  enableval=$enable_poll; unet_cv_enable_poll=$enable_poll
+else
+  if test "${unet_cv_enable_poll+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  unet_cv_enable_poll=$unet_poll_syscall
+fi
+
+fi
+
+
+# Force poll to be disabled if there is no poll.h
+if test x"$ac_cv_header_poll_h" != xyes; then
+    unet_cv_enable_poll=no
+fi
+
+{ echo "$as_me:$LINENO: result: $unet_cv_enable_poll" >&5
+echo "${ECHO_T}$unet_cv_enable_poll" >&6; }
+
+if test x"$unet_cv_enable_poll" = xyes; then
+    
+cat >>confdefs.h <<\_ACEOF
+@%:@define USE_POLL 1
+_ACEOF
+
+    ENGINE_C=engine_poll.c
+else
+    ENGINE_C=engine_select.c
+fi
+
+
+{ echo "$as_me:$LINENO: checking whether to enable debug mode" >&5
+echo $ECHO_N "checking whether to enable debug mode... $ECHO_C" >&6; }
+# Check whether --enable-debug was given.
+if test "${enable_debug+set}" = set; then
+  enableval=$enable_debug; unet_cv_enable_debug=$enable_debug
+else
+  if test "${unet_cv_enable_debug+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  unet_cv_enable_debug=no
+fi
+
+fi
+
+{ echo "$as_me:$LINENO: result: $unet_cv_enable_debug" >&5
+echo "${ECHO_T}$unet_cv_enable_debug" >&6; }
+
+if test x"$unet_cv_enable_debug" = xyes; then
+    
+cat >>confdefs.h <<\_ACEOF
+@%:@define DEBUGMODE 1
+_ACEOF
+
+    CFLAGS="$CFLAGS -O0 -g"
+fi
+
+{ echo "$as_me:$LINENO: checking whether to enable leak detection" >&5
+echo $ECHO_N "checking whether to enable leak detection... $ECHO_C" >&6; }
+
+# Check whether --with-leak-detect was given.
+if test "${with_leak_detect+set}" = set; then
+  withval=$with_leak_detect; unet_cv_with_leak_detect=$with_leak_detect
+else
+  if test "${unet_cv_with_leak_detect+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  unet_cv_with_leak_detect=no
+fi
+
+fi
+
+{ echo "$as_me:$LINENO: result: $unet_cv_enable_leak_detect" >&5
+echo "${ECHO_T}$unet_cv_enable_leak_detect" >&6; }
+
+if test x"$unet_cv_with_leak_detect" != xno; then
+    LIBS="-lgc $LIBS"
+    CFLAGS="-DMDEBUG $CFLAGS"
+    if test x"$unet_cv_with_leak_detect" != xyes; then
+       LIBS="-L$unet_cv_with_leak_detect $LIBS"
+    fi
+fi
+
+
+# Check whether --with-ipv6 was given.
+if test "${with_ipv6+set}" = set; then
+  withval=$with_ipv6; ac_cv_use_ipv6=$withval
+else
+  ac_cv_use_ipv6=$unet_have_sockaddr_in6
+fi
+
+{ echo "$as_me:$LINENO: checking whether to use IPv6" >&5
+echo $ECHO_N "checking whether to use IPv6... $ECHO_C" >&6; }
+if test "${ac_cv_use_ipv6+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_cv_use_ipv6=no
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_use_ipv6" >&5
+echo "${ECHO_T}$ac_cv_use_ipv6" >&6; }
+if test x"$ac_cv_use_ipv6" != "xno" ; then
+    
+cat >>confdefs.h <<\_ACEOF
+@%:@define IPV6 1
+_ACEOF
+
+fi
+
+{ echo "$as_me:$LINENO: checking whether to enable asserts" >&5
+echo $ECHO_N "checking whether to enable asserts... $ECHO_C" >&6; }
+# Check whether --enable-asserts was given.
+if test "${enable_asserts+set}" = set; then
+  enableval=$enable_asserts; unet_cv_enable_asserts=$enable_asserts
+else
+  if test "${unet_cv_enable_asserts+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  unet_cv_enable_asserts=yes
+fi
+
+fi
+
+{ echo "$as_me:$LINENO: result: $unet_cv_enable_asserts" >&5
+echo "${ECHO_T}$unet_cv_enable_asserts" >&6; }
+
+if test x"$unet_cv_enable_asserts" = xno; then
+    
+cat >>confdefs.h <<\_ACEOF
+@%:@define NDEBUG 1
+_ACEOF
+
+fi
+
+{ echo "$as_me:$LINENO: checking whether to enable profiling support (gprof)" >&5
+echo $ECHO_N "checking whether to enable profiling support (gprof)... $ECHO_C" >&6; }
+# Check whether --enable-profile was given.
+if test "${enable_profile+set}" = set; then
+  enableval=$enable_profile; unet_cv_enable_profile=$enable_profile
+else
+  if test "${unet_cv_enable_profile+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  unet_cv_enable_profile=no
+fi
+
+fi
+
+{ echo "$as_me:$LINENO: result: $unet_cv_enable_profile" >&5
+echo "${ECHO_T}$unet_cv_enable_profile" >&6; }
+
+if test x"$unet_cv_enable_profile" = xyes; then
+    CFLAGS="-pg $CFLAGS"
+    LDFLAGS="-pg $LDFLAGS"
+fi
+
+{ echo "$as_me:$LINENO: checking whether to enable pedantic compiler warnings" >&5
+echo $ECHO_N "checking whether to enable pedantic compiler warnings... $ECHO_C" >&6; }
+# Check whether --enable-pedantic was given.
+if test "${enable_pedantic+set}" = set; then
+  enableval=$enable_pedantic; unet_cv_enable_pedantic=$enable_pedantic
+else
+  if test "${unet_cv_enable_pedantic+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  unet_cv_enable_pedantic=no
+fi
+
+fi
+
+{ echo "$as_me:$LINENO: result: $unet_cv_enable_pedantic" >&5
+echo "${ECHO_T}$unet_cv_enable_pedantic" >&6; }
+
+if test x"$unet_cv_enable_pedantic" = xyes; then
+    CFLAGS="-pedantic $CFLAGS"
+fi
+
+{ echo "$as_me:$LINENO: checking whether to enable compiler warnings" >&5
+echo $ECHO_N "checking whether to enable compiler warnings... $ECHO_C" >&6; }
+# Check whether --enable-warnings was given.
+if test "${enable_warnings+set}" = set; then
+  enableval=$enable_warnings; unet_cv_enable_warnings=$enable_warnings
+else
+  if test "${unet_cv_enable_warnings+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  unet_cv_enable_warnings=no
+fi
+
+fi
+
+{ echo "$as_me:$LINENO: result: $unet_cv_enable_warnings" >&5
+echo "${ECHO_T}$unet_cv_enable_warnings" >&6; }
+
+if test x"$unet_cv_enable_warnings" = xyes; then
+    CFLAGS="-Wall $CFLAGS"
+fi
+
+{ echo "$as_me:$LINENO: checking whether to enable inlining for a few critical functions" >&5
+echo $ECHO_N "checking whether to enable inlining for a few critical functions... $ECHO_C" >&6; }
+# Check whether --enable-inlines was given.
+if test "${enable_inlines+set}" = set; then
+  enableval=$enable_inlines; unet_cv_enable_inlines=$enable_inlines
+else
+  if test "${unet_cv_enable_inlines+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  unet_cv_enable_inlines=yes
+fi
+
+fi
+
+{ echo "$as_me:$LINENO: result: $unet_cv_enable_inlines" >&5
+echo "${ECHO_T}$unet_cv_enable_inlines" >&6; }
+
+if test x"$unet_cv_enable_inlines" = xyes; then
+    
+cat >>confdefs.h <<\_ACEOF
+@%:@define FORCEINLINE 1
+_ACEOF
+
+fi
+
+{ echo "$as_me:$LINENO: checking whether to enable the /dev/poll event engine" >&5
+echo $ECHO_N "checking whether to enable the /dev/poll event engine... $ECHO_C" >&6; }
+# Check whether --enable-devpoll was given.
+if test "${enable_devpoll+set}" = set; then
+  enableval=$enable_devpoll; unet_cv_enable_devpoll=$enable_devpoll
+else
+  if test "${unet_cv_enable_devpoll+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  unet_cv_enable_devpoll=yes
+fi
+
+fi
+
+
+if test x"$ac_cv_header_sys_devpoll_h" = xno; then
+    unet_cv_enable_devpoll=no
+fi
+
+{ echo "$as_me:$LINENO: result: $unet_cv_enable_devpoll" >&5
+echo "${ECHO_T}$unet_cv_enable_devpoll" >&6; }
+
+if test x"$unet_cv_enable_devpoll" != xno; then
+    
+cat >>confdefs.h <<\_ACEOF
+@%:@define USE_DEVPOLL 1
+_ACEOF
+
+    ENGINE_C="engine_devpoll.c $ENGINE_C"
+fi
+
+{ echo "$as_me:$LINENO: checking whether to enable the kqueue event engine" >&5
+echo $ECHO_N "checking whether to enable the kqueue event engine... $ECHO_C" >&6; }
+# Check whether --enable-kqueue was given.
+if test "${enable_kqueue+set}" = set; then
+  enableval=$enable_kqueue; unet_cv_enable_kqueue=$enable_kqueue
+else
+  if test "${unet_cv_enable_kqueue+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  unet_cv_enable_kqueue=yes
+fi
+
+fi
+
+
+if test x"$ac_cv_header_sys_event_h" = xno -o x"$ac_cv_func_kqueue" = xno; then
+    unet_cv_enable_kqueue=no
+fi
+
+{ echo "$as_me:$LINENO: result: $unet_cv_enable_kqueue" >&5
+echo "${ECHO_T}$unet_cv_enable_kqueue" >&6; }
+
+if test x"$unet_cv_enable_kqueue" != xno; then
+    
+cat >>confdefs.h <<\_ACEOF
+@%:@define USE_KQUEUE 1
+_ACEOF
+
+    ENGINE_C="engine_kqueue.c $ENGINE_C"
+fi
+
+{ echo "$as_me:$LINENO: checking whether to enable the epoll event engine" >&5
+echo $ECHO_N "checking whether to enable the epoll event engine... $ECHO_C" >&6; }
+# Check whether --enable-epoll was given.
+if test "${enable_epoll+set}" = set; then
+  enableval=$enable_epoll; unet_cv_enable_epoll=$enable_epoll
+else
+  if test "${unet_cv_enable_epoll+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  unet_cv_enable_epoll=yes
+fi
+
+fi
+
+
+if test x"$ac_cv_header_sys_epoll_h" = xno -o x"$ac_cv_func_epoll" = xno; then
+    unet_cv_enable_epoll=no
+fi
+
+{ echo "$as_me:$LINENO: result: $unet_cv_enable_epoll" >&5
+echo "${ECHO_T}$unet_cv_enable_epoll" >&6; }
+
+if test x"$unet_cv_enable_epoll" != xno; then
+    { echo "$as_me:$LINENO: checking whether epoll functions are properly defined" >&5
+echo $ECHO_N "checking whether epoll functions are properly defined... $ECHO_C" >&6; }
+    cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <sys/epoll.h>
+int
+main ()
+{
+epoll_create(10);
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext &&
+       $as_test_x conftest$ac_exeext; then
+  { echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6; }
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+         
+cat >>confdefs.h <<\_ACEOF
+@%:@define EPOLL_NEED_BODY 1
+_ACEOF
+
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+    
+cat >>confdefs.h <<\_ACEOF
+@%:@define USE_EPOLL 1
+_ACEOF
+
+    ENGINE_C="engine_epoll.c $ENGINE_C"
+fi
+
+{ echo "$as_me:$LINENO: checking for va_copy" >&5
+echo $ECHO_N "checking for va_copy... $ECHO_C" >&6; }
+if test "${unet_cv_c_va_copy+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <stdarg.h>
+int
+main ()
+{
+va_list ap1, ap2; va_copy(ap1, ap2);
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext &&
+       $as_test_x conftest$ac_exeext; then
+  unet_cv_c_va_copy="yes"
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       unet_cv_c_va_copy="no"
+
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+fi
+{ echo "$as_me:$LINENO: result: $unet_cv_c_va_copy" >&5
+echo "${ECHO_T}$unet_cv_c_va_copy" >&6; }
+if test "$unet_cv_c_va_copy" = "yes" ; then
+  
+cat >>confdefs.h <<\_ACEOF
+@%:@define HAVE_VA_COPY 1
+_ACEOF
+
+fi
+
+{ echo "$as_me:$LINENO: checking for __va_copy" >&5
+echo $ECHO_N "checking for __va_copy... $ECHO_C" >&6; }
+if test "${unet_cv_c___va_copy+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <stdarg.h>
+int
+main ()
+{
+va_list ap1, ap2; __va_copy(ap1, ap2);
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext &&
+       $as_test_x conftest$ac_exeext; then
+  unet_cv_c___va_copy="yes"
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       unet_cv_c___va_copy="no"
+
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+fi
+{ echo "$as_me:$LINENO: result: $unet_cv_c___va_copy" >&5
+echo "${ECHO_T}$unet_cv_c___va_copy" >&6; }
+if test "$unet_cv_c___va_copy" = "yes" ; then
+  
+cat >>confdefs.h <<\_ACEOF
+@%:@define HAVE___VA_COPY 1
+_ACEOF
+
+fi
+
+{ echo "$as_me:$LINENO: checking what name to give the symlink" >&5
+echo $ECHO_N "checking what name to give the symlink... $ECHO_C" >&6; }
+
+# Check whether --with-symlink was given.
+if test "${with_symlink+set}" = set; then
+  withval=$with_symlink; unet_cv_with_symlink=$with_symlink
+else
+  if test "${unet_cv_with_symlink+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  unet_cv_with_symlink="ircd"
+fi
+
+fi
+
+
+if test x"$unet_cv_with_symlink" = xyes; then
+    unet_cv_with_symlink="ircd"
+fi
+
+{ echo "$as_me:$LINENO: result: $unet_cv_with_symlink" >&5
+echo "${ECHO_T}$unet_cv_with_symlink" >&6; }
+
+if test x"$unet_cv_with_symlink" = xno; then
+    INSTALL_RULE=install-no-symlink
+    SYMLINK=
+else
+    INSTALL_RULE=install-with-symlink
+    SYMLINK=$unet_cv_with_symlink
+fi
+
+
+
+{ echo "$as_me:$LINENO: checking what permissions to set on the installed binary" >&5
+echo $ECHO_N "checking what permissions to set on the installed binary... $ECHO_C" >&6; }
+
+# Check whether --with-mode was given.
+if test "${with_mode+set}" = set; then
+  withval=$with_mode; unet_cv_with_mode=$with_mode
+else
+  if test "${unet_cv_with_mode+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  unet_cv_with_mode=711
+fi
+
+fi
+
+
+if test x"$unet_cv_with_mode" = xyes -o x"$unet_cv_with_mode" = xno; then
+    unet_cv_with_mode=711
+fi
+
+{ echo "$as_me:$LINENO: result: $unet_cv_with_mode" >&5
+echo "${ECHO_T}$unet_cv_with_mode" >&6; }
+
+IRCDMODE=$unet_cv_with_mode
+
+
+unet_uid=`id | sed -e 's/.*uid=[0-9]*(//' -e 's/).*//' 2> /dev/null`
+{ echo "$as_me:$LINENO: checking which user should own the installed binary" >&5
+echo $ECHO_N "checking which user should own the installed binary... $ECHO_C" >&6; }
+
+# Check whether --with-owner was given.
+if test "${with_owner+set}" = set; then
+  withval=$with_owner; unet_cv_with_owner=$with_owner
+else
+  if test "${unet_cv_with_owner+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  unet_cv_with_owner=$unet_uid
+fi
+
+fi
+
+
+if test x"$unet_cv_with_owner" = xyes -o x"$unet_cv_with_owner" = xno; then
+    unet_cv_with_owner=$unet_uid
+fi
+
+{ echo "$as_me:$LINENO: result: $unet_cv_with_owner" >&5
+echo "${ECHO_T}$unet_cv_with_owner" >&6; }
+
+IRCDOWN=$unet_cv_with_owner
+
+
+unet_gid=`id | sed -e 's/.*gid=[0-9]*(//' -e 's/).*//' 2> /dev/null`
+{ echo "$as_me:$LINENO: checking which group should own the installed binary" >&5
+echo $ECHO_N "checking which group should own the installed binary... $ECHO_C" >&6; }
+
+# Check whether --with-group was given.
+if test "${with_group+set}" = set; then
+  withval=$with_group; unet_cv_with_group=$with_group
+else
+  if test "${unet_cv_with_group+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  unet_cv_with_group=$unet_gid
+fi
+
+fi
+
+
+if test x"$unet_cv_with_group" = xyes -o x"$unet_cv_with_group" = xno; then
+    unet_cv_with_group=$unet_gid
+fi
+
+{ echo "$as_me:$LINENO: result: $unet_cv_with_group" >&5
+echo "${ECHO_T}$unet_cv_with_group" >&6; }
+
+IRCDGRP=$unet_cv_with_group
+
+
+unet_domain=
+if test -f /etc/resolv.conf; then
+    unet_domain=`awk '/^domain/ { print $2; exit }' /etc/resolv.conf`
+    if test x"$unet_domain" = x; then
+       unet_domain=`awk '/^search/ { print $2; exit }' /etc/resolv.conf`
+    fi
+fi
+{ echo "$as_me:$LINENO: checking for site domain name" >&5
+echo $ECHO_N "checking for site domain name... $ECHO_C" >&6; }
+
+# Check whether --with-domain was given.
+if test "${with_domain+set}" = set; then
+  withval=$with_domain; unet_cv_with_domain=$with_domain
+else
+  if test "${unet_cv_with_domain+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  unet_cv_with_domain=$unet_domain
+fi
+
+fi
+
+
+if test x"$unet_cv_with_domain" = xyes -o x"$unet_cv_with_domain" = xno; then
+    unet_cv_with_domain=$unet_domain
+fi
+if test x"$unet_cv_with_domain" = xno; then
+    { { echo "$as_me:$LINENO: error: Unable to determine server DNS domain; use --with-domain to set it" >&5
+echo "$as_me: error: Unable to determine server DNS domain; use --with-domain to set it" >&2;}
+   { (exit 1); exit 1; }; }
+fi
+
+{ echo "$as_me:$LINENO: result: $unet_cv_with_domain" >&5
+echo "${ECHO_T}$unet_cv_with_domain" >&6; }
+
+
+cat >>confdefs.h <<_ACEOF
+@%:@define DOMAINNAME "*$unet_cv_with_domain"
+_ACEOF
+
+
+{ echo "$as_me:$LINENO: checking if chroot operation is desired" >&5
+echo $ECHO_N "checking if chroot operation is desired... $ECHO_C" >&6; }
+
+# Check whether --with-chroot was given.
+if test "${with_chroot+set}" = set; then
+  withval=$with_chroot; unet_cv_with_chroot=$with_chroot
+else
+  if test "${unet_cv_with_chroot+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  unet_cv_with_chroot=no
+fi
+
+fi
+
+
+if test x"$unet_cv_with_chroot" = xyes; then
+    { { echo "$as_me:$LINENO: error: --with-chroot given with no directory.  See doc/readme.chroot." >&5
+echo "$as_me: error: --with-chroot given with no directory.  See doc/readme.chroot." >&2;}
+   { (exit 1); exit 1; }; }
+fi
+
+# Ensure there are no trailing /'s to mess us up
+unet_cv_with_chroot=`echo "$unet_cv_with_chroot" | sed 's%/*$%%'`
+
+{ echo "$as_me:$LINENO: result: $unet_cv_with_chroot" >&5
+echo "${ECHO_T}$unet_cv_with_chroot" >&6; }
+
+# Deal with the annoying value "NONE" here
+unet_save_prefix=$prefix
+if test x"$prefix" = xNONE; then
+    prefix=$ac_default_prefix
+else
+    prefix=$prefix
+fi
+
+unet_save_exec_prefix=$exec_prefix
+if test x"$exec_prefix" = xNONE; then
+    exec_prefix=$prefix
+else
+    exec_prefix=$exec_prefix
+fi
+
+# Obtain the actual interesting directories
+unet_bindir=`eval echo "$bindir"`
+unet_libdir=`eval echo "$libdir"`
+
+# Restore the original settings of $prefix and $exec_prefix
+prefix=$unet_save_prefix
+exec_prefix=$unet_save_exec_prefix
+
+{ echo "$as_me:$LINENO: checking where the binary will be for /restart" >&5
+echo $ECHO_N "checking where the binary will be for /restart... $ECHO_C" >&6; }
+if test x"$unet_cv_with_symlink" = xno; then
+    unet_spath="$unet_bindir/ircd"
+else
+    unet_spath="$unet_bindir/$unet_cv_with_symlink"
+fi
+{ echo "$as_me:$LINENO: result: $unet_spath" >&5
+echo "${ECHO_T}$unet_spath" >&6; }
+
+if test x"$unet_cv_with_chroot" != xno; then
+    if echo "$unet_spath" | grep "^$unet_cv_with_chroot" > /dev/null 2>&1; then
+       unet_spath=`echo "$unet_spath" | sed "s%^$unet_cv_with_chroot%%"`
+    else
+       { echo "$as_me:$LINENO: WARNING: Binary $unet_spath not relative to root directory $unet_cv_with_chroot; restarts will probably fail" >&5
+echo "$as_me: WARNING: Binary $unet_spath not relative to root directory $unet_cv_with_chroot; restarts will probably fail" >&2;}
+    fi
+fi
+
+
+cat >>confdefs.h <<_ACEOF
+@%:@define SPATH "$unet_spath"
+_ACEOF
+
+
+{ echo "$as_me:$LINENO: checking what the data directory should be" >&5
+echo $ECHO_N "checking what the data directory should be... $ECHO_C" >&6; }
+
+# Check whether --with-dpath was given.
+if test "${with_dpath+set}" = set; then
+  withval=$with_dpath; unet_cv_with_dpath=$with_dpath
+else
+  if test "${unet_cv_with_dpath+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  unet_cv_with_dpath=$unet_libdir
+fi
+
+fi
+
+
+if test x"$unet_cv_with_dpath" = xyes -o x"$unet_cv_with_dpath" = xno; then
+    unet_cv_with_dpath=$unet_libdir
+fi
+
+# Ensure there are no trailing /'s to mess us up
+unet_cv_with_dpath=`echo "$unet_cv_with_dpath" | sed 's%/*$%%'`
+
+{ echo "$as_me:$LINENO: result: $unet_cv_with_dpath" >&5
+echo "${ECHO_T}$unet_cv_with_dpath" >&6; }
+
+if test x"$unet_cv_with_chroot" != xno; then
+    if echo "$unet_cv_with_dpath" | grep "^$unet_cv_with_chroot" > /dev/null 2>&1; then
+       unet_dpath=`echo "$unet_cv_with_dpath" | sed "s%^$unet_cv_with_chroot%%"`
+    else
+       { { echo "$as_me:$LINENO: error: Data directory $unet_cv_with_dpath not relative to root directory $unet_cv_with_chroot" >&5
+echo "$as_me: error: Data directory $unet_cv_with_dpath not relative to root directory $unet_cv_with_chroot" >&2;}
+   { (exit 1); exit 1; }; }
+    fi
+else
+    unet_dpath=$unet_cv_with_dpath
+fi
+
+
+cat >>confdefs.h <<_ACEOF
+@%:@define DPATH "$unet_dpath"
+_ACEOF
+
+
+DPATH=$unet_cv_with_dpath
+
+
+{ echo "$as_me:$LINENO: checking where the default configuration file resides" >&5
+echo $ECHO_N "checking where the default configuration file resides... $ECHO_C" >&6; }
+
+# Check whether --with-cpath was given.
+if test "${with_cpath+set}" = set; then
+  withval=$with_cpath; unet_cv_with_cpath=$with_cpath
+else
+  if test "${unet_cv_with_cpath+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  unet_cv_with_cpath="ircd.conf"
+fi
+
+fi
+
+
+if test x"$unet_cv_with_cpath" = xyes -o x"$unet_cv_with_cpath" = xno; then
+    unet_cv_with_cpath="ircd.conf"
+fi
+
+{ echo "$as_me:$LINENO: result: $unet_cv_with_cpath" >&5
+echo "${ECHO_T}$unet_cv_with_cpath" >&6; }
+
+if echo "$unet_cv_with_cpath" | grep '^/' > /dev/null 2>&1; then
+    # Absolute path; check against chroot stuff
+    if test x"$unet_cv_with_chroot" != xno; then
+       if echo "$unet_cv_with_cpath" | grep "^$unet_cv_with_chroot" > /dev/null 2>&1; then
+           unet_cpath=`echo "$unet_cv_with_cpath" | sed "s%^$unet_cv_with_chroot%%"`
+       else
+           { { echo "$as_me:$LINENO: error: Configuration file $unet_cv_with_cpath not relative to root directory $unet_cv_with_chroot" >&5
+echo "$as_me: error: Configuration file $unet_cv_with_cpath not relative to root directory $unet_cv_with_chroot" >&2;}
+   { (exit 1); exit 1; }; }
+       fi
+    else
+       unet_cpath=$unet_cv_with_cpath
+    fi
+else
+    unet_cpath=$unet_cv_with_cpath
+fi
+
+
+cat >>confdefs.h <<_ACEOF
+@%:@define CPATH "$unet_cpath"
+_ACEOF
+
+
+{ echo "$as_me:$LINENO: checking where to put the debugging log if debugging enabled" >&5
+echo $ECHO_N "checking where to put the debugging log if debugging enabled... $ECHO_C" >&6; }
+
+# Check whether --with-lpath was given.
+if test "${with_lpath+set}" = set; then
+  withval=$with_lpath; unet_cv_with_lpath=$with_lpath
+else
+  if test "${unet_cv_with_lpath+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  unet_cv_with_lpath="ircd.log"
+fi
+
+fi
+
+
+if test x"$unet_cv_with_lpath" = xyes -o x"$unet_cv_with_lpath" = xno; then
+    unet_cv_with_lpath="ircd.log"
+fi
+
+{ echo "$as_me:$LINENO: result: $unet_cv_with_lpath" >&5
+echo "${ECHO_T}$unet_cv_with_lpath" >&6; }
+
+if echo "$unet_cv_with_lpath" | grep '^/' > /dev/null 2>&1; then
+    # Absolute path; check against chroot stuff
+    if test x"$unet_cv_with_chroot" != xno; then
+       if echo "$unet_cv_with_lpath" | grep "^$unet_cv_with_chroot" > /dev/null 2>&1; then
+           unet_lpath=`echo "$unet_cv_with_lpath" | sed "s%^$unet_cv_with_chroot%%"`
+       else
+           { echo "$as_me:$LINENO: WARNING: Log file $unet_cv_with_lpath not relative to root directory $unet_cv_with_chroot; using default ircd.log instead" >&5
+echo "$as_me: WARNING: Log file $unet_cv_with_lpath not relative to root directory $unet_cv_with_chroot; using default ircd.log instead" >&2;}
+           unet_cv_with_lpath="ircd.log"
+           unet_lpath="ircd.log"
+       fi
+    else
+       unet_lpath=$unet_cv_with_lpath
+    fi
+else
+    unet_lpath=$unet_cv_with_lpath
+fi
+
+
+cat >>confdefs.h <<_ACEOF
+@%:@define LPATH "$unet_lpath"
+_ACEOF
+
+
+unet_maxcon=`ulimit -Hn`
+if test x"$unet_maxcon" = xunlimited; then
+    unet_maxcon=`ulimit -Sn`
+fi
+unet_maxcon=`expr $unet_maxcon - 4`
+{ echo "$as_me:$LINENO: checking max connections" >&5
+echo $ECHO_N "checking max connections... $ECHO_C" >&6; }
+
+# Check whether --with-maxcon was given.
+if test "${with_maxcon+set}" = set; then
+  withval=$with_maxcon; unet_cv_with_maxcon=$with_maxcon
+else
+  if test "${unet_cv_with_maxcon+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  unet_cv_with_maxcon=$unet_maxcon
+fi
+
+fi
+
+
+if test x"$unet_cv_with_maxcon" = xyes -o x"$unet_cv_with_maxcon" = xno; then
+    if test "$unet_maxcon" -lt 32; then
+      { { echo "$as_me:$LINENO: error: Maximum connections (number of open files minus 4) must be at least 32." >&5
+echo "$as_me: error: Maximum connections (number of open files minus 4) must be at least 32." >&2;}
+   { (exit 1); exit 1; }; }
+    fi
+    unet_cv_with_maxcon=$unet_maxcon
+elif test "$unet_cv_with_maxcon" -lt 32; then
+    { { echo "$as_me:$LINENO: error: Maximum connections (--with-maxcon) must be at least 32." >&5
+echo "$as_me: error: Maximum connections (--with-maxcon) must be at least 32." >&2;}
+   { (exit 1); exit 1; }; }
+fi
+
+{ echo "$as_me:$LINENO: result: $unet_cv_with_maxcon" >&5
+echo "${ECHO_T}$unet_cv_with_maxcon" >&6; }
+
+
+cat >>confdefs.h <<_ACEOF
+@%:@define MAXCONNECTIONS $unet_cv_with_maxcon
+_ACEOF
+
+
+unet_cv_enable_compat="yes"
+{ echo "$as_me:$LINENO: checking whether to enable OGN-compat mode" >&5
+echo $ECHO_N "checking whether to enable OGN-compat mode... $ECHO_C" >&6; }
+# Check whether --enable-compat was given.
+if test "${enable_compat+set}" = set; then
+  enableval=$enable_compat; unet_cv_enable_compat=$enable_compat
+fi
+
+{ echo "$as_me:$LINENO: result: $unet_cv_enable_compat" >&5
+echo "${ECHO_T}$unet_cv_enable_compat" >&6; }
+
+if test $unet_cv_enable_compat = "no" ; then
+    # do nothing
+    unet_cv_enable_compat="no"
+else
+    
+cat >>confdefs.h <<\_ACEOF
+@%:@define OLD_OGN_IRCU_COMPAT 1
+_ACEOF
+
+fi
+
+unet_cv_enable_unstable="no"
+{ echo "$as_me:$LINENO: checking whether to enable unstable features" >&5
+echo $ECHO_N "checking whether to enable unstable features... $ECHO_C" >&6; }
+# Check whether --enable-unstable was given.
+if test "${enable_unstable+set}" = set; then
+  enableval=$enable_unstable; unet_cv_enable_unstable=$enable_unstable
+fi
+
+{ echo "$as_me:$LINENO: result: $unet_cv_enable_unstable" >&5
+echo "${ECHO_T}$unet_cv_enable_unstable" >&6; }
+
+if test $unet_cv_enable_unstable = "yes" ; then
+    
+cat >>confdefs.h <<\_ACEOF
+@%:@define WITH_UNSTABLE_FEAT 1
+_ACEOF
+
+fi
+
+
+unet_cv_enable_gnutls="no"
+unet_cv_enable_openssl="yes"
+
+{ echo "$as_me:$LINENO: checking for GnuTLS" >&5
+echo $ECHO_N "checking for GnuTLS... $ECHO_C" >&6; }
+# Check whether --enable-gnutls was given.
+if test "${enable_gnutls+set}" = set; then
+  enableval=$enable_gnutls; unet_cv_enable_gnutls=$enable_gnutls
+fi
+
+{ echo "$as_me:$LINENO: result: $unet_cv_enable_gnutls" >&5
+echo "${ECHO_T}$unet_cv_enable_gnutls" >&6; }
+
+{ echo "$as_me:$LINENO: checking for OpenSSL" >&5
+echo $ECHO_N "checking for OpenSSL... $ECHO_C" >&6; }
+# Check whether --enable-openssl was given.
+if test "${enable_openssl+set}" = set; then
+  enableval=$enable_openssl; unet_cv_enable_openssl=$enable_openssl
+fi
+
+{ echo "$as_me:$LINENO: result: $unet_cv_enable_openssl" >&5
+echo "${ECHO_T}$unet_cv_enable_openssl" >&6; }
+
+if test x"$unet_cv_enable_gnutls" = xyes; then
+  unet_cv_enable_gnutls="no";
+  { echo "$as_me:$LINENO: checking for gnutls_init in -lgnutls" >&5
+echo $ECHO_N "checking for gnutls_init in -lgnutls... $ECHO_C" >&6; }
+if test "${ac_cv_lib_gnutls_gnutls_init+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lgnutls  $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char gnutls_init ();
+int
+main ()
+{
+return gnutls_init ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext &&
+       $as_test_x conftest$ac_exeext; then
+  ac_cv_lib_gnutls_gnutls_init=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_lib_gnutls_gnutls_init=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_lib_gnutls_gnutls_init" >&5
+echo "${ECHO_T}$ac_cv_lib_gnutls_gnutls_init" >&6; }
+if test $ac_cv_lib_gnutls_gnutls_init = yes; then
+  
+    
+for ac_header in gnutls/gnutls.h
+do
+as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
+if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
+  { echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; }
+if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+fi
+ac_res=`eval echo '${'$as_ac_Header'}'`
+              { echo "$as_me:$LINENO: result: $ac_res" >&5
+echo "${ECHO_T}$ac_res" >&6; }
+else
+  # Is the header compilable?
+{ echo "$as_me:$LINENO: checking $ac_header usability" >&5
+echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6; }
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+@%:@include <$ac_header>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_header_compiler=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_header_compiler=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+{ echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
+echo "${ECHO_T}$ac_header_compiler" >&6; }
+
+# Is the header present?
+{ echo "$as_me:$LINENO: checking $ac_header presence" >&5
+echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6; }
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+@%:@include <$ac_header>
+_ACEOF
+if { (ac_try="$ac_cpp conftest.$ac_ext"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } >/dev/null && {
+        test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       }; then
+  ac_header_preproc=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+  ac_header_preproc=no
+fi
+
+rm -f conftest.err conftest.$ac_ext
+{ echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
+echo "${ECHO_T}$ac_header_preproc" >&6; }
+
+# So?  What about this header?
+case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
+  yes:no: )
+    { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5
+echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;}
+    ac_header_preproc=yes
+    ;;
+  no:yes:* )
+    { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5
+echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header:     check for missing prerequisite headers?" >&5
+echo "$as_me: WARNING: $ac_header:     check for missing prerequisite headers?" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5
+echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&5
+echo "$as_me: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5
+echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;}
+    
+    ;;
+esac
+{ echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; }
+if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  eval "$as_ac_Header=\$ac_header_preproc"
+fi
+ac_res=`eval echo '${'$as_ac_Header'}'`
+              { echo "$as_me:$LINENO: result: $ac_res" >&5
+echo "${ECHO_T}$ac_res" >&6; }
+
+fi
+if test `eval echo '${'$as_ac_Header'}'` = yes; then
+  cat >>confdefs.h <<_ACEOF
+@%:@define `echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+      unet_cv_enable_gnutls="yes";
+    
+fi
+
+done
+
+  
+fi
+
+fi
+
+if test x"$unet_cv_enable_openssl" = xyes; then
+  unet_cv_enable_openssl="no";
+  { echo "$as_me:$LINENO: checking for SSL_read in -lssl" >&5
+echo $ECHO_N "checking for SSL_read in -lssl... $ECHO_C" >&6; }
+if test "${ac_cv_lib_ssl_SSL_read+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lssl  $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char SSL_read ();
+int
+main ()
+{
+return SSL_read ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext &&
+       $as_test_x conftest$ac_exeext; then
+  ac_cv_lib_ssl_SSL_read=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_lib_ssl_SSL_read=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_lib_ssl_SSL_read" >&5
+echo "${ECHO_T}$ac_cv_lib_ssl_SSL_read" >&6; }
+if test $ac_cv_lib_ssl_SSL_read = yes; then
+  
+    { echo "$as_me:$LINENO: checking for X509_new in -lcrypto" >&5
+echo $ECHO_N "checking for X509_new in -lcrypto... $ECHO_C" >&6; }
+if test "${ac_cv_lib_crypto_X509_new+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lcrypto  $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char X509_new ();
+int
+main ()
+{
+return X509_new ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext &&
+       $as_test_x conftest$ac_exeext; then
+  ac_cv_lib_crypto_X509_new=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_lib_crypto_X509_new=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_lib_crypto_X509_new" >&5
+echo "${ECHO_T}$ac_cv_lib_crypto_X509_new" >&6; }
+if test $ac_cv_lib_crypto_X509_new = yes; then
+  
+      
+
+for ac_header in openssl/ssl.h openssl/err.h
+do
+as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
+if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
+  { echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; }
+if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+fi
+ac_res=`eval echo '${'$as_ac_Header'}'`
+              { echo "$as_me:$LINENO: result: $ac_res" >&5
+echo "${ECHO_T}$ac_res" >&6; }
+else
+  # Is the header compilable?
+{ echo "$as_me:$LINENO: checking $ac_header usability" >&5
+echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6; }
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+@%:@include <$ac_header>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_header_compiler=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_header_compiler=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+{ echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
+echo "${ECHO_T}$ac_header_compiler" >&6; }
+
+# Is the header present?
+{ echo "$as_me:$LINENO: checking $ac_header presence" >&5
+echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6; }
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+@%:@include <$ac_header>
+_ACEOF
+if { (ac_try="$ac_cpp conftest.$ac_ext"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } >/dev/null && {
+        test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       }; then
+  ac_header_preproc=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+  ac_header_preproc=no
+fi
+
+rm -f conftest.err conftest.$ac_ext
+{ echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
+echo "${ECHO_T}$ac_header_preproc" >&6; }
+
+# So?  What about this header?
+case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
+  yes:no: )
+    { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5
+echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;}
+    ac_header_preproc=yes
+    ;;
+  no:yes:* )
+    { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5
+echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header:     check for missing prerequisite headers?" >&5
+echo "$as_me: WARNING: $ac_header:     check for missing prerequisite headers?" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5
+echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&5
+echo "$as_me: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5
+echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;}
+    
+    ;;
+esac
+{ echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; }
+if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  eval "$as_ac_Header=\$ac_header_preproc"
+fi
+ac_res=`eval echo '${'$as_ac_Header'}'`
+              { echo "$as_me:$LINENO: result: $ac_res" >&5
+echo "${ECHO_T}$ac_res" >&6; }
+
+fi
+if test `eval echo '${'$as_ac_Header'}'` = yes; then
+  cat >>confdefs.h <<_ACEOF
+@%:@define `echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+        unet_cv_enable_openssl="yes";
+      
+fi
+
+done
+
+    
+fi
+
+  
+fi
+
+fi
+
+if test x"$unet_cv_enable_gnutls" = xyes; then
+    LIBS="$LIBS -lgnutls"
+    
+cat >>confdefs.h <<\_ACEOF
+@%:@define HAVE_GNUTLS 1
+_ACEOF
+
+fi
+
+if test x"$unet_cv_enable_openssl" = xyes ; then
+    LIBS="$LIBS -lssl -lcrypto"
+    
+cat >>confdefs.h <<\_ACEOF
+@%:@define HAVE_OPENSSL 1
+_ACEOF
+
+fi
+
+ac_config_files="$ac_config_files Makefile ircd/Makefile doc/Makefile"
+
+ac_config_commands="$ac_config_commands default"
+
+cat >confcache <<\_ACEOF
+# This file is a shell script that caches the results of configure
+# tests run on this system so they can be shared between configure
+# scripts and configure runs, see configure's option --config-cache.
+# It is not useful on other systems.  If it contains results you don't
+# want to keep, you may remove or edit it.
+#
+# config.status only pays attention to the cache file if you give it
+# the --recheck option to rerun configure.
+#
+# `ac_cv_env_foo' variables (set or unset) will be overridden when
+# loading this file, other *unset* `ac_cv_foo' will be assigned the
+# following values.
+
+_ACEOF
+
+# The following way of writing the cache mishandles newlines in values,
+# but we know of no workaround that is simple, portable, and efficient.
+# So, we kill variables containing newlines.
+# Ultrix sh set writes to stderr and can't be redirected directly,
+# and sets the high bit in the cache file unless we assign to the vars.
+(
+  for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do
+    eval ac_val=\$$ac_var
+    case $ac_val in #(
+    *${as_nl}*)
+      case $ac_var in #(
+      *_cv_*) { echo "$as_me:$LINENO: WARNING: Cache variable $ac_var contains a newline." >&5
+echo "$as_me: WARNING: Cache variable $ac_var contains a newline." >&2;} ;;
+      esac
+      case $ac_var in #(
+      _ | IFS | as_nl) ;; #(
+      *) $as_unset $ac_var ;;
+      esac ;;
+    esac
+  done
+
+  (set) 2>&1 |
+    case $as_nl`(ac_space=' '; set) 2>&1` in #(
+    *${as_nl}ac_space=\ *)
+      # `set' does not quote correctly, so add quotes (double-quote
+      # substitution turns \\\\ into \\, and sed turns \\ into \).
+      sed -n \
+       "s/'/'\\\\''/g;
+         s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p"
+      ;; #(
+    *)
+      # `set' quotes correctly as required by POSIX, so do not add quotes.
+      sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p"
+      ;;
+    esac |
+    sort
+) |
+  sed '
+     /^ac_cv_env_/b end
+     t clear
+     :clear
+     s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/
+     t end
+     s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/
+     :end' >>confcache
+if diff "$cache_file" confcache >/dev/null 2>&1; then :; else
+  if test -w "$cache_file"; then
+    test "x$cache_file" != "x/dev/null" &&
+      { echo "$as_me:$LINENO: updating cache $cache_file" >&5
+echo "$as_me: updating cache $cache_file" >&6;}
+    cat confcache >$cache_file
+  else
+    { echo "$as_me:$LINENO: not updating unwritable cache $cache_file" >&5
+echo "$as_me: not updating unwritable cache $cache_file" >&6;}
+  fi
+fi
+rm -f confcache
+
+test "x$prefix" = xNONE && prefix=$ac_default_prefix
+# Let make expand exec_prefix.
+test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
+
+DEFS=-DHAVE_CONFIG_H
+
+ac_libobjs=
+ac_ltlibobjs=
+for ac_i in : $LIB@&t@OBJS; do test "x$ac_i" = x: && continue
+  # 1. Remove the extension, and $U if already installed.
+  ac_script='s/\$U\././;s/\.o$//;s/\.obj$//'
+  ac_i=`echo "$ac_i" | sed "$ac_script"`
+  # 2. Prepend LIBOBJDIR.  When used with automake>=1.10 LIBOBJDIR
+  #    will be set to the directory where LIBOBJS objects are built.
+  ac_libobjs="$ac_libobjs \${LIBOBJDIR}$ac_i\$U.$ac_objext"
+  ac_ltlibobjs="$ac_ltlibobjs \${LIBOBJDIR}$ac_i"'$U.lo'
+done
+LIB@&t@OBJS=$ac_libobjs
+
+LTLIBOBJS=$ac_ltlibobjs
+
+
+
+: ${CONFIG_STATUS=./config.status}
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files $CONFIG_STATUS"
+{ echo "$as_me:$LINENO: creating $CONFIG_STATUS" >&5
+echo "$as_me: creating $CONFIG_STATUS" >&6;}
+cat >$CONFIG_STATUS <<_ACEOF
+#! $SHELL
+# Generated by $as_me.
+# Run this file to recreate the current configuration.
+# Compiler output produced by configure, useful for debugging
+# configure, is in config.log if it exists.
+
+debug=false
+ac_cs_recheck=false
+ac_cs_silent=false
+SHELL=\${CONFIG_SHELL-$SHELL}
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF
+## --------------------- ##
+## M4sh Initialization.  ##
+## --------------------- ##
+
+# Be more Bourne compatible
+DUALCASE=1; export DUALCASE # for MKS sh
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then
+  emulate sh
+  NULLCMD=:
+  # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which
+  # is contrary to our usage.  Disable this feature.
+  alias -g '${1+"$@"}'='"$@"'
+  setopt NO_GLOB_SUBST
+else
+  case `(set -o) 2>/dev/null` in
+  *posix*) set -o posix ;;
+esac
+
+fi
+
+
+
+
+# PATH needs CR
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+  echo "#! /bin/sh" >conf$$.sh
+  echo  "exit 0"   >>conf$$.sh
+  chmod +x conf$$.sh
+  if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then
+    PATH_SEPARATOR=';'
+  else
+    PATH_SEPARATOR=:
+  fi
+  rm -f conf$$.sh
+fi
+
+# Support unset when possible.
+if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then
+  as_unset=unset
+else
+  as_unset=false
+fi
+
+
+# IFS
+# We need space, tab and new line, in precisely that order.  Quoting is
+# there to prevent editors from complaining about space-tab.
+# (If _AS_PATH_WALK were called with IFS unset, it would disable word
+# splitting by setting IFS to empty value.)
+as_nl='
+'
+IFS=" ""       $as_nl"
+
+# Find who we are.  Look in the path if we contain no directory separator.
+case $0 in
+  *[\\/]* ) as_myself=$0 ;;
+  *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+done
+IFS=$as_save_IFS
+
+     ;;
+esac
+# We did not find ourselves, most probably we were run as `sh COMMAND'
+# in which case we are not to be found in the path.
+if test "x$as_myself" = x; then
+  as_myself=$0
+fi
+if test ! -f "$as_myself"; then
+  echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
+  { (exit 1); exit 1; }
+fi
+
+# Work around bugs in pre-3.0 UWIN ksh.
+for as_var in ENV MAIL MAILPATH
+do ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var
+done
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+for as_var in \
+  LANG LANGUAGE LC_ADDRESS LC_ALL LC_COLLATE LC_CTYPE LC_IDENTIFICATION \
+  LC_MEASUREMENT LC_MESSAGES LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER \
+  LC_TELEPHONE LC_TIME
+do
+  if (set +x; test -z "`(eval $as_var=C; export $as_var) 2>&1`"); then
+    eval $as_var=C; export $as_var
+  else
+    ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var
+  fi
+done
+
+# Required to use basename.
+if expr a : '\(a\)' >/dev/null 2>&1 &&
+   test "X`expr 00001 : '.*\(...\)'`" = X001; then
+  as_expr=expr
+else
+  as_expr=false
+fi
+
+if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then
+  as_basename=basename
+else
+  as_basename=false
+fi
+
+
+# Name of the executable.
+as_me=`$as_basename -- "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+        X"$0" : 'X\(//\)$' \| \
+        X"$0" : 'X\(/\)' \| . 2>/dev/null ||
+echo X/"$0" |
+    sed '/^.*\/\([^/][^/]*\)\/*$/{
+           s//\1/
+           q
+         }
+         /^X\/\(\/\/\)$/{
+           s//\1/
+           q
+         }
+         /^X\/\(\/\).*/{
+           s//\1/
+           q
+         }
+         s/.*/./; q'`
+
+# CDPATH.
+$as_unset CDPATH
+
+
+
+  as_lineno_1=$LINENO
+  as_lineno_2=$LINENO
+  test "x$as_lineno_1" != "x$as_lineno_2" &&
+  test "x`expr $as_lineno_1 + 1`" = "x$as_lineno_2" || {
+
+  # Create $as_me.lineno as a copy of $as_myself, but with $LINENO
+  # uniformly replaced by the line number.  The first 'sed' inserts a
+  # line-number line after each line using $LINENO; the second 'sed'
+  # does the real work.  The second script uses 'N' to pair each
+  # line-number line with the line containing $LINENO, and appends
+  # trailing '-' during substitution so that $LINENO is not a special
+  # case at line end.
+  # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the
+  # scripts with optimization help from Paolo Bonzini.  Blame Lee
+  # E. McMahon (1931-1989) for sed's syntax.  :-)
+  sed -n '
+    p
+    /[$]LINENO/=
+  ' <$as_myself |
+    sed '
+      s/[$]LINENO.*/&-/
+      t lineno
+      b
+      :lineno
+      N
+      :loop
+      s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/
+      t loop
+      s/-\n.*//
+    ' >$as_me.lineno &&
+  chmod +x "$as_me.lineno" ||
+    { echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2
+   { (exit 1); exit 1; }; }
+
+  # Don't try to exec as it changes $[0], causing all sort of problems
+  # (the dirname of $[0] is not the place where we might find the
+  # original and so on.  Autoconf is especially sensitive to this).
+  . "./$as_me.lineno"
+  # Exit status is that of the last command.
+  exit
+}
+
+
+if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
+  as_dirname=dirname
+else
+  as_dirname=false
+fi
+
+ECHO_C= ECHO_N= ECHO_T=
+case `echo -n x` in
+-n*)
+  case `echo 'x\c'` in
+  *c*) ECHO_T='        ';;     # ECHO_T is single tab character.
+  *)   ECHO_C='\c';;
+  esac;;
+*)
+  ECHO_N='-n';;
+esac
+
+if expr a : '\(a\)' >/dev/null 2>&1 &&
+   test "X`expr 00001 : '.*\(...\)'`" = X001; then
+  as_expr=expr
+else
+  as_expr=false
+fi
+
+rm -f conf$$ conf$$.exe conf$$.file
+if test -d conf$$.dir; then
+  rm -f conf$$.dir/conf$$.file
+else
+  rm -f conf$$.dir
+  mkdir conf$$.dir
+fi
+echo >conf$$.file
+if ln -s conf$$.file conf$$ 2>/dev/null; then
+  as_ln_s='ln -s'
+  # ... but there are two gotchas:
+  # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
+  # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
+  # In both cases, we have to default to `cp -p'.
+  ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
+    as_ln_s='cp -p'
+elif ln conf$$.file conf$$ 2>/dev/null; then
+  as_ln_s=ln
+else
+  as_ln_s='cp -p'
+fi
+rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
+rmdir conf$$.dir 2>/dev/null
+
+if mkdir -p . 2>/dev/null; then
+  as_mkdir_p=:
+else
+  test -d ./-p && rmdir ./-p
+  as_mkdir_p=false
+fi
+
+if test -x / >/dev/null 2>&1; then
+  as_test_x='test -x'
+else
+  if ls -dL / >/dev/null 2>&1; then
+    as_ls_L_option=L
+  else
+    as_ls_L_option=
+  fi
+  as_test_x='
+    eval sh -c '\''
+      if test -d "$1"; then
+        test -d "$1/.";
+      else
+       case $1 in
+        -*)set "./$1";;
+       esac;
+       case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in
+       ???[sx]*):;;*)false;;esac;fi
+    '\'' sh
+  '
+fi
+as_executable_p=$as_test_x
+
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
+
+# Sed expression to map a string onto a valid variable name.
+as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
+
+
+exec 6>&1
+
+# Save the log message, to keep $[0] and so on meaningful, and to
+# report actual input values of CONFIG_FILES etc. instead of their
+# values after options handling.
+ac_log="
+This file was extended by $as_me, which was
+generated by GNU Autoconf 2.61.  Invocation command line was
+
+  CONFIG_FILES    = $CONFIG_FILES
+  CONFIG_HEADERS  = $CONFIG_HEADERS
+  CONFIG_LINKS    = $CONFIG_LINKS
+  CONFIG_COMMANDS = $CONFIG_COMMANDS
+  $ $0 $@
+
+on `(hostname || uname -n) 2>/dev/null | sed 1q`
+"
+
+_ACEOF
+
+cat >>$CONFIG_STATUS <<_ACEOF
+# Files that config.status was made for.
+config_files="$ac_config_files"
+config_headers="$ac_config_headers"
+config_commands="$ac_config_commands"
+
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF
+ac_cs_usage="\
+\`$as_me' instantiates files from templates according to the
+current configuration.
+
+Usage: $0 [OPTIONS] [FILE]...
+
+  -h, --help       print this help, then exit
+  -V, --version    print version number and configuration settings, then exit
+  -q, --quiet      do not print progress messages
+  -d, --debug      don't remove temporary files
+      --recheck    update $as_me by reconfiguring in the same conditions
+  --file=FILE[:TEMPLATE]
+                  instantiate the configuration file FILE
+  --header=FILE[:TEMPLATE]
+                  instantiate the configuration header FILE
+
+Configuration files:
+$config_files
+
+Configuration headers:
+$config_headers
+
+Configuration commands:
+$config_commands
+
+Report bugs to <bug-autoconf@gnu.org>."
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF
+ac_cs_version="\\
+config.status
+configured by $0, generated by GNU Autoconf 2.61,
+  with options \\"`echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`\\"
+
+Copyright (C) 2006 Free Software Foundation, Inc.
+This config.status script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it."
+
+ac_pwd='$ac_pwd'
+srcdir='$srcdir'
+INSTALL='$INSTALL'
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF
+# If no file are specified by the user, then we need to provide default
+# value.  By we need to know if files were specified by the user.
+ac_need_defaults=:
+while test $# != 0
+do
+  case $1 in
+  --*=*)
+    ac_option=`expr "X$1" : 'X\([^=]*\)='`
+    ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'`
+    ac_shift=:
+    ;;
+  *)
+    ac_option=$1
+    ac_optarg=$2
+    ac_shift=shift
+    ;;
+  esac
+
+  case $ac_option in
+  # Handling of the options.
+  -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
+    ac_cs_recheck=: ;;
+  --version | --versio | --versi | --vers | --ver | --ve | --v | -V )
+    echo "$ac_cs_version"; exit ;;
+  --debug | --debu | --deb | --de | --d | -d )
+    debug=: ;;
+  --file | --fil | --fi | --f )
+    $ac_shift
+    CONFIG_FILES="$CONFIG_FILES $ac_optarg"
+    ac_need_defaults=false;;
+  --header | --heade | --head | --hea )
+    $ac_shift
+    CONFIG_HEADERS="$CONFIG_HEADERS $ac_optarg"
+    ac_need_defaults=false;;
+  --he | --h)
+    # Conflict between --help and --header
+    { echo "$as_me: error: ambiguous option: $1
+Try \`$0 --help' for more information." >&2
+   { (exit 1); exit 1; }; };;
+  --help | --hel | -h )
+    echo "$ac_cs_usage"; exit ;;
+  -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+  | -silent | --silent | --silen | --sile | --sil | --si | --s)
+    ac_cs_silent=: ;;
+
+  # This is an error.
+  -*) { echo "$as_me: error: unrecognized option: $1
+Try \`$0 --help' for more information." >&2
+   { (exit 1); exit 1; }; } ;;
+
+  *) ac_config_targets="$ac_config_targets $1"
+     ac_need_defaults=false ;;
+
+  esac
+  shift
+done
+
+ac_configure_extra_args=
+
+if $ac_cs_silent; then
+  exec 6>/dev/null
+  ac_configure_extra_args="$ac_configure_extra_args --silent"
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF
+if \$ac_cs_recheck; then
+  echo "running CONFIG_SHELL=$SHELL $SHELL $0 "$ac_configure_args \$ac_configure_extra_args " --no-create --no-recursion" >&6
+  CONFIG_SHELL=$SHELL
+  export CONFIG_SHELL
+  exec $SHELL "$0"$ac_configure_args \$ac_configure_extra_args --no-create --no-recursion
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF
+exec 5>>config.log
+{
+  echo
+  sed 'h;s/./-/g;s/^.../@%:@@%:@ /;s/...$/ @%:@@%:@/;p;x;p;x' <<_ASBOX
+@%:@@%:@ Running $as_me. @%:@@%:@
+_ASBOX
+  echo "$ac_log"
+} >&5
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF
+
+# Handling of arguments.
+for ac_config_target in $ac_config_targets
+do
+  case $ac_config_target in
+    "config.h") CONFIG_HEADERS="$CONFIG_HEADERS config.h" ;;
+    "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;;
+    "ircd/Makefile") CONFIG_FILES="$CONFIG_FILES ircd/Makefile" ;;
+    "doc/Makefile") CONFIG_FILES="$CONFIG_FILES doc/Makefile" ;;
+    "default") CONFIG_COMMANDS="$CONFIG_COMMANDS default" ;;
+
+  *) { { echo "$as_me:$LINENO: error: invalid argument: $ac_config_target" >&5
+echo "$as_me: error: invalid argument: $ac_config_target" >&2;}
+   { (exit 1); exit 1; }; };;
+  esac
+done
+
+
+# If the user did not use the arguments to specify the items to instantiate,
+# then the envvar interface is used.  Set only those that are not.
+# We use the long form for the default assignment because of an extremely
+# bizarre bug on SunOS 4.1.3.
+if $ac_need_defaults; then
+  test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files
+  test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers
+  test "${CONFIG_COMMANDS+set}" = set || CONFIG_COMMANDS=$config_commands
+fi
+
+# Have a temporary directory for convenience.  Make it in the build tree
+# simply because there is no reason against having it here, and in addition,
+# creating and moving files from /tmp can sometimes cause problems.
+# Hook for its removal unless debugging.
+# Note that there is a small window in which the directory will not be cleaned:
+# after its creation but before its name has been assigned to `$tmp'.
+$debug ||
+{
+  tmp=
+  trap 'exit_status=$?
+  { test -z "$tmp" || test ! -d "$tmp" || rm -fr "$tmp"; } && exit $exit_status
+' 0
+  trap '{ (exit 1); exit 1; }' 1 2 13 15
+}
+# Create a (secure) tmp directory for tmp files.
+
+{
+  tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` &&
+  test -n "$tmp" && test -d "$tmp"
+}  ||
+{
+  tmp=./conf$$-$RANDOM
+  (umask 077 && mkdir "$tmp")
+} ||
+{
+   echo "$me: cannot create a temporary directory in ." >&2
+   { (exit 1); exit 1; }
+}
+
+#
+# Set up the sed scripts for CONFIG_FILES section.
+#
+
+# No need to generate the scripts if there are no CONFIG_FILES.
+# This happens for instance when ./config.status config.h
+if test -n "$CONFIG_FILES"; then
+
+_ACEOF
+
+
+
+ac_delim='%!_!# '
+for ac_last_try in false false false false false :; do
+  cat >conf$$subs.sed <<_ACEOF
+SHELL!$SHELL$ac_delim
+PATH_SEPARATOR!$PATH_SEPARATOR$ac_delim
+PACKAGE_NAME!$PACKAGE_NAME$ac_delim
+PACKAGE_TARNAME!$PACKAGE_TARNAME$ac_delim
+PACKAGE_VERSION!$PACKAGE_VERSION$ac_delim
+PACKAGE_STRING!$PACKAGE_STRING$ac_delim
+PACKAGE_BUGREPORT!$PACKAGE_BUGREPORT$ac_delim
+exec_prefix!$exec_prefix$ac_delim
+prefix!$prefix$ac_delim
+program_transform_name!$program_transform_name$ac_delim
+bindir!$bindir$ac_delim
+sbindir!$sbindir$ac_delim
+libexecdir!$libexecdir$ac_delim
+datarootdir!$datarootdir$ac_delim
+datadir!$datadir$ac_delim
+sysconfdir!$sysconfdir$ac_delim
+sharedstatedir!$sharedstatedir$ac_delim
+localstatedir!$localstatedir$ac_delim
+includedir!$includedir$ac_delim
+oldincludedir!$oldincludedir$ac_delim
+docdir!$docdir$ac_delim
+infodir!$infodir$ac_delim
+htmldir!$htmldir$ac_delim
+dvidir!$dvidir$ac_delim
+pdfdir!$pdfdir$ac_delim
+psdir!$psdir$ac_delim
+libdir!$libdir$ac_delim
+localedir!$localedir$ac_delim
+mandir!$mandir$ac_delim
+DEFS!$DEFS$ac_delim
+ECHO_C!$ECHO_C$ac_delim
+ECHO_N!$ECHO_N$ac_delim
+ECHO_T!$ECHO_T$ac_delim
+LIBS!$LIBS$ac_delim
+build_alias!$build_alias$ac_delim
+host_alias!$host_alias$ac_delim
+target_alias!$target_alias$ac_delim
+build!$build$ac_delim
+build_cpu!$build_cpu$ac_delim
+build_vendor!$build_vendor$ac_delim
+build_os!$build_os$ac_delim
+host!$host$ac_delim
+host_cpu!$host_cpu$ac_delim
+host_vendor!$host_vendor$ac_delim
+host_os!$host_os$ac_delim
+CC!$CC$ac_delim
+CFLAGS!$CFLAGS$ac_delim
+LDFLAGS!$LDFLAGS$ac_delim
+CPPFLAGS!$CPPFLAGS$ac_delim
+ac_ct_CC!$ac_ct_CC$ac_delim
+EXEEXT!$EXEEXT$ac_delim
+OBJEXT!$OBJEXT$ac_delim
+CPP!$CPP$ac_delim
+GREP!$GREP$ac_delim
+EGREP!$EGREP$ac_delim
+AWK!$AWK$ac_delim
+SET_MAKE!$SET_MAKE$ac_delim
+INSTALL_PROGRAM!$INSTALL_PROGRAM$ac_delim
+INSTALL_SCRIPT!$INSTALL_SCRIPT$ac_delim
+INSTALL_DATA!$INSTALL_DATA$ac_delim
+LN_S!$LN_S$ac_delim
+RMPROG!$RMPROG$ac_delim
+SHPROG!$SHPROG$ac_delim
+LEX!$LEX$ac_delim
+LEX_OUTPUT_ROOT!$LEX_OUTPUT_ROOT$ac_delim
+LEXLIB!$LEXLIB$ac_delim
+YACC!$YACC$ac_delim
+YFLAGS!$YFLAGS$ac_delim
+ENGINE_C!$ENGINE_C$ac_delim
+INSTALL_RULE!$INSTALL_RULE$ac_delim
+SYMLINK!$SYMLINK$ac_delim
+IRCDMODE!$IRCDMODE$ac_delim
+IRCDOWN!$IRCDOWN$ac_delim
+IRCDGRP!$IRCDGRP$ac_delim
+DPATH!$DPATH$ac_delim
+LIB@&t@OBJS!$LIB@&t@OBJS$ac_delim
+LTLIBOBJS!$LTLIBOBJS$ac_delim
+_ACEOF
+
+  if test `sed -n "s/.*$ac_delim\$/X/p" conf$$subs.sed | grep -c X` = 77; then
+    break
+  elif $ac_last_try; then
+    { { echo "$as_me:$LINENO: error: could not make $CONFIG_STATUS" >&5
+echo "$as_me: error: could not make $CONFIG_STATUS" >&2;}
+   { (exit 1); exit 1; }; }
+  else
+    ac_delim="$ac_delim!$ac_delim _$ac_delim!! "
+  fi
+done
+
+ac_eof=`sed -n '/^CEOF[0-9]*$/s/CEOF/0/p' conf$$subs.sed`
+if test -n "$ac_eof"; then
+  ac_eof=`echo "$ac_eof" | sort -nru | sed 1q`
+  ac_eof=`expr $ac_eof + 1`
+fi
+
+cat >>$CONFIG_STATUS <<_ACEOF
+cat >"\$tmp/subs-1.sed" <<\CEOF$ac_eof
+/@[a-zA-Z_][a-zA-Z_0-9]*@/!b end
+_ACEOF
+sed '
+s/[,\\&]/\\&/g; s/@/@|#_!!_#|/g
+s/^/s,@/; s/!/@,|#_!!_#|/
+:n
+t n
+s/'"$ac_delim"'$/,g/; t
+s/$/\\/; p
+N; s/^.*\n//; s/[,\\&]/\\&/g; s/@/@|#_!!_#|/g; b n
+' >>$CONFIG_STATUS <conf$$subs.sed
+rm -f conf$$subs.sed
+cat >>$CONFIG_STATUS <<_ACEOF
+:end
+s/|#_!!_#|//g
+CEOF$ac_eof
+_ACEOF
+
+
+# VPATH may cause trouble with some makes, so we remove $(srcdir),
+# ${srcdir} and @srcdir@ from VPATH if srcdir is ".", strip leading and
+# trailing colons and then remove the whole line if VPATH becomes empty
+# (actually we leave an empty line to preserve line numbers).
+if test "x$srcdir" = x.; then
+  ac_vpsub='/^[         ]*VPATH[        ]*=/{
+s/:*\$(srcdir):*/:/
+s/:*\${srcdir}:*/:/
+s/:*@srcdir@:*/:/
+s/^\([^=]*=[    ]*\):*/\1/
+s/:*$//
+s/^[^=]*=[      ]*$//
+}'
+fi
+
+cat >>$CONFIG_STATUS <<\_ACEOF
+fi # test -n "$CONFIG_FILES"
+
+
+for ac_tag in  :F $CONFIG_FILES  :H $CONFIG_HEADERS    :C $CONFIG_COMMANDS
+do
+  case $ac_tag in
+  :[FHLC]) ac_mode=$ac_tag; continue;;
+  esac
+  case $ac_mode$ac_tag in
+  :[FHL]*:*);;
+  :L* | :C*:*) { { echo "$as_me:$LINENO: error: Invalid tag $ac_tag." >&5
+echo "$as_me: error: Invalid tag $ac_tag." >&2;}
+   { (exit 1); exit 1; }; };;
+  :[FH]-) ac_tag=-:-;;
+  :[FH]*) ac_tag=$ac_tag:$ac_tag.in;;
+  esac
+  ac_save_IFS=$IFS
+  IFS=:
+  set x $ac_tag
+  IFS=$ac_save_IFS
+  shift
+  ac_file=$1
+  shift
+
+  case $ac_mode in
+  :L) ac_source=$1;;
+  :[FH])
+    ac_file_inputs=
+    for ac_f
+    do
+      case $ac_f in
+      -) ac_f="$tmp/stdin";;
+      *) # Look for the file first in the build tree, then in the source tree
+        # (if the path is not absolute).  The absolute path cannot be DOS-style,
+        # because $ac_f cannot contain `:'.
+        test -f "$ac_f" ||
+          case $ac_f in
+          [\\/$]*) false;;
+          *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";;
+          esac ||
+          { { echo "$as_me:$LINENO: error: cannot find input file: $ac_f" >&5
+echo "$as_me: error: cannot find input file: $ac_f" >&2;}
+   { (exit 1); exit 1; }; };;
+      esac
+      ac_file_inputs="$ac_file_inputs $ac_f"
+    done
+
+    # Let's still pretend it is `configure' which instantiates (i.e., don't
+    # use $as_me), people would be surprised to read:
+    #    /* config.h.  Generated by config.status.  */
+    configure_input="Generated from "`IFS=:
+         echo $* | sed 's|^[^:]*/||;s|:[^:]*/|, |g'`" by configure."
+    if test x"$ac_file" != x-; then
+      configure_input="$ac_file.  $configure_input"
+      { echo "$as_me:$LINENO: creating $ac_file" >&5
+echo "$as_me: creating $ac_file" >&6;}
+    fi
+
+    case $ac_tag in
+    *:-:* | *:-) cat >"$tmp/stdin";;
+    esac
+    ;;
+  esac
+
+  ac_dir=`$as_dirname -- "$ac_file" ||
+$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+        X"$ac_file" : 'X\(//\)[^/]' \| \
+        X"$ac_file" : 'X\(//\)$' \| \
+        X"$ac_file" : 'X\(/\)' \| . 2>/dev/null ||
+echo X"$ac_file" |
+    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+           s//\1/
+           q
+         }
+         /^X\(\/\/\)[^/].*/{
+           s//\1/
+           q
+         }
+         /^X\(\/\/\)$/{
+           s//\1/
+           q
+         }
+         /^X\(\/\).*/{
+           s//\1/
+           q
+         }
+         s/.*/./; q'`
+  { as_dir="$ac_dir"
+  case $as_dir in #(
+  -*) as_dir=./$as_dir;;
+  esac
+  test -d "$as_dir" || { $as_mkdir_p && mkdir -p "$as_dir"; } || {
+    as_dirs=
+    while :; do
+      case $as_dir in #(
+      *\'*) as_qdir=`echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #(
+      *) as_qdir=$as_dir;;
+      esac
+      as_dirs="'$as_qdir' $as_dirs"
+      as_dir=`$as_dirname -- "$as_dir" ||
+$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+        X"$as_dir" : 'X\(//\)[^/]' \| \
+        X"$as_dir" : 'X\(//\)$' \| \
+        X"$as_dir" : 'X\(/\)' \| . 2>/dev/null ||
+echo X"$as_dir" |
+    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+           s//\1/
+           q
+         }
+         /^X\(\/\/\)[^/].*/{
+           s//\1/
+           q
+         }
+         /^X\(\/\/\)$/{
+           s//\1/
+           q
+         }
+         /^X\(\/\).*/{
+           s//\1/
+           q
+         }
+         s/.*/./; q'`
+      test -d "$as_dir" && break
+    done
+    test -z "$as_dirs" || eval "mkdir $as_dirs"
+  } || test -d "$as_dir" || { { echo "$as_me:$LINENO: error: cannot create directory $as_dir" >&5
+echo "$as_me: error: cannot create directory $as_dir" >&2;}
+   { (exit 1); exit 1; }; }; }
+  ac_builddir=.
+
+case "$ac_dir" in
+.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
+*)
+  ac_dir_suffix=/`echo "$ac_dir" | sed 's,^\.[\\/],,'`
+  # A ".." for each directory in $ac_dir_suffix.
+  ac_top_builddir_sub=`echo "$ac_dir_suffix" | sed 's,/[^\\/]*,/..,g;s,/,,'`
+  case $ac_top_builddir_sub in
+  "") ac_top_builddir_sub=. ac_top_build_prefix= ;;
+  *)  ac_top_build_prefix=$ac_top_builddir_sub/ ;;
+  esac ;;
+esac
+ac_abs_top_builddir=$ac_pwd
+ac_abs_builddir=$ac_pwd$ac_dir_suffix
+# for backward compatibility:
+ac_top_builddir=$ac_top_build_prefix
+
+case $srcdir in
+  .)  # We are building in place.
+    ac_srcdir=.
+    ac_top_srcdir=$ac_top_builddir_sub
+    ac_abs_top_srcdir=$ac_pwd ;;
+  [\\/]* | ?:[\\/]* )  # Absolute name.
+    ac_srcdir=$srcdir$ac_dir_suffix;
+    ac_top_srcdir=$srcdir
+    ac_abs_top_srcdir=$srcdir ;;
+  *) # Relative name.
+    ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix
+    ac_top_srcdir=$ac_top_build_prefix$srcdir
+    ac_abs_top_srcdir=$ac_pwd/$srcdir ;;
+esac
+ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix
+
+
+  case $ac_mode in
+  :F)
+  #
+  # CONFIG_FILE
+  #
+
+  case $INSTALL in
+  [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;;
+  *) ac_INSTALL=$ac_top_build_prefix$INSTALL ;;
+  esac
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF
+# If the template does not know about datarootdir, expand it.
+# FIXME: This hack should be removed a few years after 2.60.
+ac_datarootdir_hack=; ac_datarootdir_seen=
+
+case `sed -n '/datarootdir/ {
+  p
+  q
+}
+/@datadir@/p
+/@docdir@/p
+/@infodir@/p
+/@localedir@/p
+/@mandir@/p
+' $ac_file_inputs` in
+*datarootdir*) ac_datarootdir_seen=yes;;
+*@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*)
+  { echo "$as_me:$LINENO: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5
+echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;}
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF
+  ac_datarootdir_hack='
+  s&@datadir@&$datadir&g
+  s&@docdir@&$docdir&g
+  s&@infodir@&$infodir&g
+  s&@localedir@&$localedir&g
+  s&@mandir@&$mandir&g
+    s&\\\${datarootdir}&$datarootdir&g' ;;
+esac
+_ACEOF
+
+# Neutralize VPATH when `$srcdir' = `.'.
+# Shell code in configure.ac might set extrasub.
+# FIXME: do we really want to maintain this feature?
+cat >>$CONFIG_STATUS <<_ACEOF
+  sed "$ac_vpsub
+$extrasub
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF
+:t
+/@[a-zA-Z_][a-zA-Z_0-9]*@/!b
+s&@configure_input@&$configure_input&;t t
+s&@top_builddir@&$ac_top_builddir_sub&;t t
+s&@srcdir@&$ac_srcdir&;t t
+s&@abs_srcdir@&$ac_abs_srcdir&;t t
+s&@top_srcdir@&$ac_top_srcdir&;t t
+s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t
+s&@builddir@&$ac_builddir&;t t
+s&@abs_builddir@&$ac_abs_builddir&;t t
+s&@abs_top_builddir@&$ac_abs_top_builddir&;t t
+s&@INSTALL@&$ac_INSTALL&;t t
+$ac_datarootdir_hack
+" $ac_file_inputs | sed -f "$tmp/subs-1.sed" >$tmp/out
+
+test -z "$ac_datarootdir_hack$ac_datarootdir_seen" &&
+  { ac_out=`sed -n '/\${datarootdir}/p' "$tmp/out"`; test -n "$ac_out"; } &&
+  { ac_out=`sed -n '/^[         ]*datarootdir[  ]*:*=/p' "$tmp/out"`; test -z "$ac_out"; } &&
+  { echo "$as_me:$LINENO: WARNING: $ac_file contains a reference to the variable \`datarootdir'
+which seems to be undefined.  Please make sure it is defined." >&5
+echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir'
+which seems to be undefined.  Please make sure it is defined." >&2;}
+
+  rm -f "$tmp/stdin"
+  case $ac_file in
+  -) cat "$tmp/out"; rm -f "$tmp/out";;
+  *) rm -f "$ac_file"; mv "$tmp/out" $ac_file;;
+  esac
+ ;;
+  :H)
+  #
+  # CONFIG_HEADER
+  #
+_ACEOF
+
+# Transform confdefs.h into a sed script `conftest.defines', that
+# substitutes the proper values into config.h.in to produce config.h.
+rm -f conftest.defines conftest.tail
+# First, append a space to every undef/define line, to ease matching.
+echo 's/$/ /' >conftest.defines
+# Then, protect against being on the right side of a sed subst, or in
+# an unquoted here document, in config.status.  If some macros were
+# called several times there might be several #defines for the same
+# symbol, which is useless.  But do not sort them, since the last
+# AC_DEFINE must be honored.
+ac_word_re=[_$as_cr_Letters][_$as_cr_alnum]*
+# These sed commands are passed to sed as "A NAME B PARAMS C VALUE D", where
+# NAME is the cpp macro being defined, VALUE is the value it is being given.
+# PARAMS is the parameter list in the macro definition--in most cases, it's
+# just an empty string.
+ac_dA='s,^\\([  #]*\\)[^        ]*\\([  ]*'
+ac_dB='\\)[     (].*,\\1define\\2'
+ac_dC=' '
+ac_dD=' ,'
+
+uniq confdefs.h |
+  sed -n '
+       t rset
+       :rset
+       s/^[     ]*#[    ]*define[       ][      ]*//
+       t ok
+       d
+       :ok
+       s/[\\&,]/\\&/g
+       s/^\('"$ac_word_re"'\)\(([^()]*)\)[      ]*\(.*\)/ '"$ac_dA"'\1'"$ac_dB"'\2'"${ac_dC}"'\3'"$ac_dD"'/p
+       s/^\('"$ac_word_re"'\)[  ]*\(.*\)/'"$ac_dA"'\1'"$ac_dB$ac_dC"'\2'"$ac_dD"'/p
+  ' >>conftest.defines
+
+# Remove the space that was appended to ease matching.
+# Then replace #undef with comments.  This is necessary, for
+# example, in the case of _POSIX_SOURCE, which is predefined and required
+# on some systems where configure will not decide to define it.
+# (The regexp can be short, since the line contains either #define or #undef.)
+echo 's/ $//
+s,^[    #]*u.*,/* & */,' >>conftest.defines
+
+# Break up conftest.defines:
+ac_max_sed_lines=50
+
+# First sed command is:         sed -f defines.sed $ac_file_inputs >"$tmp/out1"
+# Second one is:        sed -f defines.sed "$tmp/out1" >"$tmp/out2"
+# Third one will be:    sed -f defines.sed "$tmp/out2" >"$tmp/out1"
+# et cetera.
+ac_in='$ac_file_inputs'
+ac_out='"$tmp/out1"'
+ac_nxt='"$tmp/out2"'
+
+while :
+do
+  # Write a here document:
+    cat >>$CONFIG_STATUS <<_ACEOF
+    # First, check the format of the line:
+    cat >"\$tmp/defines.sed" <<\\CEOF
+/^[     ]*#[    ]*undef[        ][      ]*$ac_word_re[  ]*\$/b def
+/^[     ]*#[    ]*define[       ][      ]*$ac_word_re[(         ]/b def
+b
+:def
+_ACEOF
+  sed ${ac_max_sed_lines}q conftest.defines >>$CONFIG_STATUS
+  echo 'CEOF
+    sed -f "$tmp/defines.sed"' "$ac_in >$ac_out" >>$CONFIG_STATUS
+  ac_in=$ac_out; ac_out=$ac_nxt; ac_nxt=$ac_in
+  sed 1,${ac_max_sed_lines}d conftest.defines >conftest.tail
+  grep . conftest.tail >/dev/null || break
+  rm -f conftest.defines
+  mv conftest.tail conftest.defines
+done
+rm -f conftest.defines conftest.tail
+
+echo "ac_result=$ac_in" >>$CONFIG_STATUS
+cat >>$CONFIG_STATUS <<\_ACEOF
+  if test x"$ac_file" != x-; then
+    echo "/* $configure_input  */" >"$tmp/config.h"
+    cat "$ac_result" >>"$tmp/config.h"
+    if diff $ac_file "$tmp/config.h" >/dev/null 2>&1; then
+      { echo "$as_me:$LINENO: $ac_file is unchanged" >&5
+echo "$as_me: $ac_file is unchanged" >&6;}
+    else
+      rm -f $ac_file
+      mv "$tmp/config.h" $ac_file
+    fi
+  else
+    echo "/* $configure_input  */"
+    cat "$ac_result"
+  fi
+  rm -f "$tmp/out12"
+ ;;
+  
+  :C)  { echo "$as_me:$LINENO: executing $ac_file commands" >&5
+echo "$as_me: executing $ac_file commands" >&6;}
+ ;;
+  esac
+
+
+  case $ac_file$ac_mode in
+    "default":C) echo timestamp > stamp-h ;;
+
+  esac
+done # for ac_tag
+
+
+{ (exit 0); exit 0; }
+_ACEOF
+chmod +x $CONFIG_STATUS
+ac_clean_files=$ac_clean_files_save
+
+
+# configure is writing to config.log, and then calls config.status.
+# config.status does its own redirection, appending to config.log.
+# Unfortunately, on DOS this fails, as config.log is still kept open
+# by configure, so config.status won't be able to write to it; its
+# output is simply discarded.  So we exec the FD to /dev/null,
+# effectively closing config.log, so it can be properly (re)opened and
+# appended to by config.status.  When coming back to configure, we
+# need to make the FD available again.
+if test "$no_create" != yes; then
+  ac_cs_success=:
+  ac_config_status_args=
+  test "$silent" = yes &&
+    ac_config_status_args="$ac_config_status_args --quiet"
+  exec 5>/dev/null
+  $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false
+  exec 5>>config.log
+  # Use ||, not &&, to avoid exiting from the if with $? = 1, which
+  # would make configure fail if this is the last instruction.
+  $ac_cs_success || { (exit 1); exit 1; }
+fi
+
+
+{ echo "$as_me:$LINENO: result: 
+ircu is now hopefully configured for your system.
+
+  Host system:         $host_os
+  Prefix:              $prefix
+  Asserts:             $unet_cv_enable_asserts
+  Warnings:            $unet_cv_enable_warnings
+  Debug:               $unet_cv_enable_debug
+  Profile:             $unet_cv_enable_profile
+  Owner/mode:          $unet_cv_with_owner.$unet_cv_with_group ($unet_cv_with_mode)
+  Chroot:              $unet_cv_with_chroot
+  OpenSSL:             $unet_cv_enable_openssl
+  GnuTLS:              $unet_cv_enable_gnutls
+  Compatibility mode:  $unet_cv_enable_compat
+  Unstable features:   $unet_cv_enable_unstable
+
+  Domain:              $unet_cv_with_domain
+  DPath:               $unet_cv_with_dpath
+  CPath:               $unet_cv_with_cpath
+  LPath:               $unet_cv_with_lpath
+  Maximum connections: $unet_cv_with_maxcon
+
+  poll() engine:       $unet_cv_enable_poll
+  kqueue() engine:     $unet_cv_enable_kqueue
+  /dev/poll engine:    $unet_cv_enable_devpoll
+  epoll() engine:      $unet_cv_enable_epoll
+" >&5
+echo "${ECHO_T}
+ircu is now hopefully configured for your system.
+
+  Host system:         $host_os
+  Prefix:              $prefix
+  Asserts:             $unet_cv_enable_asserts
+  Warnings:            $unet_cv_enable_warnings
+  Debug:               $unet_cv_enable_debug
+  Profile:             $unet_cv_enable_profile
+  Owner/mode:          $unet_cv_with_owner.$unet_cv_with_group ($unet_cv_with_mode)
+  Chroot:              $unet_cv_with_chroot
+  OpenSSL:             $unet_cv_enable_openssl
+  GnuTLS:              $unet_cv_enable_gnutls
+  Compatibility mode:  $unet_cv_enable_compat
+  Unstable features:   $unet_cv_enable_unstable
+
+  Domain:              $unet_cv_with_domain
+  DPath:               $unet_cv_with_dpath
+  CPath:               $unet_cv_with_cpath
+  LPath:               $unet_cv_with_lpath
+  Maximum connections: $unet_cv_with_maxcon
+
+  poll() engine:       $unet_cv_enable_poll
+  kqueue() engine:     $unet_cv_enable_kqueue
+  /dev/poll engine:    $unet_cv_enable_devpoll
+  epoll() engine:      $unet_cv_enable_epoll
+" >&6; }
diff --git a/autom4te.cache/output.1 b/autom4te.cache/output.1
new file mode 100644 (file)
index 0000000..d6a2ace
--- /dev/null
@@ -0,0 +1,12623 @@
+@%:@! /bin/sh
+@%:@ Guess values for system-dependent variables and create Makefiles.
+@%:@ Generated by GNU Autoconf 2.61.
+@%:@ 
+@%:@ Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001,
+@%:@ 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
+@%:@ This configure script is free software; the Free Software Foundation
+@%:@ gives unlimited permission to copy, distribute and modify it.
+## --------------------- ##
+## M4sh Initialization.  ##
+## --------------------- ##
+
+# Be more Bourne compatible
+DUALCASE=1; export DUALCASE # for MKS sh
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then
+  emulate sh
+  NULLCMD=:
+  # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which
+  # is contrary to our usage.  Disable this feature.
+  alias -g '${1+"$@"}'='"$@"'
+  setopt NO_GLOB_SUBST
+else
+  case `(set -o) 2>/dev/null` in
+  *posix*) set -o posix ;;
+esac
+
+fi
+
+
+
+
+# PATH needs CR
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+  echo "#! /bin/sh" >conf$$.sh
+  echo  "exit 0"   >>conf$$.sh
+  chmod +x conf$$.sh
+  if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then
+    PATH_SEPARATOR=';'
+  else
+    PATH_SEPARATOR=:
+  fi
+  rm -f conf$$.sh
+fi
+
+# Support unset when possible.
+if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then
+  as_unset=unset
+else
+  as_unset=false
+fi
+
+
+# IFS
+# We need space, tab and new line, in precisely that order.  Quoting is
+# there to prevent editors from complaining about space-tab.
+# (If _AS_PATH_WALK were called with IFS unset, it would disable word
+# splitting by setting IFS to empty value.)
+as_nl='
+'
+IFS=" ""       $as_nl"
+
+# Find who we are.  Look in the path if we contain no directory separator.
+case $0 in
+  *[\\/]* ) as_myself=$0 ;;
+  *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+done
+IFS=$as_save_IFS
+
+     ;;
+esac
+# We did not find ourselves, most probably we were run as `sh COMMAND'
+# in which case we are not to be found in the path.
+if test "x$as_myself" = x; then
+  as_myself=$0
+fi
+if test ! -f "$as_myself"; then
+  echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
+  { (exit 1); exit 1; }
+fi
+
+# Work around bugs in pre-3.0 UWIN ksh.
+for as_var in ENV MAIL MAILPATH
+do ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var
+done
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+for as_var in \
+  LANG LANGUAGE LC_ADDRESS LC_ALL LC_COLLATE LC_CTYPE LC_IDENTIFICATION \
+  LC_MEASUREMENT LC_MESSAGES LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER \
+  LC_TELEPHONE LC_TIME
+do
+  if (set +x; test -z "`(eval $as_var=C; export $as_var) 2>&1`"); then
+    eval $as_var=C; export $as_var
+  else
+    ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var
+  fi
+done
+
+# Required to use basename.
+if expr a : '\(a\)' >/dev/null 2>&1 &&
+   test "X`expr 00001 : '.*\(...\)'`" = X001; then
+  as_expr=expr
+else
+  as_expr=false
+fi
+
+if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then
+  as_basename=basename
+else
+  as_basename=false
+fi
+
+
+# Name of the executable.
+as_me=`$as_basename -- "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+        X"$0" : 'X\(//\)$' \| \
+        X"$0" : 'X\(/\)' \| . 2>/dev/null ||
+echo X/"$0" |
+    sed '/^.*\/\([^/][^/]*\)\/*$/{
+           s//\1/
+           q
+         }
+         /^X\/\(\/\/\)$/{
+           s//\1/
+           q
+         }
+         /^X\/\(\/\).*/{
+           s//\1/
+           q
+         }
+         s/.*/./; q'`
+
+# CDPATH.
+$as_unset CDPATH
+
+
+if test "x$CONFIG_SHELL" = x; then
+  if (eval ":") 2>/dev/null; then
+  as_have_required=yes
+else
+  as_have_required=no
+fi
+
+  if test $as_have_required = yes &&    (eval ":
+(as_func_return () {
+  (exit \$1)
+}
+as_func_success () {
+  as_func_return 0
+}
+as_func_failure () {
+  as_func_return 1
+}
+as_func_ret_success () {
+  return 0
+}
+as_func_ret_failure () {
+  return 1
+}
+
+exitcode=0
+if as_func_success; then
+  :
+else
+  exitcode=1
+  echo as_func_success failed.
+fi
+
+if as_func_failure; then
+  exitcode=1
+  echo as_func_failure succeeded.
+fi
+
+if as_func_ret_success; then
+  :
+else
+  exitcode=1
+  echo as_func_ret_success failed.
+fi
+
+if as_func_ret_failure; then
+  exitcode=1
+  echo as_func_ret_failure succeeded.
+fi
+
+if ( set x; as_func_ret_success y && test x = \"\$1\" ); then
+  :
+else
+  exitcode=1
+  echo positional parameters were not saved.
+fi
+
+test \$exitcode = 0) || { (exit 1); exit 1; }
+
+(
+  as_lineno_1=\$LINENO
+  as_lineno_2=\$LINENO
+  test \"x\$as_lineno_1\" != \"x\$as_lineno_2\" &&
+  test \"x\`expr \$as_lineno_1 + 1\`\" = \"x\$as_lineno_2\") || { (exit 1); exit 1; }
+") 2> /dev/null; then
+  :
+else
+  as_candidate_shells=
+    as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  case $as_dir in
+        /*)
+          for as_base in sh bash ksh sh5; do
+            as_candidate_shells="$as_candidate_shells $as_dir/$as_base"
+          done;;
+       esac
+done
+IFS=$as_save_IFS
+
+
+      for as_shell in $as_candidate_shells $SHELL; do
+        # Try only shells that exist, to save several forks.
+        if { test -f "$as_shell" || test -f "$as_shell.exe"; } &&
+               { ("$as_shell") 2> /dev/null <<\_ASEOF
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then
+  emulate sh
+  NULLCMD=:
+  # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which
+  # is contrary to our usage.  Disable this feature.
+  alias -g '${1+"$@"}'='"$@"'
+  setopt NO_GLOB_SUBST
+else
+  case `(set -o) 2>/dev/null` in
+  *posix*) set -o posix ;;
+esac
+
+fi
+
+
+:
+_ASEOF
+}; then
+  CONFIG_SHELL=$as_shell
+              as_have_required=yes
+              if { "$as_shell" 2> /dev/null <<\_ASEOF
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then
+  emulate sh
+  NULLCMD=:
+  # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which
+  # is contrary to our usage.  Disable this feature.
+  alias -g '${1+"$@"}'='"$@"'
+  setopt NO_GLOB_SUBST
+else
+  case `(set -o) 2>/dev/null` in
+  *posix*) set -o posix ;;
+esac
+
+fi
+
+
+:
+(as_func_return () {
+  (exit $1)
+}
+as_func_success () {
+  as_func_return 0
+}
+as_func_failure () {
+  as_func_return 1
+}
+as_func_ret_success () {
+  return 0
+}
+as_func_ret_failure () {
+  return 1
+}
+
+exitcode=0
+if as_func_success; then
+  :
+else
+  exitcode=1
+  echo as_func_success failed.
+fi
+
+if as_func_failure; then
+  exitcode=1
+  echo as_func_failure succeeded.
+fi
+
+if as_func_ret_success; then
+  :
+else
+  exitcode=1
+  echo as_func_ret_success failed.
+fi
+
+if as_func_ret_failure; then
+  exitcode=1
+  echo as_func_ret_failure succeeded.
+fi
+
+if ( set x; as_func_ret_success y && test x = "$1" ); then
+  :
+else
+  exitcode=1
+  echo positional parameters were not saved.
+fi
+
+test $exitcode = 0) || { (exit 1); exit 1; }
+
+(
+  as_lineno_1=$LINENO
+  as_lineno_2=$LINENO
+  test "x$as_lineno_1" != "x$as_lineno_2" &&
+  test "x`expr $as_lineno_1 + 1`" = "x$as_lineno_2") || { (exit 1); exit 1; }
+
+_ASEOF
+}; then
+  break
+fi
+
+fi
+
+      done
+
+      if test "x$CONFIG_SHELL" != x; then
+  for as_var in BASH_ENV ENV
+        do ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var
+        done
+        export CONFIG_SHELL
+        exec "$CONFIG_SHELL" "$as_myself" ${1+"$@"}
+fi
+
+
+    if test $as_have_required = no; then
+  echo This script requires a shell more modern than all the
+      echo shells that I found on your system.  Please install a
+      echo modern shell, or manually run the script under such a
+      echo shell if you do have one.
+      { (exit 1); exit 1; }
+fi
+
+    
+fi
+
+fi
+
+
+
+(eval "as_func_return () {
+  (exit \$1)
+}
+as_func_success () {
+  as_func_return 0
+}
+as_func_failure () {
+  as_func_return 1
+}
+as_func_ret_success () {
+  return 0
+}
+as_func_ret_failure () {
+  return 1
+}
+
+exitcode=0
+if as_func_success; then
+  :
+else
+  exitcode=1
+  echo as_func_success failed.
+fi
+
+if as_func_failure; then
+  exitcode=1
+  echo as_func_failure succeeded.
+fi
+
+if as_func_ret_success; then
+  :
+else
+  exitcode=1
+  echo as_func_ret_success failed.
+fi
+
+if as_func_ret_failure; then
+  exitcode=1
+  echo as_func_ret_failure succeeded.
+fi
+
+if ( set x; as_func_ret_success y && test x = \"\$1\" ); then
+  :
+else
+  exitcode=1
+  echo positional parameters were not saved.
+fi
+
+test \$exitcode = 0") || {
+  echo No shell found that supports shell functions.
+  echo Please tell autoconf@gnu.org about your system,
+  echo including any error possibly output before this
+  echo message
+}
+
+
+
+  as_lineno_1=$LINENO
+  as_lineno_2=$LINENO
+  test "x$as_lineno_1" != "x$as_lineno_2" &&
+  test "x`expr $as_lineno_1 + 1`" = "x$as_lineno_2" || {
+
+  # Create $as_me.lineno as a copy of $as_myself, but with $LINENO
+  # uniformly replaced by the line number.  The first 'sed' inserts a
+  # line-number line after each line using $LINENO; the second 'sed'
+  # does the real work.  The second script uses 'N' to pair each
+  # line-number line with the line containing $LINENO, and appends
+  # trailing '-' during substitution so that $LINENO is not a special
+  # case at line end.
+  # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the
+  # scripts with optimization help from Paolo Bonzini.  Blame Lee
+  # E. McMahon (1931-1989) for sed's syntax.  :-)
+  sed -n '
+    p
+    /[$]LINENO/=
+  ' <$as_myself |
+    sed '
+      s/[$]LINENO.*/&-/
+      t lineno
+      b
+      :lineno
+      N
+      :loop
+      s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/
+      t loop
+      s/-\n.*//
+    ' >$as_me.lineno &&
+  chmod +x "$as_me.lineno" ||
+    { echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2
+   { (exit 1); exit 1; }; }
+
+  # Don't try to exec as it changes $[0], causing all sort of problems
+  # (the dirname of $[0] is not the place where we might find the
+  # original and so on.  Autoconf is especially sensitive to this).
+  . "./$as_me.lineno"
+  # Exit status is that of the last command.
+  exit
+}
+
+
+if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
+  as_dirname=dirname
+else
+  as_dirname=false
+fi
+
+ECHO_C= ECHO_N= ECHO_T=
+case `echo -n x` in
+-n*)
+  case `echo 'x\c'` in
+  *c*) ECHO_T='        ';;     # ECHO_T is single tab character.
+  *)   ECHO_C='\c';;
+  esac;;
+*)
+  ECHO_N='-n';;
+esac
+
+if expr a : '\(a\)' >/dev/null 2>&1 &&
+   test "X`expr 00001 : '.*\(...\)'`" = X001; then
+  as_expr=expr
+else
+  as_expr=false
+fi
+
+rm -f conf$$ conf$$.exe conf$$.file
+if test -d conf$$.dir; then
+  rm -f conf$$.dir/conf$$.file
+else
+  rm -f conf$$.dir
+  mkdir conf$$.dir
+fi
+echo >conf$$.file
+if ln -s conf$$.file conf$$ 2>/dev/null; then
+  as_ln_s='ln -s'
+  # ... but there are two gotchas:
+  # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
+  # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
+  # In both cases, we have to default to `cp -p'.
+  ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
+    as_ln_s='cp -p'
+elif ln conf$$.file conf$$ 2>/dev/null; then
+  as_ln_s=ln
+else
+  as_ln_s='cp -p'
+fi
+rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
+rmdir conf$$.dir 2>/dev/null
+
+if mkdir -p . 2>/dev/null; then
+  as_mkdir_p=:
+else
+  test -d ./-p && rmdir ./-p
+  as_mkdir_p=false
+fi
+
+if test -x / >/dev/null 2>&1; then
+  as_test_x='test -x'
+else
+  if ls -dL / >/dev/null 2>&1; then
+    as_ls_L_option=L
+  else
+    as_ls_L_option=
+  fi
+  as_test_x='
+    eval sh -c '\''
+      if test -d "$1"; then
+        test -d "$1/.";
+      else
+       case $1 in
+        -*)set "./$1";;
+       esac;
+       case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in
+       ???[sx]*):;;*)false;;esac;fi
+    '\'' sh
+  '
+fi
+as_executable_p=$as_test_x
+
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
+
+# Sed expression to map a string onto a valid variable name.
+as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
+
+
+
+exec 7<&0 </dev/null 6>&1
+
+# Name of the host.
+# hostname on some systems (SVR3.2, Linux) returns a bogus exit status,
+# so uname gets run too.
+ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q`
+
+#
+# Initializations.
+#
+ac_default_prefix=/usr/local
+ac_clean_files=
+ac_config_libobj_dir=.
+LIB@&t@OBJS=
+cross_compiling=no
+subdirs=
+MFLAGS=
+MAKEFLAGS=
+SHELL=${CONFIG_SHELL-/bin/sh}
+
+# Identity of this package.
+PACKAGE_NAME=
+PACKAGE_TARNAME=
+PACKAGE_VERSION=
+PACKAGE_STRING=
+PACKAGE_BUGREPORT=
+
+ac_unique_file="ircd/ircd.c"
+ac_default_prefix=$HOME
+# Factoring default headers for most tests.
+ac_includes_default="\
+#include <stdio.h>
+#ifdef HAVE_SYS_TYPES_H
+# include <sys/types.h>
+#endif
+#ifdef HAVE_SYS_STAT_H
+# include <sys/stat.h>
+#endif
+#ifdef STDC_HEADERS
+# include <stdlib.h>
+# include <stddef.h>
+#else
+# ifdef HAVE_STDLIB_H
+#  include <stdlib.h>
+# endif
+#endif
+#ifdef HAVE_STRING_H
+# if !defined STDC_HEADERS && defined HAVE_MEMORY_H
+#  include <memory.h>
+# endif
+# include <string.h>
+#endif
+#ifdef HAVE_STRINGS_H
+# include <strings.h>
+#endif
+#ifdef HAVE_INTTYPES_H
+# include <inttypes.h>
+#endif
+#ifdef HAVE_STDINT_H
+# include <stdint.h>
+#endif
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif"
+
+ac_subst_vars='SHELL
+PATH_SEPARATOR
+PACKAGE_NAME
+PACKAGE_TARNAME
+PACKAGE_VERSION
+PACKAGE_STRING
+PACKAGE_BUGREPORT
+exec_prefix
+prefix
+program_transform_name
+bindir
+sbindir
+libexecdir
+datarootdir
+datadir
+sysconfdir
+sharedstatedir
+localstatedir
+includedir
+oldincludedir
+docdir
+infodir
+htmldir
+dvidir
+pdfdir
+psdir
+libdir
+localedir
+mandir
+DEFS
+ECHO_C
+ECHO_N
+ECHO_T
+LIBS
+build_alias
+host_alias
+target_alias
+build
+build_cpu
+build_vendor
+build_os
+host
+host_cpu
+host_vendor
+host_os
+CC
+CFLAGS
+LDFLAGS
+CPPFLAGS
+ac_ct_CC
+EXEEXT
+OBJEXT
+CPP
+GREP
+EGREP
+AWK
+SET_MAKE
+INSTALL_PROGRAM
+INSTALL_SCRIPT
+INSTALL_DATA
+LN_S
+RMPROG
+SHPROG
+LEX
+LEX_OUTPUT_ROOT
+LEXLIB
+YACC
+YFLAGS
+ENGINE_C
+INSTALL_RULE
+SYMLINK
+IRCDMODE
+IRCDOWN
+IRCDGRP
+DPATH
+LIB@&t@OBJS
+LTLIBOBJS'
+ac_subst_files=''
+      ac_precious_vars='build_alias
+host_alias
+target_alias
+CC
+CFLAGS
+LDFLAGS
+LIBS
+CPPFLAGS
+CPP
+YACC
+YFLAGS'
+
+
+# Initialize some variables set by options.
+ac_init_help=
+ac_init_version=false
+# The variables have the same names as the options, with
+# dashes changed to underlines.
+cache_file=/dev/null
+exec_prefix=NONE
+no_create=
+no_recursion=
+prefix=NONE
+program_prefix=NONE
+program_suffix=NONE
+program_transform_name=s,x,x,
+silent=
+site=
+srcdir=
+verbose=
+x_includes=NONE
+x_libraries=NONE
+
+# Installation directory options.
+# These are left unexpanded so users can "make install exec_prefix=/foo"
+# and all the variables that are supposed to be based on exec_prefix
+# by default will actually change.
+# Use braces instead of parens because sh, perl, etc. also accept them.
+# (The list follows the same order as the GNU Coding Standards.)
+bindir='${exec_prefix}/bin'
+sbindir='${exec_prefix}/sbin'
+libexecdir='${exec_prefix}/libexec'
+datarootdir='${prefix}/share'
+datadir='${datarootdir}'
+sysconfdir='${prefix}/etc'
+sharedstatedir='${prefix}/com'
+localstatedir='${prefix}/var'
+includedir='${prefix}/include'
+oldincludedir='/usr/include'
+docdir='${datarootdir}/doc/${PACKAGE}'
+infodir='${datarootdir}/info'
+htmldir='${docdir}'
+dvidir='${docdir}'
+pdfdir='${docdir}'
+psdir='${docdir}'
+libdir='${exec_prefix}/lib'
+localedir='${datarootdir}/locale'
+mandir='${datarootdir}/man'
+
+ac_prev=
+ac_dashdash=
+for ac_option
+do
+  # If the previous option needs an argument, assign it.
+  if test -n "$ac_prev"; then
+    eval $ac_prev=\$ac_option
+    ac_prev=
+    continue
+  fi
+
+  case $ac_option in
+  *=*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;;
+  *)   ac_optarg=yes ;;
+  esac
+
+  # Accept the important Cygnus configure options, so we can diagnose typos.
+
+  case $ac_dashdash$ac_option in
+  --)
+    ac_dashdash=yes ;;
+
+  -bindir | --bindir | --bindi | --bind | --bin | --bi)
+    ac_prev=bindir ;;
+  -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*)
+    bindir=$ac_optarg ;;
+
+  -build | --build | --buil | --bui | --bu)
+    ac_prev=build_alias ;;
+  -build=* | --build=* | --buil=* | --bui=* | --bu=*)
+    build_alias=$ac_optarg ;;
+
+  -cache-file | --cache-file | --cache-fil | --cache-fi \
+  | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c)
+    ac_prev=cache_file ;;
+  -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \
+  | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*)
+    cache_file=$ac_optarg ;;
+
+  --config-cache | -C)
+    cache_file=config.cache ;;
+
+  -datadir | --datadir | --datadi | --datad)
+    ac_prev=datadir ;;
+  -datadir=* | --datadir=* | --datadi=* | --datad=*)
+    datadir=$ac_optarg ;;
+
+  -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \
+  | --dataroo | --dataro | --datar)
+    ac_prev=datarootdir ;;
+  -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \
+  | --dataroot=* | --dataroo=* | --dataro=* | --datar=*)
+    datarootdir=$ac_optarg ;;
+
+  -disable-* | --disable-*)
+    ac_feature=`expr "x$ac_option" : 'x-*disable-\(.*\)'`
+    # Reject names that are not valid shell variable names.
+    expr "x$ac_feature" : ".*[^-._$as_cr_alnum]" >/dev/null &&
+      { echo "$as_me: error: invalid feature name: $ac_feature" >&2
+   { (exit 1); exit 1; }; }
+    ac_feature=`echo $ac_feature | sed 's/[-.]/_/g'`
+    eval enable_$ac_feature=no ;;
+
+  -docdir | --docdir | --docdi | --doc | --do)
+    ac_prev=docdir ;;
+  -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*)
+    docdir=$ac_optarg ;;
+
+  -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv)
+    ac_prev=dvidir ;;
+  -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*)
+    dvidir=$ac_optarg ;;
+
+  -enable-* | --enable-*)
+    ac_feature=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'`
+    # Reject names that are not valid shell variable names.
+    expr "x$ac_feature" : ".*[^-._$as_cr_alnum]" >/dev/null &&
+      { echo "$as_me: error: invalid feature name: $ac_feature" >&2
+   { (exit 1); exit 1; }; }
+    ac_feature=`echo $ac_feature | sed 's/[-.]/_/g'`
+    eval enable_$ac_feature=\$ac_optarg ;;
+
+  -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \
+  | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \
+  | --exec | --exe | --ex)
+    ac_prev=exec_prefix ;;
+  -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \
+  | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \
+  | --exec=* | --exe=* | --ex=*)
+    exec_prefix=$ac_optarg ;;
+
+  -gas | --gas | --ga | --g)
+    # Obsolete; use --with-gas.
+    with_gas=yes ;;
+
+  -help | --help | --hel | --he | -h)
+    ac_init_help=long ;;
+  -help=r* | --help=r* | --hel=r* | --he=r* | -hr*)
+    ac_init_help=recursive ;;
+  -help=s* | --help=s* | --hel=s* | --he=s* | -hs*)
+    ac_init_help=short ;;
+
+  -host | --host | --hos | --ho)
+    ac_prev=host_alias ;;
+  -host=* | --host=* | --hos=* | --ho=*)
+    host_alias=$ac_optarg ;;
+
+  -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht)
+    ac_prev=htmldir ;;
+  -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \
+  | --ht=*)
+    htmldir=$ac_optarg ;;
+
+  -includedir | --includedir | --includedi | --included | --include \
+  | --includ | --inclu | --incl | --inc)
+    ac_prev=includedir ;;
+  -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \
+  | --includ=* | --inclu=* | --incl=* | --inc=*)
+    includedir=$ac_optarg ;;
+
+  -infodir | --infodir | --infodi | --infod | --info | --inf)
+    ac_prev=infodir ;;
+  -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*)
+    infodir=$ac_optarg ;;
+
+  -libdir | --libdir | --libdi | --libd)
+    ac_prev=libdir ;;
+  -libdir=* | --libdir=* | --libdi=* | --libd=*)
+    libdir=$ac_optarg ;;
+
+  -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \
+  | --libexe | --libex | --libe)
+    ac_prev=libexecdir ;;
+  -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \
+  | --libexe=* | --libex=* | --libe=*)
+    libexecdir=$ac_optarg ;;
+
+  -localedir | --localedir | --localedi | --localed | --locale)
+    ac_prev=localedir ;;
+  -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*)
+    localedir=$ac_optarg ;;
+
+  -localstatedir | --localstatedir | --localstatedi | --localstated \
+  | --localstate | --localstat | --localsta | --localst | --locals)
+    ac_prev=localstatedir ;;
+  -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \
+  | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*)
+    localstatedir=$ac_optarg ;;
+
+  -mandir | --mandir | --mandi | --mand | --man | --ma | --m)
+    ac_prev=mandir ;;
+  -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*)
+    mandir=$ac_optarg ;;
+
+  -nfp | --nfp | --nf)
+    # Obsolete; use --without-fp.
+    with_fp=no ;;
+
+  -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+  | --no-cr | --no-c | -n)
+    no_create=yes ;;
+
+  -no-recursion | --no-recursion | --no-recursio | --no-recursi \
+  | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r)
+    no_recursion=yes ;;
+
+  -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \
+  | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \
+  | --oldin | --oldi | --old | --ol | --o)
+    ac_prev=oldincludedir ;;
+  -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \
+  | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \
+  | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*)
+    oldincludedir=$ac_optarg ;;
+
+  -prefix | --prefix | --prefi | --pref | --pre | --pr | --p)
+    ac_prev=prefix ;;
+  -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*)
+    prefix=$ac_optarg ;;
+
+  -program-prefix | --program-prefix | --program-prefi | --program-pref \
+  | --program-pre | --program-pr | --program-p)
+    ac_prev=program_prefix ;;
+  -program-prefix=* | --program-prefix=* | --program-prefi=* \
+  | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*)
+    program_prefix=$ac_optarg ;;
+
+  -program-suffix | --program-suffix | --program-suffi | --program-suff \
+  | --program-suf | --program-su | --program-s)
+    ac_prev=program_suffix ;;
+  -program-suffix=* | --program-suffix=* | --program-suffi=* \
+  | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*)
+    program_suffix=$ac_optarg ;;
+
+  -program-transform-name | --program-transform-name \
+  | --program-transform-nam | --program-transform-na \
+  | --program-transform-n | --program-transform- \
+  | --program-transform | --program-transfor \
+  | --program-transfo | --program-transf \
+  | --program-trans | --program-tran \
+  | --progr-tra | --program-tr | --program-t)
+    ac_prev=program_transform_name ;;
+  -program-transform-name=* | --program-transform-name=* \
+  | --program-transform-nam=* | --program-transform-na=* \
+  | --program-transform-n=* | --program-transform-=* \
+  | --program-transform=* | --program-transfor=* \
+  | --program-transfo=* | --program-transf=* \
+  | --program-trans=* | --program-tran=* \
+  | --progr-tra=* | --program-tr=* | --program-t=*)
+    program_transform_name=$ac_optarg ;;
+
+  -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd)
+    ac_prev=pdfdir ;;
+  -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*)
+    pdfdir=$ac_optarg ;;
+
+  -psdir | --psdir | --psdi | --psd | --ps)
+    ac_prev=psdir ;;
+  -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*)
+    psdir=$ac_optarg ;;
+
+  -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+  | -silent | --silent | --silen | --sile | --sil)
+    silent=yes ;;
+
+  -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
+    ac_prev=sbindir ;;
+  -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
+  | --sbi=* | --sb=*)
+    sbindir=$ac_optarg ;;
+
+  -sharedstatedir | --sharedstatedir | --sharedstatedi \
+  | --sharedstated | --sharedstate | --sharedstat | --sharedsta \
+  | --sharedst | --shareds | --shared | --share | --shar \
+  | --sha | --sh)
+    ac_prev=sharedstatedir ;;
+  -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \
+  | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \
+  | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \
+  | --sha=* | --sh=*)
+    sharedstatedir=$ac_optarg ;;
+
+  -site | --site | --sit)
+    ac_prev=site ;;
+  -site=* | --site=* | --sit=*)
+    site=$ac_optarg ;;
+
+  -srcdir | --srcdir | --srcdi | --srcd | --src | --sr)
+    ac_prev=srcdir ;;
+  -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*)
+    srcdir=$ac_optarg ;;
+
+  -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \
+  | --syscon | --sysco | --sysc | --sys | --sy)
+    ac_prev=sysconfdir ;;
+  -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \
+  | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*)
+    sysconfdir=$ac_optarg ;;
+
+  -target | --target | --targe | --targ | --tar | --ta | --t)
+    ac_prev=target_alias ;;
+  -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*)
+    target_alias=$ac_optarg ;;
+
+  -v | -verbose | --verbose | --verbos | --verbo | --verb)
+    verbose=yes ;;
+
+  -version | --version | --versio | --versi | --vers | -V)
+    ac_init_version=: ;;
+
+  -with-* | --with-*)
+    ac_package=`expr "x$ac_option" : 'x-*with-\([^=]*\)'`
+    # Reject names that are not valid shell variable names.
+    expr "x$ac_package" : ".*[^-._$as_cr_alnum]" >/dev/null &&
+      { echo "$as_me: error: invalid package name: $ac_package" >&2
+   { (exit 1); exit 1; }; }
+    ac_package=`echo $ac_package | sed 's/[-.]/_/g'`
+    eval with_$ac_package=\$ac_optarg ;;
+
+  -without-* | --without-*)
+    ac_package=`expr "x$ac_option" : 'x-*without-\(.*\)'`
+    # Reject names that are not valid shell variable names.
+    expr "x$ac_package" : ".*[^-._$as_cr_alnum]" >/dev/null &&
+      { echo "$as_me: error: invalid package name: $ac_package" >&2
+   { (exit 1); exit 1; }; }
+    ac_package=`echo $ac_package | sed 's/[-.]/_/g'`
+    eval with_$ac_package=no ;;
+
+  --x)
+    # Obsolete; use --with-x.
+    with_x=yes ;;
+
+  -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \
+  | --x-incl | --x-inc | --x-in | --x-i)
+    ac_prev=x_includes ;;
+  -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \
+  | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*)
+    x_includes=$ac_optarg ;;
+
+  -x-libraries | --x-libraries | --x-librarie | --x-librari \
+  | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l)
+    ac_prev=x_libraries ;;
+  -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \
+  | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*)
+    x_libraries=$ac_optarg ;;
+
+  -*) { echo "$as_me: error: unrecognized option: $ac_option
+Try \`$0 --help' for more information." >&2
+   { (exit 1); exit 1; }; }
+    ;;
+
+  *=*)
+    ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='`
+    # Reject names that are not valid shell variable names.
+    expr "x$ac_envvar" : ".*[^_$as_cr_alnum]" >/dev/null &&
+      { echo "$as_me: error: invalid variable name: $ac_envvar" >&2
+   { (exit 1); exit 1; }; }
+    eval $ac_envvar=\$ac_optarg
+    export $ac_envvar ;;
+
+  *)
+    # FIXME: should be removed in autoconf 3.0.
+    echo "$as_me: WARNING: you should use --build, --host, --target" >&2
+    expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null &&
+      echo "$as_me: WARNING: invalid host type: $ac_option" >&2
+    : ${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}
+    ;;
+
+  esac
+done
+
+if test -n "$ac_prev"; then
+  ac_option=--`echo $ac_prev | sed 's/_/-/g'`
+  { echo "$as_me: error: missing argument to $ac_option" >&2
+   { (exit 1); exit 1; }; }
+fi
+
+# Be sure to have absolute directory names.
+for ac_var in  exec_prefix prefix bindir sbindir libexecdir datarootdir \
+               datadir sysconfdir sharedstatedir localstatedir includedir \
+               oldincludedir docdir infodir htmldir dvidir pdfdir psdir \
+               libdir localedir mandir
+do
+  eval ac_val=\$$ac_var
+  case $ac_val in
+    [\\/$]* | ?:[\\/]* )  continue;;
+    NONE | '' ) case $ac_var in *prefix ) continue;; esac;;
+  esac
+  { echo "$as_me: error: expected an absolute directory name for --$ac_var: $ac_val" >&2
+   { (exit 1); exit 1; }; }
+done
+
+# There might be people who depend on the old broken behavior: `$host'
+# used to hold the argument of --host etc.
+# FIXME: To remove some day.
+build=$build_alias
+host=$host_alias
+target=$target_alias
+
+# FIXME: To remove some day.
+if test "x$host_alias" != x; then
+  if test "x$build_alias" = x; then
+    cross_compiling=maybe
+    echo "$as_me: WARNING: If you wanted to set the --build type, don't use --host.
+    If a cross compiler is detected then cross compile mode will be used." >&2
+  elif test "x$build_alias" != "x$host_alias"; then
+    cross_compiling=yes
+  fi
+fi
+
+ac_tool_prefix=
+test -n "$host_alias" && ac_tool_prefix=$host_alias-
+
+test "$silent" = yes && exec 6>/dev/null
+
+
+ac_pwd=`pwd` && test -n "$ac_pwd" &&
+ac_ls_di=`ls -di .` &&
+ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` ||
+  { echo "$as_me: error: Working directory cannot be determined" >&2
+   { (exit 1); exit 1; }; }
+test "X$ac_ls_di" = "X$ac_pwd_ls_di" ||
+  { echo "$as_me: error: pwd does not report name of working directory" >&2
+   { (exit 1); exit 1; }; }
+
+
+# Find the source files, if location was not specified.
+if test -z "$srcdir"; then
+  ac_srcdir_defaulted=yes
+  # Try the directory containing this script, then the parent directory.
+  ac_confdir=`$as_dirname -- "$0" ||
+$as_expr X"$0" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+        X"$0" : 'X\(//\)[^/]' \| \
+        X"$0" : 'X\(//\)$' \| \
+        X"$0" : 'X\(/\)' \| . 2>/dev/null ||
+echo X"$0" |
+    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+           s//\1/
+           q
+         }
+         /^X\(\/\/\)[^/].*/{
+           s//\1/
+           q
+         }
+         /^X\(\/\/\)$/{
+           s//\1/
+           q
+         }
+         /^X\(\/\).*/{
+           s//\1/
+           q
+         }
+         s/.*/./; q'`
+  srcdir=$ac_confdir
+  if test ! -r "$srcdir/$ac_unique_file"; then
+    srcdir=..
+  fi
+else
+  ac_srcdir_defaulted=no
+fi
+if test ! -r "$srcdir/$ac_unique_file"; then
+  test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .."
+  { echo "$as_me: error: cannot find sources ($ac_unique_file) in $srcdir" >&2
+   { (exit 1); exit 1; }; }
+fi
+ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work"
+ac_abs_confdir=`(
+       cd "$srcdir" && test -r "./$ac_unique_file" || { echo "$as_me: error: $ac_msg" >&2
+   { (exit 1); exit 1; }; }
+       pwd)`
+# When building in place, set srcdir=.
+if test "$ac_abs_confdir" = "$ac_pwd"; then
+  srcdir=.
+fi
+# Remove unnecessary trailing slashes from srcdir.
+# Double slashes in file names in object file debugging info
+# mess up M-x gdb in Emacs.
+case $srcdir in
+*/) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;;
+esac
+for ac_var in $ac_precious_vars; do
+  eval ac_env_${ac_var}_set=\${${ac_var}+set}
+  eval ac_env_${ac_var}_value=\$${ac_var}
+  eval ac_cv_env_${ac_var}_set=\${${ac_var}+set}
+  eval ac_cv_env_${ac_var}_value=\$${ac_var}
+done
+
+#
+# Report the --help message.
+#
+if test "$ac_init_help" = "long"; then
+  # Omit some internal or obsolete options to make the list less imposing.
+  # This message is too long to be a string in the A/UX 3.1 sh.
+  cat <<_ACEOF
+\`configure' configures this package to adapt to many kinds of systems.
+
+Usage: $0 [OPTION]... [VAR=VALUE]...
+
+To assign environment variables (e.g., CC, CFLAGS...), specify them as
+VAR=VALUE.  See below for descriptions of some of the useful variables.
+
+Defaults for the options are specified in brackets.
+
+Configuration:
+  -h, --help              display this help and exit
+      --help=short        display options specific to this package
+      --help=recursive    display the short help of all the included packages
+  -V, --version           display version information and exit
+  -q, --quiet, --silent   do not print \`checking...' messages
+      --cache-file=FILE   cache test results in FILE [disabled]
+  -C, --config-cache      alias for \`--cache-file=config.cache'
+  -n, --no-create         do not create output files
+      --srcdir=DIR        find the sources in DIR [configure dir or \`..']
+
+Installation directories:
+  --prefix=PREFIX         install architecture-independent files in PREFIX
+                         [$ac_default_prefix]
+  --exec-prefix=EPREFIX   install architecture-dependent files in EPREFIX
+                         [PREFIX]
+
+By default, \`make install' will install all the files in
+\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc.  You can specify
+an installation prefix other than \`$ac_default_prefix' using \`--prefix',
+for instance \`--prefix=\$HOME'.
+
+For better control, use the options below.
+
+Fine tuning of the installation directories:
+  --bindir=DIR           user executables [EPREFIX/bin]
+  --sbindir=DIR          system admin executables [EPREFIX/sbin]
+  --libexecdir=DIR       program executables [EPREFIX/libexec]
+  --sysconfdir=DIR       read-only single-machine data [PREFIX/etc]
+  --sharedstatedir=DIR   modifiable architecture-independent data [PREFIX/com]
+  --localstatedir=DIR    modifiable single-machine data [PREFIX/var]
+  --libdir=DIR           object code libraries [EPREFIX/lib]
+  --includedir=DIR       C header files [PREFIX/include]
+  --oldincludedir=DIR    C header files for non-gcc [/usr/include]
+  --datarootdir=DIR      read-only arch.-independent data root [PREFIX/share]
+  --datadir=DIR          read-only architecture-independent data [DATAROOTDIR]
+  --infodir=DIR          info documentation [DATAROOTDIR/info]
+  --localedir=DIR        locale-dependent data [DATAROOTDIR/locale]
+  --mandir=DIR           man documentation [DATAROOTDIR/man]
+  --docdir=DIR           documentation root @<:@DATAROOTDIR/doc/PACKAGE@:>@
+  --htmldir=DIR          html documentation [DOCDIR]
+  --dvidir=DIR           dvi documentation [DOCDIR]
+  --pdfdir=DIR           pdf documentation [DOCDIR]
+  --psdir=DIR            ps documentation [DOCDIR]
+_ACEOF
+
+  cat <<\_ACEOF
+
+System types:
+  --build=BUILD     configure for building on BUILD [guessed]
+  --host=HOST       cross-compile to build programs to run on HOST [BUILD]
+_ACEOF
+fi
+
+if test -n "$ac_init_help"; then
+
+  cat <<\_ACEOF
+
+Optional Features:
+  --disable-FEATURE       do not include FEATURE (same as --enable-FEATURE=no)
+  --enable-FEATURE[=ARG]  include FEATURE [ARG=yes]
+  --enable-poll           Force poll to be used regardless of whether or not
+                          it is a system call
+  --enable-debug          Turn on debugging mode
+  --disable-asserts       Disable assertion checking
+  --enable-profile        Enable profiling support (add -pg to CFLAGS and LDFLAGS)
+  --enable-pedantic       Enable pedantic warnings (add -pedantic to CFLAGS)
+  --enable-warnings       Enable warnings (add -Wall to CFLAGS)
+  --disable-inlines       Disable inlining for a few critical functions
+  --disable-devpoll       Disable the /dev/poll-based engine
+  --disable-kqueue        Disable the kqueue-based engine
+  --disable-epoll         Disable the epoll-based engine
+  --enable-compat          Enables OGN-compat mode.
+  --enable-unstable          Enables unstable features.
+  --enable-gnutls          Enables GnuTLS ssl backend.
+  --enable-openssl          Enables OpenSSL ssl backend.
+
+Optional Packages:
+  --with-PACKAGE[=ARG]    use PACKAGE [ARG=yes]
+  --without-PACKAGE       do not use PACKAGE (same as --with-PACKAGE=no)
+  --with-leak-detect          Turn on the leak detector(requires patched boehm)
+  --without-ipv6          disable IPv6 support (default is autodetect)
+  --with-symlink=name     Name to give the symlink; if name is "no," no
+                          symlink will be created.
+  --with-mode=mode        Permissions (in octal) to give the binary
+  --with-owner=owner      Specify owner of the installed binary
+  --with-group=group      Specify group owner of the installed binary
+  --with-domain=domain    Domain name to use in local statistics gathering
+  --with-chroot=dir       Specify that the server will be operated under
+                          a different root directory given by dir.  See
+                          doc/readme.chroot for more information.
+  --with-dpath=dir        Directory for all server data files
+  --with-cpath=file       Set server configuration file
+  --with-lpath=file       Set the debugging log file
+  --with-maxcon=maxcon    Maximum number of connections server will accept
+
+Some influential environment variables:
+  CC          C compiler command
+  CFLAGS      C compiler flags
+  LDFLAGS     linker flags, e.g. -L<lib dir> if you have libraries in a
+              nonstandard directory <lib dir>
+  LIBS        libraries to pass to the linker, e.g. -l<library>
+  CPPFLAGS    C/C++/Objective C preprocessor flags, e.g. -I<include dir> if
+              you have headers in a nonstandard directory <include dir>
+  CPP         C preprocessor
+  YACC        The `Yet Another C Compiler' implementation to use. Defaults to
+              the first program found out of: `bison -y', `byacc', `yacc'.
+  YFLAGS      The list of arguments that will be passed by default to $YACC.
+              This script will default YFLAGS to the empty string to avoid a
+              default value of `-d' given by some make applications.
+
+Use these variables to override the choices made by `configure' or to help
+it to find libraries and programs with nonstandard names/locations.
+
+_ACEOF
+ac_status=$?
+fi
+
+if test "$ac_init_help" = "recursive"; then
+  # If there are subdirs, report their specific --help.
+  for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue
+    test -d "$ac_dir" || continue
+    ac_builddir=.
+
+case "$ac_dir" in
+.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
+*)
+  ac_dir_suffix=/`echo "$ac_dir" | sed 's,^\.[\\/],,'`
+  # A ".." for each directory in $ac_dir_suffix.
+  ac_top_builddir_sub=`echo "$ac_dir_suffix" | sed 's,/[^\\/]*,/..,g;s,/,,'`
+  case $ac_top_builddir_sub in
+  "") ac_top_builddir_sub=. ac_top_build_prefix= ;;
+  *)  ac_top_build_prefix=$ac_top_builddir_sub/ ;;
+  esac ;;
+esac
+ac_abs_top_builddir=$ac_pwd
+ac_abs_builddir=$ac_pwd$ac_dir_suffix
+# for backward compatibility:
+ac_top_builddir=$ac_top_build_prefix
+
+case $srcdir in
+  .)  # We are building in place.
+    ac_srcdir=.
+    ac_top_srcdir=$ac_top_builddir_sub
+    ac_abs_top_srcdir=$ac_pwd ;;
+  [\\/]* | ?:[\\/]* )  # Absolute name.
+    ac_srcdir=$srcdir$ac_dir_suffix;
+    ac_top_srcdir=$srcdir
+    ac_abs_top_srcdir=$srcdir ;;
+  *) # Relative name.
+    ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix
+    ac_top_srcdir=$ac_top_build_prefix$srcdir
+    ac_abs_top_srcdir=$ac_pwd/$srcdir ;;
+esac
+ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix
+
+    cd "$ac_dir" || { ac_status=$?; continue; }
+    # Check for guested configure.
+    if test -f "$ac_srcdir/configure.gnu"; then
+      echo &&
+      $SHELL "$ac_srcdir/configure.gnu" --help=recursive
+    elif test -f "$ac_srcdir/configure"; then
+      echo &&
+      $SHELL "$ac_srcdir/configure" --help=recursive
+    else
+      echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2
+    fi || ac_status=$?
+    cd "$ac_pwd" || { ac_status=$?; break; }
+  done
+fi
+
+test -n "$ac_init_help" && exit $ac_status
+if $ac_init_version; then
+  cat <<\_ACEOF
+configure
+generated by GNU Autoconf 2.61
+
+Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001,
+2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
+This configure script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it.
+_ACEOF
+  exit
+fi
+cat >config.log <<_ACEOF
+This file contains any messages produced by compilers while
+running configure, to aid debugging if configure makes a mistake.
+
+It was created by $as_me, which was
+generated by GNU Autoconf 2.61.  Invocation command line was
+
+  $ $0 $@
+
+_ACEOF
+exec 5>>config.log
+{
+cat <<_ASUNAME
+@%:@@%:@ --------- @%:@@%:@
+@%:@@%:@ Platform. @%:@@%:@
+@%:@@%:@ --------- @%:@@%:@
+
+hostname = `(hostname || uname -n) 2>/dev/null | sed 1q`
+uname -m = `(uname -m) 2>/dev/null || echo unknown`
+uname -r = `(uname -r) 2>/dev/null || echo unknown`
+uname -s = `(uname -s) 2>/dev/null || echo unknown`
+uname -v = `(uname -v) 2>/dev/null || echo unknown`
+
+/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown`
+/bin/uname -X     = `(/bin/uname -X) 2>/dev/null     || echo unknown`
+
+/bin/arch              = `(/bin/arch) 2>/dev/null              || echo unknown`
+/usr/bin/arch -k       = `(/usr/bin/arch -k) 2>/dev/null       || echo unknown`
+/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown`
+/usr/bin/hostinfo      = `(/usr/bin/hostinfo) 2>/dev/null      || echo unknown`
+/bin/machine           = `(/bin/machine) 2>/dev/null           || echo unknown`
+/usr/bin/oslevel       = `(/usr/bin/oslevel) 2>/dev/null       || echo unknown`
+/bin/universe          = `(/bin/universe) 2>/dev/null          || echo unknown`
+
+_ASUNAME
+
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  echo "PATH: $as_dir"
+done
+IFS=$as_save_IFS
+
+} >&5
+
+cat >&5 <<_ACEOF
+
+
+@%:@@%:@ ----------- @%:@@%:@
+@%:@@%:@ Core tests. @%:@@%:@
+@%:@@%:@ ----------- @%:@@%:@
+
+_ACEOF
+
+
+# Keep a trace of the command line.
+# Strip out --no-create and --no-recursion so they do not pile up.
+# Strip out --silent because we don't want to record it for future runs.
+# Also quote any args containing shell meta-characters.
+# Make two passes to allow for proper duplicate-argument suppression.
+ac_configure_args=
+ac_configure_args0=
+ac_configure_args1=
+ac_must_keep_next=false
+for ac_pass in 1 2
+do
+  for ac_arg
+  do
+    case $ac_arg in
+    -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;;
+    -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+    | -silent | --silent | --silen | --sile | --sil)
+      continue ;;
+    *\'*)
+      ac_arg=`echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;;
+    esac
+    case $ac_pass in
+    1) ac_configure_args0="$ac_configure_args0 '$ac_arg'" ;;
+    2)
+      ac_configure_args1="$ac_configure_args1 '$ac_arg'"
+      if test $ac_must_keep_next = true; then
+       ac_must_keep_next=false # Got value, back to normal.
+      else
+       case $ac_arg in
+         *=* | --config-cache | -C | -disable-* | --disable-* \
+         | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \
+         | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \
+         | -with-* | --with-* | -without-* | --without-* | --x)
+           case "$ac_configure_args0 " in
+             "$ac_configure_args1"*" '$ac_arg' "* ) continue ;;
+           esac
+           ;;
+         -* ) ac_must_keep_next=true ;;
+       esac
+      fi
+      ac_configure_args="$ac_configure_args '$ac_arg'"
+      ;;
+    esac
+  done
+done
+$as_unset ac_configure_args0 || test "${ac_configure_args0+set}" != set || { ac_configure_args0=; export ac_configure_args0; }
+$as_unset ac_configure_args1 || test "${ac_configure_args1+set}" != set || { ac_configure_args1=; export ac_configure_args1; }
+
+# When interrupted or exit'd, cleanup temporary files, and complete
+# config.log.  We remove comments because anyway the quotes in there
+# would cause problems or look ugly.
+# WARNING: Use '\'' to represent an apostrophe within the trap.
+# WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug.
+trap 'exit_status=$?
+  # Save into config.log some information that might help in debugging.
+  {
+    echo
+
+    cat <<\_ASBOX
+@%:@@%:@ ---------------- @%:@@%:@
+@%:@@%:@ Cache variables. @%:@@%:@
+@%:@@%:@ ---------------- @%:@@%:@
+_ASBOX
+    echo
+    # The following way of writing the cache mishandles newlines in values,
+(
+  for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do
+    eval ac_val=\$$ac_var
+    case $ac_val in #(
+    *${as_nl}*)
+      case $ac_var in #(
+      *_cv_*) { echo "$as_me:$LINENO: WARNING: Cache variable $ac_var contains a newline." >&5
+echo "$as_me: WARNING: Cache variable $ac_var contains a newline." >&2;} ;;
+      esac
+      case $ac_var in #(
+      _ | IFS | as_nl) ;; #(
+      *) $as_unset $ac_var ;;
+      esac ;;
+    esac
+  done
+  (set) 2>&1 |
+    case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #(
+    *${as_nl}ac_space=\ *)
+      sed -n \
+       "s/'\''/'\''\\\\'\'''\''/g;
+         s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p"
+      ;; #(
+    *)
+      sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p"
+      ;;
+    esac |
+    sort
+)
+    echo
+
+    cat <<\_ASBOX
+@%:@@%:@ ----------------- @%:@@%:@
+@%:@@%:@ Output variables. @%:@@%:@
+@%:@@%:@ ----------------- @%:@@%:@
+_ASBOX
+    echo
+    for ac_var in $ac_subst_vars
+    do
+      eval ac_val=\$$ac_var
+      case $ac_val in
+      *\'\''*) ac_val=`echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
+      esac
+      echo "$ac_var='\''$ac_val'\''"
+    done | sort
+    echo
+
+    if test -n "$ac_subst_files"; then
+      cat <<\_ASBOX
+@%:@@%:@ ------------------- @%:@@%:@
+@%:@@%:@ File substitutions. @%:@@%:@
+@%:@@%:@ ------------------- @%:@@%:@
+_ASBOX
+      echo
+      for ac_var in $ac_subst_files
+      do
+       eval ac_val=\$$ac_var
+       case $ac_val in
+       *\'\''*) ac_val=`echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
+       esac
+       echo "$ac_var='\''$ac_val'\''"
+      done | sort
+      echo
+    fi
+
+    if test -s confdefs.h; then
+      cat <<\_ASBOX
+@%:@@%:@ ----------- @%:@@%:@
+@%:@@%:@ confdefs.h. @%:@@%:@
+@%:@@%:@ ----------- @%:@@%:@
+_ASBOX
+      echo
+      cat confdefs.h
+      echo
+    fi
+    test "$ac_signal" != 0 &&
+      echo "$as_me: caught signal $ac_signal"
+    echo "$as_me: exit $exit_status"
+  } >&5
+  rm -f core *.core core.conftest.* &&
+    rm -f -r conftest* confdefs* conf$$* $ac_clean_files &&
+    exit $exit_status
+' 0
+for ac_signal in 1 2 13 15; do
+  trap 'ac_signal='$ac_signal'; { (exit 1); exit 1; }' $ac_signal
+done
+ac_signal=0
+
+# confdefs.h avoids OS command line length limits that DEFS can exceed.
+rm -f -r conftest* confdefs.h
+
+# Predefined preprocessor variables.
+
+cat >>confdefs.h <<_ACEOF
+@%:@define PACKAGE_NAME "$PACKAGE_NAME"
+_ACEOF
+
+
+cat >>confdefs.h <<_ACEOF
+@%:@define PACKAGE_TARNAME "$PACKAGE_TARNAME"
+_ACEOF
+
+
+cat >>confdefs.h <<_ACEOF
+@%:@define PACKAGE_VERSION "$PACKAGE_VERSION"
+_ACEOF
+
+
+cat >>confdefs.h <<_ACEOF
+@%:@define PACKAGE_STRING "$PACKAGE_STRING"
+_ACEOF
+
+
+cat >>confdefs.h <<_ACEOF
+@%:@define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT"
+_ACEOF
+
+
+# Let the site file select an alternate cache file if it wants to.
+# Prefer explicitly selected file to automatically selected ones.
+if test -n "$CONFIG_SITE"; then
+  set x "$CONFIG_SITE"
+elif test "x$prefix" != xNONE; then
+  set x "$prefix/share/config.site" "$prefix/etc/config.site"
+else
+  set x "$ac_default_prefix/share/config.site" \
+       "$ac_default_prefix/etc/config.site"
+fi
+shift
+for ac_site_file
+do
+  if test -r "$ac_site_file"; then
+    { echo "$as_me:$LINENO: loading site script $ac_site_file" >&5
+echo "$as_me: loading site script $ac_site_file" >&6;}
+    sed 's/^/| /' "$ac_site_file" >&5
+    . "$ac_site_file"
+  fi
+done
+
+if test -r "$cache_file"; then
+  # Some versions of bash will fail to source /dev/null (special
+  # files actually), so we avoid doing that.
+  if test -f "$cache_file"; then
+    { echo "$as_me:$LINENO: loading cache $cache_file" >&5
+echo "$as_me: loading cache $cache_file" >&6;}
+    case $cache_file in
+      [\\/]* | ?:[\\/]* ) . "$cache_file";;
+      *)                      . "./$cache_file";;
+    esac
+  fi
+else
+  { echo "$as_me:$LINENO: creating cache $cache_file" >&5
+echo "$as_me: creating cache $cache_file" >&6;}
+  >$cache_file
+fi
+
+# Check that the precious variables saved in the cache have kept the same
+# value.
+ac_cache_corrupted=false
+for ac_var in $ac_precious_vars; do
+  eval ac_old_set=\$ac_cv_env_${ac_var}_set
+  eval ac_new_set=\$ac_env_${ac_var}_set
+  eval ac_old_val=\$ac_cv_env_${ac_var}_value
+  eval ac_new_val=\$ac_env_${ac_var}_value
+  case $ac_old_set,$ac_new_set in
+    set,)
+      { echo "$as_me:$LINENO: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5
+echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;}
+      ac_cache_corrupted=: ;;
+    ,set)
+      { echo "$as_me:$LINENO: error: \`$ac_var' was not set in the previous run" >&5
+echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;}
+      ac_cache_corrupted=: ;;
+    ,);;
+    *)
+      if test "x$ac_old_val" != "x$ac_new_val"; then
+       { echo "$as_me:$LINENO: error: \`$ac_var' has changed since the previous run:" >&5
+echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;}
+       { echo "$as_me:$LINENO:   former value:  $ac_old_val" >&5
+echo "$as_me:   former value:  $ac_old_val" >&2;}
+       { echo "$as_me:$LINENO:   current value: $ac_new_val" >&5
+echo "$as_me:   current value: $ac_new_val" >&2;}
+       ac_cache_corrupted=:
+      fi;;
+  esac
+  # Pass precious variables to config.status.
+  if test "$ac_new_set" = set; then
+    case $ac_new_val in
+    *\'*) ac_arg=$ac_var=`echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;;
+    *) ac_arg=$ac_var=$ac_new_val ;;
+    esac
+    case " $ac_configure_args " in
+      *" '$ac_arg' "*) ;; # Avoid dups.  Use of quotes ensures accuracy.
+      *) ac_configure_args="$ac_configure_args '$ac_arg'" ;;
+    esac
+  fi
+done
+if $ac_cache_corrupted; then
+  { echo "$as_me:$LINENO: error: changes in the environment can compromise the build" >&5
+echo "$as_me: error: changes in the environment can compromise the build" >&2;}
+  { { echo "$as_me:$LINENO: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&5
+echo "$as_me: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&2;}
+   { (exit 1); exit 1; }; }
+fi
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+
+
+{ echo "$as_me:$LINENO: checking for installation prefix" >&5
+echo $ECHO_N "checking for installation prefix... $ECHO_C" >&6; }
+if test "${unet_cv_prefix+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  unet_cv_prefix=$HOME
+fi
+
+if test x"$prefix" != xNONE; then
+    unet_cv_prefix=$prefix
+fi
+{ echo "$as_me:$LINENO: result: $unet_cv_prefix" >&5
+echo "${ECHO_T}$unet_cv_prefix" >&6; }
+ac_default_prefix=$unet_cv_prefix
+
+ac_config_headers="$ac_config_headers config.h"
+
+
+
+
+ac_aux_dir=
+for ac_dir in "$srcdir" "$srcdir/.." "$srcdir/../.."; do
+  if test -f "$ac_dir/install-sh"; then
+    ac_aux_dir=$ac_dir
+    ac_install_sh="$ac_aux_dir/install-sh -c"
+    break
+  elif test -f "$ac_dir/install.sh"; then
+    ac_aux_dir=$ac_dir
+    ac_install_sh="$ac_aux_dir/install.sh -c"
+    break
+  elif test -f "$ac_dir/shtool"; then
+    ac_aux_dir=$ac_dir
+    ac_install_sh="$ac_aux_dir/shtool install -c"
+    break
+  fi
+done
+if test -z "$ac_aux_dir"; then
+  { { echo "$as_me:$LINENO: error: cannot find install-sh or install.sh in \"$srcdir\" \"$srcdir/..\" \"$srcdir/../..\"" >&5
+echo "$as_me: error: cannot find install-sh or install.sh in \"$srcdir\" \"$srcdir/..\" \"$srcdir/../..\"" >&2;}
+   { (exit 1); exit 1; }; }
+fi
+
+# These three variables are undocumented and unsupported,
+# and are intended to be withdrawn in a future Autoconf release.
+# They can cause serious problems if a builder's source tree is in a directory
+# whose full name contains unusual characters.
+ac_config_guess="$SHELL $ac_aux_dir/config.guess"  # Please don't use this var.
+ac_config_sub="$SHELL $ac_aux_dir/config.sub"  # Please don't use this var.
+ac_configure="$SHELL $ac_aux_dir/configure"  # Please don't use this var.
+
+
+# Make sure we can run config.sub.
+$SHELL "$ac_aux_dir/config.sub" sun4 >/dev/null 2>&1 ||
+  { { echo "$as_me:$LINENO: error: cannot run $SHELL $ac_aux_dir/config.sub" >&5
+echo "$as_me: error: cannot run $SHELL $ac_aux_dir/config.sub" >&2;}
+   { (exit 1); exit 1; }; }
+
+{ echo "$as_me:$LINENO: checking build system type" >&5
+echo $ECHO_N "checking build system type... $ECHO_C" >&6; }
+if test "${ac_cv_build+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_build_alias=$build_alias
+test "x$ac_build_alias" = x &&
+  ac_build_alias=`$SHELL "$ac_aux_dir/config.guess"`
+test "x$ac_build_alias" = x &&
+  { { echo "$as_me:$LINENO: error: cannot guess build type; you must specify one" >&5
+echo "$as_me: error: cannot guess build type; you must specify one" >&2;}
+   { (exit 1); exit 1; }; }
+ac_cv_build=`$SHELL "$ac_aux_dir/config.sub" $ac_build_alias` ||
+  { { echo "$as_me:$LINENO: error: $SHELL $ac_aux_dir/config.sub $ac_build_alias failed" >&5
+echo "$as_me: error: $SHELL $ac_aux_dir/config.sub $ac_build_alias failed" >&2;}
+   { (exit 1); exit 1; }; }
+
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_build" >&5
+echo "${ECHO_T}$ac_cv_build" >&6; }
+case $ac_cv_build in
+*-*-*) ;;
+*) { { echo "$as_me:$LINENO: error: invalid value of canonical build" >&5
+echo "$as_me: error: invalid value of canonical build" >&2;}
+   { (exit 1); exit 1; }; };;
+esac
+build=$ac_cv_build
+ac_save_IFS=$IFS; IFS='-'
+set x $ac_cv_build
+shift
+build_cpu=$1
+build_vendor=$2
+shift; shift
+# Remember, the first character of IFS is used to create $*,
+# except with old shells:
+build_os=$*
+IFS=$ac_save_IFS
+case $build_os in *\ *) build_os=`echo "$build_os" | sed 's/ /-/g'`;; esac
+
+
+{ echo "$as_me:$LINENO: checking host system type" >&5
+echo $ECHO_N "checking host system type... $ECHO_C" >&6; }
+if test "${ac_cv_host+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if test "x$host_alias" = x; then
+  ac_cv_host=$ac_cv_build
+else
+  ac_cv_host=`$SHELL "$ac_aux_dir/config.sub" $host_alias` ||
+    { { echo "$as_me:$LINENO: error: $SHELL $ac_aux_dir/config.sub $host_alias failed" >&5
+echo "$as_me: error: $SHELL $ac_aux_dir/config.sub $host_alias failed" >&2;}
+   { (exit 1); exit 1; }; }
+fi
+
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_host" >&5
+echo "${ECHO_T}$ac_cv_host" >&6; }
+case $ac_cv_host in
+*-*-*) ;;
+*) { { echo "$as_me:$LINENO: error: invalid value of canonical host" >&5
+echo "$as_me: error: invalid value of canonical host" >&2;}
+   { (exit 1); exit 1; }; };;
+esac
+host=$ac_cv_host
+ac_save_IFS=$IFS; IFS='-'
+set x $ac_cv_host
+shift
+host_cpu=$1
+host_vendor=$2
+shift; shift
+# Remember, the first character of IFS is used to create $*,
+# except with old shells:
+host_os=$*
+IFS=$ac_save_IFS
+case $host_os in *\ *) host_os=`echo "$host_os" | sed 's/ /-/g'`;; esac
+
+
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+if test -n "$ac_tool_prefix"; then
+  # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args.
+set dummy ${ac_tool_prefix}gcc; ac_word=$2
+{ echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
+if test "${ac_cv_prog_CC+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_CC="${ac_tool_prefix}gcc"
+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+  { echo "$as_me:$LINENO: result: $CC" >&5
+echo "${ECHO_T}$CC" >&6; }
+else
+  { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_CC"; then
+  ac_ct_CC=$CC
+  # Extract the first word of "gcc", so it can be a program name with args.
+set dummy gcc; ac_word=$2
+{ echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
+if test "${ac_cv_prog_ac_ct_CC+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if test -n "$ac_ct_CC"; then
+  ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_ac_ct_CC="gcc"
+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+  { echo "$as_me:$LINENO: result: $ac_ct_CC" >&5
+echo "${ECHO_T}$ac_ct_CC" >&6; }
+else
+  { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+fi
+
+  if test "x$ac_ct_CC" = x; then
+    CC=""
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ echo "$as_me:$LINENO: WARNING: In the future, Autoconf will not detect cross-tools
+whose name does not start with the host triplet.  If you think this
+configuration is useful to you, please write to autoconf@gnu.org." >&5
+echo "$as_me: WARNING: In the future, Autoconf will not detect cross-tools
+whose name does not start with the host triplet.  If you think this
+configuration is useful to you, please write to autoconf@gnu.org." >&2;}
+ac_tool_warned=yes ;;
+esac
+    CC=$ac_ct_CC
+  fi
+else
+  CC="$ac_cv_prog_CC"
+fi
+
+if test -z "$CC"; then
+          if test -n "$ac_tool_prefix"; then
+    # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args.
+set dummy ${ac_tool_prefix}cc; ac_word=$2
+{ echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
+if test "${ac_cv_prog_CC+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_CC="${ac_tool_prefix}cc"
+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+  { echo "$as_me:$LINENO: result: $CC" >&5
+echo "${ECHO_T}$CC" >&6; }
+else
+  { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+fi
+
+
+  fi
+fi
+if test -z "$CC"; then
+  # Extract the first word of "cc", so it can be a program name with args.
+set dummy cc; ac_word=$2
+{ echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
+if test "${ac_cv_prog_CC+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+  ac_prog_rejected=no
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then
+       ac_prog_rejected=yes
+       continue
+     fi
+    ac_cv_prog_CC="cc"
+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+IFS=$as_save_IFS
+
+if test $ac_prog_rejected = yes; then
+  # We found a bogon in the path, so make sure we never use it.
+  set dummy $ac_cv_prog_CC
+  shift
+  if test $@%:@ != 0; then
+    # We chose a different compiler from the bogus one.
+    # However, it has the same basename, so the bogon will be chosen
+    # first if we set CC to just the basename; use the full file name.
+    shift
+    ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@"
+  fi
+fi
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+  { echo "$as_me:$LINENO: result: $CC" >&5
+echo "${ECHO_T}$CC" >&6; }
+else
+  { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+fi
+
+
+fi
+if test -z "$CC"; then
+  if test -n "$ac_tool_prefix"; then
+  for ac_prog in cl.exe
+  do
+    # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
+set dummy $ac_tool_prefix$ac_prog; ac_word=$2
+{ echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
+if test "${ac_cv_prog_CC+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_CC="$ac_tool_prefix$ac_prog"
+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+  { echo "$as_me:$LINENO: result: $CC" >&5
+echo "${ECHO_T}$CC" >&6; }
+else
+  { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+fi
+
+
+    test -n "$CC" && break
+  done
+fi
+if test -z "$CC"; then
+  ac_ct_CC=$CC
+  for ac_prog in cl.exe
+do
+  # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
+if test "${ac_cv_prog_ac_ct_CC+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if test -n "$ac_ct_CC"; then
+  ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_ac_ct_CC="$ac_prog"
+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+  { echo "$as_me:$LINENO: result: $ac_ct_CC" >&5
+echo "${ECHO_T}$ac_ct_CC" >&6; }
+else
+  { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+fi
+
+
+  test -n "$ac_ct_CC" && break
+done
+
+  if test "x$ac_ct_CC" = x; then
+    CC=""
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ echo "$as_me:$LINENO: WARNING: In the future, Autoconf will not detect cross-tools
+whose name does not start with the host triplet.  If you think this
+configuration is useful to you, please write to autoconf@gnu.org." >&5
+echo "$as_me: WARNING: In the future, Autoconf will not detect cross-tools
+whose name does not start with the host triplet.  If you think this
+configuration is useful to you, please write to autoconf@gnu.org." >&2;}
+ac_tool_warned=yes ;;
+esac
+    CC=$ac_ct_CC
+  fi
+fi
+
+fi
+
+
+test -z "$CC" && { { echo "$as_me:$LINENO: error: no acceptable C compiler found in \$PATH
+See \`config.log' for more details." >&5
+echo "$as_me: error: no acceptable C compiler found in \$PATH
+See \`config.log' for more details." >&2;}
+   { (exit 1); exit 1; }; }
+
+# Provide some information about the compiler.
+echo "$as_me:$LINENO: checking for C compiler version" >&5
+ac_compiler=`set X $ac_compile; echo $2`
+{ (ac_try="$ac_compiler --version >&5"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compiler --version >&5") 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }
+{ (ac_try="$ac_compiler -v >&5"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compiler -v >&5") 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }
+{ (ac_try="$ac_compiler -V >&5"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compiler -V >&5") 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }
+
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files a.out a.exe b.out"
+# Try to create an executable without -o first, disregard a.out.
+# It will help us diagnose broken compilers, and finding out an intuition
+# of exeext.
+{ echo "$as_me:$LINENO: checking for C compiler default output file name" >&5
+echo $ECHO_N "checking for C compiler default output file name... $ECHO_C" >&6; }
+ac_link_default=`echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'`
+#
+# List of possible output files, starting from the most likely.
+# The algorithm is not robust to junk in `.', hence go to wildcards (a.*)
+# only as a last resort.  b.out is created by i960 compilers.
+ac_files='a_out.exe a.exe conftest.exe a.out conftest a.* conftest.* b.out'
+#
+# The IRIX 6 linker writes into existing files which may not be
+# executable, retaining their permissions.  Remove them first so a
+# subsequent execution test works.
+ac_rmfiles=
+for ac_file in $ac_files
+do
+  case $ac_file in
+    *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.o | *.obj ) ;;
+    * ) ac_rmfiles="$ac_rmfiles $ac_file";;
+  esac
+done
+rm -f $ac_rmfiles
+
+if { (ac_try="$ac_link_default"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link_default") 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; then
+  # Autoconf-2.13 could set the ac_cv_exeext variable to `no'.
+# So ignore a value of `no', otherwise this would lead to `EXEEXT = no'
+# in a Makefile.  We should not override ac_cv_exeext if it was cached,
+# so that the user can short-circuit this test for compilers unknown to
+# Autoconf.
+for ac_file in $ac_files ''
+do
+  test -f "$ac_file" || continue
+  case $ac_file in
+    *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.o | *.obj )
+       ;;
+    [ab].out )
+       # We found the default executable, but exeext='' is most
+       # certainly right.
+       break;;
+    *.* )
+        if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no;
+       then :; else
+          ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
+       fi
+       # We set ac_cv_exeext here because the later test for it is not
+       # safe: cross compilers may not add the suffix if given an `-o'
+       # argument, so we may need to know it at that point already.
+       # Even if this section looks crufty: it has the advantage of
+       # actually working.
+       break;;
+    * )
+       break;;
+  esac
+done
+test "$ac_cv_exeext" = no && ac_cv_exeext=
+
+else
+  ac_file=''
+fi
+
+{ echo "$as_me:$LINENO: result: $ac_file" >&5
+echo "${ECHO_T}$ac_file" >&6; }
+if test -z "$ac_file"; then
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+{ { echo "$as_me:$LINENO: error: C compiler cannot create executables
+See \`config.log' for more details." >&5
+echo "$as_me: error: C compiler cannot create executables
+See \`config.log' for more details." >&2;}
+   { (exit 77); exit 77; }; }
+fi
+
+ac_exeext=$ac_cv_exeext
+
+# Check that the compiler produces executables we can run.  If not, either
+# the compiler is broken, or we cross compile.
+{ echo "$as_me:$LINENO: checking whether the C compiler works" >&5
+echo $ECHO_N "checking whether the C compiler works... $ECHO_C" >&6; }
+# FIXME: These cross compiler hacks should be removed for Autoconf 3.0
+# If not cross compiling, check that we can run a simple program.
+if test "$cross_compiling" != yes; then
+  if { ac_try='./$ac_file'
+  { (case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_try") 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+    cross_compiling=no
+  else
+    if test "$cross_compiling" = maybe; then
+       cross_compiling=yes
+    else
+       { { echo "$as_me:$LINENO: error: cannot run C compiled programs.
+If you meant to cross compile, use \`--host'.
+See \`config.log' for more details." >&5
+echo "$as_me: error: cannot run C compiled programs.
+If you meant to cross compile, use \`--host'.
+See \`config.log' for more details." >&2;}
+   { (exit 1); exit 1; }; }
+    fi
+  fi
+fi
+{ echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6; }
+
+rm -f a.out a.exe conftest$ac_cv_exeext b.out
+ac_clean_files=$ac_clean_files_save
+# Check that the compiler produces executables we can run.  If not, either
+# the compiler is broken, or we cross compile.
+{ echo "$as_me:$LINENO: checking whether we are cross compiling" >&5
+echo $ECHO_N "checking whether we are cross compiling... $ECHO_C" >&6; }
+{ echo "$as_me:$LINENO: result: $cross_compiling" >&5
+echo "${ECHO_T}$cross_compiling" >&6; }
+
+{ echo "$as_me:$LINENO: checking for suffix of executables" >&5
+echo $ECHO_N "checking for suffix of executables... $ECHO_C" >&6; }
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; then
+  # If both `conftest.exe' and `conftest' are `present' (well, observable)
+# catch `conftest.exe'.  For instance with Cygwin, `ls conftest' will
+# work properly (i.e., refer to `conftest.exe'), while it won't with
+# `rm'.
+for ac_file in conftest.exe conftest conftest.*; do
+  test -f "$ac_file" || continue
+  case $ac_file in
+    *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.o | *.obj ) ;;
+    *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
+         break;;
+    * ) break;;
+  esac
+done
+else
+  { { echo "$as_me:$LINENO: error: cannot compute suffix of executables: cannot compile and link
+See \`config.log' for more details." >&5
+echo "$as_me: error: cannot compute suffix of executables: cannot compile and link
+See \`config.log' for more details." >&2;}
+   { (exit 1); exit 1; }; }
+fi
+
+rm -f conftest$ac_cv_exeext
+{ echo "$as_me:$LINENO: result: $ac_cv_exeext" >&5
+echo "${ECHO_T}$ac_cv_exeext" >&6; }
+
+rm -f conftest.$ac_ext
+EXEEXT=$ac_cv_exeext
+ac_exeext=$EXEEXT
+{ echo "$as_me:$LINENO: checking for suffix of object files" >&5
+echo $ECHO_N "checking for suffix of object files... $ECHO_C" >&6; }
+if test "${ac_cv_objext+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.o conftest.obj
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; then
+  for ac_file in conftest.o conftest.obj conftest.*; do
+  test -f "$ac_file" || continue;
+  case $ac_file in
+    *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf ) ;;
+    *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'`
+       break;;
+  esac
+done
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+{ { echo "$as_me:$LINENO: error: cannot compute suffix of object files: cannot compile
+See \`config.log' for more details." >&5
+echo "$as_me: error: cannot compute suffix of object files: cannot compile
+See \`config.log' for more details." >&2;}
+   { (exit 1); exit 1; }; }
+fi
+
+rm -f conftest.$ac_cv_objext conftest.$ac_ext
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_objext" >&5
+echo "${ECHO_T}$ac_cv_objext" >&6; }
+OBJEXT=$ac_cv_objext
+ac_objext=$OBJEXT
+{ echo "$as_me:$LINENO: checking whether we are using the GNU C compiler" >&5
+echo $ECHO_N "checking whether we are using the GNU C compiler... $ECHO_C" >&6; }
+if test "${ac_cv_c_compiler_gnu+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+int
+main ()
+{
+#ifndef __GNUC__
+       choke me
+#endif
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_compiler_gnu=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_compiler_gnu=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ac_cv_c_compiler_gnu=$ac_compiler_gnu
+
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_c_compiler_gnu" >&5
+echo "${ECHO_T}$ac_cv_c_compiler_gnu" >&6; }
+GCC=`test $ac_compiler_gnu = yes && echo yes`
+ac_test_CFLAGS=${CFLAGS+set}
+ac_save_CFLAGS=$CFLAGS
+{ echo "$as_me:$LINENO: checking whether $CC accepts -g" >&5
+echo $ECHO_N "checking whether $CC accepts -g... $ECHO_C" >&6; }
+if test "${ac_cv_prog_cc_g+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_save_c_werror_flag=$ac_c_werror_flag
+   ac_c_werror_flag=yes
+   ac_cv_prog_cc_g=no
+   CFLAGS="-g"
+   cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_cv_prog_cc_g=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       CFLAGS=""
+      cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  :
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_c_werror_flag=$ac_save_c_werror_flag
+        CFLAGS="-g"
+        cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_cv_prog_cc_g=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+   ac_c_werror_flag=$ac_save_c_werror_flag
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_prog_cc_g" >&5
+echo "${ECHO_T}$ac_cv_prog_cc_g" >&6; }
+if test "$ac_test_CFLAGS" = set; then
+  CFLAGS=$ac_save_CFLAGS
+elif test $ac_cv_prog_cc_g = yes; then
+  if test "$GCC" = yes; then
+    CFLAGS="-g -O2"
+  else
+    CFLAGS="-g"
+  fi
+else
+  if test "$GCC" = yes; then
+    CFLAGS="-O2"
+  else
+    CFLAGS=
+  fi
+fi
+{ echo "$as_me:$LINENO: checking for $CC option to accept ISO C89" >&5
+echo $ECHO_N "checking for $CC option to accept ISO C89... $ECHO_C" >&6; }
+if test "${ac_cv_prog_cc_c89+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_cv_prog_cc_c89=no
+ac_save_CC=$CC
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <stdarg.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+/* Most of the following tests are stolen from RCS 5.7's src/conf.sh.  */
+struct buf { int x; };
+FILE * (*rcsopen) (struct buf *, struct stat *, int);
+static char *e (p, i)
+     char **p;
+     int i;
+{
+  return p[i];
+}
+static char *f (char * (*g) (char **, int), char **p, ...)
+{
+  char *s;
+  va_list v;
+  va_start (v,p);
+  s = g (p, va_arg (v,int));
+  va_end (v);
+  return s;
+}
+
+/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default.  It has
+   function prototypes and stuff, but not '\xHH' hex character constants.
+   These don't provoke an error unfortunately, instead are silently treated
+   as 'x'.  The following induces an error, until -std is added to get
+   proper ANSI mode.  Curiously '\x00'!='x' always comes out true, for an
+   array size at least.  It's necessary to write '\x00'==0 to get something
+   that's true only with -std.  */
+int osf4_cc_array ['\x00' == 0 ? 1 : -1];
+
+/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters
+   inside strings and character constants.  */
+#define FOO(x) 'x'
+int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1];
+
+int test (int i, double x);
+struct s1 {int (*f) (int a);};
+struct s2 {int (*f) (double a);};
+int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int);
+int argc;
+char **argv;
+int
+main ()
+{
+return f (e, argv, 0) != argv[0]  ||  f (e, argv, 1) != argv[1];
+  ;
+  return 0;
+}
+_ACEOF
+for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \
+       -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__"
+do
+  CC="$ac_save_CC $ac_arg"
+  rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_cv_prog_cc_c89=$ac_arg
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       
+fi
+
+rm -f core conftest.err conftest.$ac_objext 
+  test "x$ac_cv_prog_cc_c89" != "xno" && break
+done
+rm -f conftest.$ac_ext
+CC=$ac_save_CC
+
+fi
+# AC_CACHE_VAL
+case "x$ac_cv_prog_cc_c89" in
+  x)
+    { echo "$as_me:$LINENO: result: none needed" >&5
+echo "${ECHO_T}none needed" >&6; } ;;
+  xno)
+    { echo "$as_me:$LINENO: result: unsupported" >&5
+echo "${ECHO_T}unsupported" >&6; } ;;
+  *)
+    CC="$CC $ac_cv_prog_cc_c89"
+    { echo "$as_me:$LINENO: result: $ac_cv_prog_cc_c89" >&5
+echo "${ECHO_T}$ac_cv_prog_cc_c89" >&6; } ;;
+esac
+
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+if test -n "$ac_tool_prefix"; then
+  # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args.
+set dummy ${ac_tool_prefix}gcc; ac_word=$2
+{ echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
+if test "${ac_cv_prog_CC+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_CC="${ac_tool_prefix}gcc"
+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+  { echo "$as_me:$LINENO: result: $CC" >&5
+echo "${ECHO_T}$CC" >&6; }
+else
+  { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_CC"; then
+  ac_ct_CC=$CC
+  # Extract the first word of "gcc", so it can be a program name with args.
+set dummy gcc; ac_word=$2
+{ echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
+if test "${ac_cv_prog_ac_ct_CC+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if test -n "$ac_ct_CC"; then
+  ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_ac_ct_CC="gcc"
+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+  { echo "$as_me:$LINENO: result: $ac_ct_CC" >&5
+echo "${ECHO_T}$ac_ct_CC" >&6; }
+else
+  { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+fi
+
+  if test "x$ac_ct_CC" = x; then
+    CC=""
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ echo "$as_me:$LINENO: WARNING: In the future, Autoconf will not detect cross-tools
+whose name does not start with the host triplet.  If you think this
+configuration is useful to you, please write to autoconf@gnu.org." >&5
+echo "$as_me: WARNING: In the future, Autoconf will not detect cross-tools
+whose name does not start with the host triplet.  If you think this
+configuration is useful to you, please write to autoconf@gnu.org." >&2;}
+ac_tool_warned=yes ;;
+esac
+    CC=$ac_ct_CC
+  fi
+else
+  CC="$ac_cv_prog_CC"
+fi
+
+if test -z "$CC"; then
+          if test -n "$ac_tool_prefix"; then
+    # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args.
+set dummy ${ac_tool_prefix}cc; ac_word=$2
+{ echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
+if test "${ac_cv_prog_CC+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_CC="${ac_tool_prefix}cc"
+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+  { echo "$as_me:$LINENO: result: $CC" >&5
+echo "${ECHO_T}$CC" >&6; }
+else
+  { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+fi
+
+
+  fi
+fi
+if test -z "$CC"; then
+  # Extract the first word of "cc", so it can be a program name with args.
+set dummy cc; ac_word=$2
+{ echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
+if test "${ac_cv_prog_CC+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+  ac_prog_rejected=no
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then
+       ac_prog_rejected=yes
+       continue
+     fi
+    ac_cv_prog_CC="cc"
+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+IFS=$as_save_IFS
+
+if test $ac_prog_rejected = yes; then
+  # We found a bogon in the path, so make sure we never use it.
+  set dummy $ac_cv_prog_CC
+  shift
+  if test $@%:@ != 0; then
+    # We chose a different compiler from the bogus one.
+    # However, it has the same basename, so the bogon will be chosen
+    # first if we set CC to just the basename; use the full file name.
+    shift
+    ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@"
+  fi
+fi
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+  { echo "$as_me:$LINENO: result: $CC" >&5
+echo "${ECHO_T}$CC" >&6; }
+else
+  { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+fi
+
+
+fi
+if test -z "$CC"; then
+  if test -n "$ac_tool_prefix"; then
+  for ac_prog in cl.exe
+  do
+    # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
+set dummy $ac_tool_prefix$ac_prog; ac_word=$2
+{ echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
+if test "${ac_cv_prog_CC+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_CC="$ac_tool_prefix$ac_prog"
+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+  { echo "$as_me:$LINENO: result: $CC" >&5
+echo "${ECHO_T}$CC" >&6; }
+else
+  { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+fi
+
+
+    test -n "$CC" && break
+  done
+fi
+if test -z "$CC"; then
+  ac_ct_CC=$CC
+  for ac_prog in cl.exe
+do
+  # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
+if test "${ac_cv_prog_ac_ct_CC+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if test -n "$ac_ct_CC"; then
+  ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_ac_ct_CC="$ac_prog"
+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+  { echo "$as_me:$LINENO: result: $ac_ct_CC" >&5
+echo "${ECHO_T}$ac_ct_CC" >&6; }
+else
+  { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+fi
+
+
+  test -n "$ac_ct_CC" && break
+done
+
+  if test "x$ac_ct_CC" = x; then
+    CC=""
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ echo "$as_me:$LINENO: WARNING: In the future, Autoconf will not detect cross-tools
+whose name does not start with the host triplet.  If you think this
+configuration is useful to you, please write to autoconf@gnu.org." >&5
+echo "$as_me: WARNING: In the future, Autoconf will not detect cross-tools
+whose name does not start with the host triplet.  If you think this
+configuration is useful to you, please write to autoconf@gnu.org." >&2;}
+ac_tool_warned=yes ;;
+esac
+    CC=$ac_ct_CC
+  fi
+fi
+
+fi
+
+
+test -z "$CC" && { { echo "$as_me:$LINENO: error: no acceptable C compiler found in \$PATH
+See \`config.log' for more details." >&5
+echo "$as_me: error: no acceptable C compiler found in \$PATH
+See \`config.log' for more details." >&2;}
+   { (exit 1); exit 1; }; }
+
+# Provide some information about the compiler.
+echo "$as_me:$LINENO: checking for C compiler version" >&5
+ac_compiler=`set X $ac_compile; echo $2`
+{ (ac_try="$ac_compiler --version >&5"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compiler --version >&5") 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }
+{ (ac_try="$ac_compiler -v >&5"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compiler -v >&5") 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }
+{ (ac_try="$ac_compiler -V >&5"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compiler -V >&5") 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }
+
+{ echo "$as_me:$LINENO: checking whether we are using the GNU C compiler" >&5
+echo $ECHO_N "checking whether we are using the GNU C compiler... $ECHO_C" >&6; }
+if test "${ac_cv_c_compiler_gnu+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+int
+main ()
+{
+#ifndef __GNUC__
+       choke me
+#endif
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_compiler_gnu=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_compiler_gnu=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ac_cv_c_compiler_gnu=$ac_compiler_gnu
+
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_c_compiler_gnu" >&5
+echo "${ECHO_T}$ac_cv_c_compiler_gnu" >&6; }
+GCC=`test $ac_compiler_gnu = yes && echo yes`
+ac_test_CFLAGS=${CFLAGS+set}
+ac_save_CFLAGS=$CFLAGS
+{ echo "$as_me:$LINENO: checking whether $CC accepts -g" >&5
+echo $ECHO_N "checking whether $CC accepts -g... $ECHO_C" >&6; }
+if test "${ac_cv_prog_cc_g+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_save_c_werror_flag=$ac_c_werror_flag
+   ac_c_werror_flag=yes
+   ac_cv_prog_cc_g=no
+   CFLAGS="-g"
+   cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_cv_prog_cc_g=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       CFLAGS=""
+      cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  :
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_c_werror_flag=$ac_save_c_werror_flag
+        CFLAGS="-g"
+        cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_cv_prog_cc_g=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+   ac_c_werror_flag=$ac_save_c_werror_flag
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_prog_cc_g" >&5
+echo "${ECHO_T}$ac_cv_prog_cc_g" >&6; }
+if test "$ac_test_CFLAGS" = set; then
+  CFLAGS=$ac_save_CFLAGS
+elif test $ac_cv_prog_cc_g = yes; then
+  if test "$GCC" = yes; then
+    CFLAGS="-g -O2"
+  else
+    CFLAGS="-g"
+  fi
+else
+  if test "$GCC" = yes; then
+    CFLAGS="-O2"
+  else
+    CFLAGS=
+  fi
+fi
+{ echo "$as_me:$LINENO: checking for $CC option to accept ISO C89" >&5
+echo $ECHO_N "checking for $CC option to accept ISO C89... $ECHO_C" >&6; }
+if test "${ac_cv_prog_cc_c89+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_cv_prog_cc_c89=no
+ac_save_CC=$CC
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <stdarg.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+/* Most of the following tests are stolen from RCS 5.7's src/conf.sh.  */
+struct buf { int x; };
+FILE * (*rcsopen) (struct buf *, struct stat *, int);
+static char *e (p, i)
+     char **p;
+     int i;
+{
+  return p[i];
+}
+static char *f (char * (*g) (char **, int), char **p, ...)
+{
+  char *s;
+  va_list v;
+  va_start (v,p);
+  s = g (p, va_arg (v,int));
+  va_end (v);
+  return s;
+}
+
+/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default.  It has
+   function prototypes and stuff, but not '\xHH' hex character constants.
+   These don't provoke an error unfortunately, instead are silently treated
+   as 'x'.  The following induces an error, until -std is added to get
+   proper ANSI mode.  Curiously '\x00'!='x' always comes out true, for an
+   array size at least.  It's necessary to write '\x00'==0 to get something
+   that's true only with -std.  */
+int osf4_cc_array ['\x00' == 0 ? 1 : -1];
+
+/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters
+   inside strings and character constants.  */
+#define FOO(x) 'x'
+int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1];
+
+int test (int i, double x);
+struct s1 {int (*f) (int a);};
+struct s2 {int (*f) (double a);};
+int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int);
+int argc;
+char **argv;
+int
+main ()
+{
+return f (e, argv, 0) != argv[0]  ||  f (e, argv, 1) != argv[1];
+  ;
+  return 0;
+}
+_ACEOF
+for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \
+       -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__"
+do
+  CC="$ac_save_CC $ac_arg"
+  rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_cv_prog_cc_c89=$ac_arg
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       
+fi
+
+rm -f core conftest.err conftest.$ac_objext 
+  test "x$ac_cv_prog_cc_c89" != "xno" && break
+done
+rm -f conftest.$ac_ext
+CC=$ac_save_CC
+
+fi
+# AC_CACHE_VAL
+case "x$ac_cv_prog_cc_c89" in
+  x)
+    { echo "$as_me:$LINENO: result: none needed" >&5
+echo "${ECHO_T}none needed" >&6; } ;;
+  xno)
+    { echo "$as_me:$LINENO: result: unsupported" >&5
+echo "${ECHO_T}unsupported" >&6; } ;;
+  *)
+    CC="$CC $ac_cv_prog_cc_c89"
+    { echo "$as_me:$LINENO: result: $ac_cv_prog_cc_c89" >&5
+echo "${ECHO_T}$ac_cv_prog_cc_c89" >&6; } ;;
+esac
+
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+am_cv_prog_cc_stdc=$ac_cv_prog_cc_stdc
+
+
+
+
+{ echo "$as_me:$LINENO: checking for library containing crypt" >&5
+echo $ECHO_N "checking for library containing crypt... $ECHO_C" >&6; }
+if test "${ac_cv_search_crypt+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_func_search_save_LIBS=$LIBS
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char crypt ();
+int
+main ()
+{
+return crypt ();
+  ;
+  return 0;
+}
+_ACEOF
+for ac_lib in '' descrypt crypt; do
+  if test -z "$ac_lib"; then
+    ac_res="none required"
+  else
+    ac_res=-l$ac_lib
+    LIBS="-l$ac_lib  $ac_func_search_save_LIBS"
+  fi
+  rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext &&
+       $as_test_x conftest$ac_exeext; then
+  ac_cv_search_crypt=$ac_res
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext 
+  if test "${ac_cv_search_crypt+set}" = set; then
+  break
+fi
+done
+if test "${ac_cv_search_crypt+set}" = set; then
+  :
+else
+  ac_cv_search_crypt=no
+fi
+rm conftest.$ac_ext
+LIBS=$ac_func_search_save_LIBS
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_search_crypt" >&5
+echo "${ECHO_T}$ac_cv_search_crypt" >&6; }
+ac_res=$ac_cv_search_crypt
+if test "$ac_res" != no; then
+  test "$ac_res" = "none required" || LIBS="$ac_res $LIBS"
+  
+else
+  { { echo "$as_me:$LINENO: error: Unable to find library containing crypt()" >&5
+echo "$as_me: error: Unable to find library containing crypt()" >&2;}
+   { (exit 1); exit 1; }; }
+fi
+
+
+
+   # Most operating systems have gethostbyname() in the default searched
+   # libraries (i.e. libc):
+   { echo "$as_me:$LINENO: checking for gethostbyname" >&5
+echo $ECHO_N "checking for gethostbyname... $ECHO_C" >&6; }
+if test "${ac_cv_func_gethostbyname+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+/* Define gethostbyname to an innocuous variant, in case <limits.h> declares gethostbyname.
+   For example, HP-UX 11i <limits.h> declares gettimeofday.  */
+#define gethostbyname innocuous_gethostbyname
+
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char gethostbyname (); below.
+    Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+    <limits.h> exists even on freestanding compilers.  */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef gethostbyname
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char gethostbyname ();
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined __stub_gethostbyname || defined __stub___gethostbyname
+choke me
+#endif
+
+int
+main ()
+{
+return gethostbyname ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext &&
+       $as_test_x conftest$ac_exeext; then
+  ac_cv_func_gethostbyname=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_func_gethostbyname=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_func_gethostbyname" >&5
+echo "${ECHO_T}$ac_cv_func_gethostbyname" >&6; }
+if test $ac_cv_func_gethostbyname = yes; then
+  :
+else
+  # Some OSes (eg. Solaris) place it in libnsl:
+     
+{ echo "$as_me:$LINENO: checking for gethostbyname in -lnsl" >&5
+echo $ECHO_N "checking for gethostbyname in -lnsl... $ECHO_C" >&6; }
+if test "${ac_cv_lib_nsl_gethostbyname+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lnsl  $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char gethostbyname ();
+int
+main ()
+{
+return gethostbyname ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext &&
+       $as_test_x conftest$ac_exeext; then
+  ac_cv_lib_nsl_gethostbyname=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_lib_nsl_gethostbyname=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_lib_nsl_gethostbyname" >&5
+echo "${ECHO_T}$ac_cv_lib_nsl_gethostbyname" >&6; }
+if test $ac_cv_lib_nsl_gethostbyname = yes; then
+  cat >>confdefs.h <<_ACEOF
+@%:@define HAVE_LIBNSL 1
+_ACEOF
+
+  LIBS="-lnsl $LIBS"
+
+else
+  # Some strange OSes (SINIX) have it in libsocket:
+       
+{ echo "$as_me:$LINENO: checking for gethostbyname in -lsocket" >&5
+echo $ECHO_N "checking for gethostbyname in -lsocket... $ECHO_C" >&6; }
+if test "${ac_cv_lib_socket_gethostbyname+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lsocket  $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char gethostbyname ();
+int
+main ()
+{
+return gethostbyname ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext &&
+       $as_test_x conftest$ac_exeext; then
+  ac_cv_lib_socket_gethostbyname=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_lib_socket_gethostbyname=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_lib_socket_gethostbyname" >&5
+echo "${ECHO_T}$ac_cv_lib_socket_gethostbyname" >&6; }
+if test $ac_cv_lib_socket_gethostbyname = yes; then
+  cat >>confdefs.h <<_ACEOF
+@%:@define HAVE_LIBSOCKET 1
+_ACEOF
+
+  LIBS="-lsocket $LIBS"
+
+else
+  # Unfortunately libsocket sometimes depends on libnsl.
+          # AC_CHECK_LIB's API is essentially broken so the following
+          # ugliness is necessary:
+          { echo "$as_me:$LINENO: checking for gethostbyname in -lsocket" >&5
+echo $ECHO_N "checking for gethostbyname in -lsocket... $ECHO_C" >&6; }
+if test "${ac_cv_lib_socket_gethostbyname+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lsocket -lnsl $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char gethostbyname ();
+int
+main ()
+{
+return gethostbyname ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext &&
+       $as_test_x conftest$ac_exeext; then
+  ac_cv_lib_socket_gethostbyname=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_lib_socket_gethostbyname=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_lib_socket_gethostbyname" >&5
+echo "${ECHO_T}$ac_cv_lib_socket_gethostbyname" >&6; }
+if test $ac_cv_lib_socket_gethostbyname = yes; then
+  LIBS="-lsocket -lnsl $LIBS"
+else
+  
+{ echo "$as_me:$LINENO: checking for gethostbyname in -lresolv" >&5
+echo $ECHO_N "checking for gethostbyname in -lresolv... $ECHO_C" >&6; }
+if test "${ac_cv_lib_resolv_gethostbyname+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lresolv  $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char gethostbyname ();
+int
+main ()
+{
+return gethostbyname ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext &&
+       $as_test_x conftest$ac_exeext; then
+  ac_cv_lib_resolv_gethostbyname=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_lib_resolv_gethostbyname=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_lib_resolv_gethostbyname" >&5
+echo "${ECHO_T}$ac_cv_lib_resolv_gethostbyname" >&6; }
+if test $ac_cv_lib_resolv_gethostbyname = yes; then
+  cat >>confdefs.h <<_ACEOF
+@%:@define HAVE_LIBRESOLV 1
+_ACEOF
+
+  LIBS="-lresolv $LIBS"
+
+fi
+
+fi
+
+       
+fi
+
+     
+fi
+
+   
+fi
+
+  { echo "$as_me:$LINENO: checking for socket" >&5
+echo $ECHO_N "checking for socket... $ECHO_C" >&6; }
+if test "${ac_cv_func_socket+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+/* Define socket to an innocuous variant, in case <limits.h> declares socket.
+   For example, HP-UX 11i <limits.h> declares gettimeofday.  */
+#define socket innocuous_socket
+
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char socket (); below.
+    Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+    <limits.h> exists even on freestanding compilers.  */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef socket
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char socket ();
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined __stub_socket || defined __stub___socket
+choke me
+#endif
+
+int
+main ()
+{
+return socket ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext &&
+       $as_test_x conftest$ac_exeext; then
+  ac_cv_func_socket=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_func_socket=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_func_socket" >&5
+echo "${ECHO_T}$ac_cv_func_socket" >&6; }
+if test $ac_cv_func_socket = yes; then
+  :
+else
+  
+{ echo "$as_me:$LINENO: checking for socket in -lsocket" >&5
+echo $ECHO_N "checking for socket in -lsocket... $ECHO_C" >&6; }
+if test "${ac_cv_lib_socket_socket+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lsocket  $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char socket ();
+int
+main ()
+{
+return socket ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext &&
+       $as_test_x conftest$ac_exeext; then
+  ac_cv_lib_socket_socket=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_lib_socket_socket=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_lib_socket_socket" >&5
+echo "${ECHO_T}$ac_cv_lib_socket_socket" >&6; }
+if test $ac_cv_lib_socket_socket = yes; then
+  cat >>confdefs.h <<_ACEOF
+@%:@define HAVE_LIBSOCKET 1
+_ACEOF
+
+  LIBS="-lsocket $LIBS"
+
+else
+  { echo "$as_me:$LINENO: checking for socket in -lsocket" >&5
+echo $ECHO_N "checking for socket in -lsocket... $ECHO_C" >&6; }
+if test "${ac_cv_lib_socket_socket+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lsocket -lnsl $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char socket ();
+int
+main ()
+{
+return socket ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext &&
+       $as_test_x conftest$ac_exeext; then
+  ac_cv_lib_socket_socket=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_lib_socket_socket=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_lib_socket_socket" >&5
+echo "${ECHO_T}$ac_cv_lib_socket_socket" >&6; }
+if test $ac_cv_lib_socket_socket = yes; then
+  LIBS="-lsocket -lnsl $LIBS"
+fi
+
+fi
+
+fi
+
+  
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+{ echo "$as_me:$LINENO: checking how to run the C preprocessor" >&5
+echo $ECHO_N "checking how to run the C preprocessor... $ECHO_C" >&6; }
+# On Suns, sometimes $CPP names a directory.
+if test -n "$CPP" && test -d "$CPP"; then
+  CPP=
+fi
+if test -z "$CPP"; then
+  if test "${ac_cv_prog_CPP+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+      # Double quotes because CPP needs to be expanded
+    for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp"
+    do
+      ac_preproc_ok=false
+for ac_c_preproc_warn_flag in '' yes
+do
+  # Use a header file that comes with gcc, so configuring glibc
+  # with a fresh cross-compiler works.
+  # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+  # <limits.h> exists even on freestanding compilers.
+  # On the NeXT, cc -E runs the code through the compiler's parser,
+  # not just through cpp. "Syntax error" is here to catch this case.
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+@%:@ifdef __STDC__
+@%:@ include <limits.h>
+@%:@else
+@%:@ include <assert.h>
+@%:@endif
+                    Syntax error
+_ACEOF
+if { (ac_try="$ac_cpp conftest.$ac_ext"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } >/dev/null && {
+        test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       }; then
+  :
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+  # Broken: fails on valid input.
+continue
+fi
+
+rm -f conftest.err conftest.$ac_ext
+
+  # OK, works on sane cases.  Now check whether nonexistent headers
+  # can be detected and how.
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+@%:@include <ac_nonexistent.h>
+_ACEOF
+if { (ac_try="$ac_cpp conftest.$ac_ext"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } >/dev/null && {
+        test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       }; then
+  # Broken: success on invalid input.
+continue
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+  # Passes both tests.
+ac_preproc_ok=:
+break
+fi
+
+rm -f conftest.err conftest.$ac_ext
+
+done
+# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
+rm -f conftest.err conftest.$ac_ext
+if $ac_preproc_ok; then
+  break
+fi
+
+    done
+    ac_cv_prog_CPP=$CPP
+  
+fi
+  CPP=$ac_cv_prog_CPP
+else
+  ac_cv_prog_CPP=$CPP
+fi
+{ echo "$as_me:$LINENO: result: $CPP" >&5
+echo "${ECHO_T}$CPP" >&6; }
+ac_preproc_ok=false
+for ac_c_preproc_warn_flag in '' yes
+do
+  # Use a header file that comes with gcc, so configuring glibc
+  # with a fresh cross-compiler works.
+  # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+  # <limits.h> exists even on freestanding compilers.
+  # On the NeXT, cc -E runs the code through the compiler's parser,
+  # not just through cpp. "Syntax error" is here to catch this case.
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+@%:@ifdef __STDC__
+@%:@ include <limits.h>
+@%:@else
+@%:@ include <assert.h>
+@%:@endif
+                    Syntax error
+_ACEOF
+if { (ac_try="$ac_cpp conftest.$ac_ext"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } >/dev/null && {
+        test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       }; then
+  :
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+  # Broken: fails on valid input.
+continue
+fi
+
+rm -f conftest.err conftest.$ac_ext
+
+  # OK, works on sane cases.  Now check whether nonexistent headers
+  # can be detected and how.
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+@%:@include <ac_nonexistent.h>
+_ACEOF
+if { (ac_try="$ac_cpp conftest.$ac_ext"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } >/dev/null && {
+        test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       }; then
+  # Broken: success on invalid input.
+continue
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+  # Passes both tests.
+ac_preproc_ok=:
+break
+fi
+
+rm -f conftest.err conftest.$ac_ext
+
+done
+# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
+rm -f conftest.err conftest.$ac_ext
+if $ac_preproc_ok; then
+  :
+else
+  { { echo "$as_me:$LINENO: error: C preprocessor \"$CPP\" fails sanity check
+See \`config.log' for more details." >&5
+echo "$as_me: error: C preprocessor \"$CPP\" fails sanity check
+See \`config.log' for more details." >&2;}
+   { (exit 1); exit 1; }; }
+fi
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+{ echo "$as_me:$LINENO: checking for grep that handles long lines and -e" >&5
+echo $ECHO_N "checking for grep that handles long lines and -e... $ECHO_C" >&6; }
+if test "${ac_cv_path_GREP+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  # Extract the first word of "grep ggrep" to use in msg output
+if test -z "$GREP"; then
+set dummy grep ggrep; ac_prog_name=$2
+if test "${ac_cv_path_GREP+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_path_GREP_found=false
+# Loop through the user's path and test for each of PROGNAME-LIST
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_prog in grep ggrep; do
+  for ac_exec_ext in '' $ac_executable_extensions; do
+    ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext"
+    { test -f "$ac_path_GREP" && $as_test_x "$ac_path_GREP"; } || continue
+    # Check for GNU ac_path_GREP and select it if it is found.
+  # Check for GNU $ac_path_GREP
+case `"$ac_path_GREP" --version 2>&1` in
+*GNU*)
+  ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;;
+*)
+  ac_count=0
+  echo $ECHO_N "0123456789$ECHO_C" >"conftest.in"
+  while :
+  do
+    cat "conftest.in" "conftest.in" >"conftest.tmp"
+    mv "conftest.tmp" "conftest.in"
+    cp "conftest.in" "conftest.nl"
+    echo 'GREP' >> "conftest.nl"
+    "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break
+    diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
+    ac_count=`expr $ac_count + 1`
+    if test $ac_count -gt ${ac_path_GREP_max-0}; then
+      # Best one so far, save it but keep looking for a better one
+      ac_cv_path_GREP="$ac_path_GREP"
+      ac_path_GREP_max=$ac_count
+    fi
+    # 10*(2^10) chars as input seems more than enough
+    test $ac_count -gt 10 && break
+  done
+  rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
+esac
+
+
+    $ac_path_GREP_found && break 3
+  done
+done
+
+done
+IFS=$as_save_IFS
+
+
+fi
+
+GREP="$ac_cv_path_GREP"
+if test -z "$GREP"; then
+  { { echo "$as_me:$LINENO: error: no acceptable $ac_prog_name could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" >&5
+echo "$as_me: error: no acceptable $ac_prog_name could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" >&2;}
+   { (exit 1); exit 1; }; }
+fi
+
+else
+  ac_cv_path_GREP=$GREP
+fi
+
+
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_path_GREP" >&5
+echo "${ECHO_T}$ac_cv_path_GREP" >&6; }
+ GREP="$ac_cv_path_GREP"
+
+{ echo "$as_me:$LINENO: checking for egrep" >&5
+echo $ECHO_N "checking for egrep... $ECHO_C" >&6; }
+if test "${ac_cv_path_EGREP+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if echo a | $GREP -E '(a|b)' >/dev/null 2>&1
+   then ac_cv_path_EGREP="$GREP -E"
+   else
+     # Extract the first word of "egrep" to use in msg output
+if test -z "$EGREP"; then
+set dummy egrep; ac_prog_name=$2
+if test "${ac_cv_path_EGREP+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_path_EGREP_found=false
+# Loop through the user's path and test for each of PROGNAME-LIST
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_prog in egrep; do
+  for ac_exec_ext in '' $ac_executable_extensions; do
+    ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext"
+    { test -f "$ac_path_EGREP" && $as_test_x "$ac_path_EGREP"; } || continue
+    # Check for GNU ac_path_EGREP and select it if it is found.
+  # Check for GNU $ac_path_EGREP
+case `"$ac_path_EGREP" --version 2>&1` in
+*GNU*)
+  ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;;
+*)
+  ac_count=0
+  echo $ECHO_N "0123456789$ECHO_C" >"conftest.in"
+  while :
+  do
+    cat "conftest.in" "conftest.in" >"conftest.tmp"
+    mv "conftest.tmp" "conftest.in"
+    cp "conftest.in" "conftest.nl"
+    echo 'EGREP' >> "conftest.nl"
+    "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break
+    diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
+    ac_count=`expr $ac_count + 1`
+    if test $ac_count -gt ${ac_path_EGREP_max-0}; then
+      # Best one so far, save it but keep looking for a better one
+      ac_cv_path_EGREP="$ac_path_EGREP"
+      ac_path_EGREP_max=$ac_count
+    fi
+    # 10*(2^10) chars as input seems more than enough
+    test $ac_count -gt 10 && break
+  done
+  rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
+esac
+
+
+    $ac_path_EGREP_found && break 3
+  done
+done
+
+done
+IFS=$as_save_IFS
+
+
+fi
+
+EGREP="$ac_cv_path_EGREP"
+if test -z "$EGREP"; then
+  { { echo "$as_me:$LINENO: error: no acceptable $ac_prog_name could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" >&5
+echo "$as_me: error: no acceptable $ac_prog_name could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" >&2;}
+   { (exit 1); exit 1; }; }
+fi
+
+else
+  ac_cv_path_EGREP=$EGREP
+fi
+
+
+   fi
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_path_EGREP" >&5
+echo "${ECHO_T}$ac_cv_path_EGREP" >&6; }
+ EGREP="$ac_cv_path_EGREP"
+
+{ echo "$as_me:$LINENO: checking for ANSI C header files" >&5
+echo $ECHO_N "checking for ANSI C header files... $ECHO_C" >&6; }
+if test "${ac_cv_header_stdc+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <float.h>
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_cv_header_stdc=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_header_stdc=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
+if test $ac_cv_header_stdc = yes; then
+  # SunOS 4.x string.h does not declare mem*, contrary to ANSI.
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <string.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  $EGREP "memchr" >/dev/null 2>&1; then
+  :
+else
+  ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+  # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI.
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <stdlib.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  $EGREP "free" >/dev/null 2>&1; then
+  :
+else
+  ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+  # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi.
+  if test "$cross_compiling" = yes; then
+  :
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <ctype.h>
+#include <stdlib.h>
+#if ((' ' & 0x0FF) == 0x020)
+# define ISLOWER(c) ('a' <= (c) && (c) <= 'z')
+# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c))
+#else
+# define ISLOWER(c) \
+                  (('a' <= (c) && (c) <= 'i') \
+                    || ('j' <= (c) && (c) <= 'r') \
+                    || ('s' <= (c) && (c) <= 'z'))
+# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c))
+#endif
+
+#define XOR(e, f) (((e) && !(f)) || (!(e) && (f)))
+int
+main ()
+{
+  int i;
+  for (i = 0; i < 256; i++)
+    if (XOR (islower (i), ISLOWER (i))
+       || toupper (i) != TOUPPER (i))
+      return 2;
+  return 0;
+}
+_ACEOF
+rm -f conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
+  { (case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_try") 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  :
+else
+  echo "$as_me: program exited with status $ac_status" >&5
+echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+( exit $ac_status )
+ac_cv_header_stdc=no
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+fi
+
+
+fi
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_header_stdc" >&5
+echo "${ECHO_T}$ac_cv_header_stdc" >&6; }
+if test $ac_cv_header_stdc = yes; then
+  
+cat >>confdefs.h <<\_ACEOF
+@%:@define STDC_HEADERS 1
+_ACEOF
+
+fi
+
+# On IRIX 5.3, sys/types and inttypes.h are conflicting.
+
+
+
+
+
+
+
+
+
+for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \
+                 inttypes.h stdint.h unistd.h
+do
+as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
+{ echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; }
+if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+
+@%:@include <$ac_header>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  eval "$as_ac_Header=yes"
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       eval "$as_ac_Header=no"
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+ac_res=`eval echo '${'$as_ac_Header'}'`
+              { echo "$as_me:$LINENO: result: $ac_res" >&5
+echo "${ECHO_T}$ac_res" >&6; }
+if test `eval echo '${'$as_ac_Header'}'` = yes; then
+  cat >>confdefs.h <<_ACEOF
+@%:@define `echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+fi
+
+done
+
+
+
+
+
+
+
+
+
+
+
+
+for ac_header in crypt.h poll.h inttypes.h stdint.h sys/devpoll.h sys/epoll.h sys/event.h sys/param.h sys/resource.h sys/socket.h
+do
+as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
+if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
+  { echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; }
+if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+fi
+ac_res=`eval echo '${'$as_ac_Header'}'`
+              { echo "$as_me:$LINENO: result: $ac_res" >&5
+echo "${ECHO_T}$ac_res" >&6; }
+else
+  # Is the header compilable?
+{ echo "$as_me:$LINENO: checking $ac_header usability" >&5
+echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6; }
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+@%:@include <$ac_header>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_header_compiler=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_header_compiler=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+{ echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
+echo "${ECHO_T}$ac_header_compiler" >&6; }
+
+# Is the header present?
+{ echo "$as_me:$LINENO: checking $ac_header presence" >&5
+echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6; }
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+@%:@include <$ac_header>
+_ACEOF
+if { (ac_try="$ac_cpp conftest.$ac_ext"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } >/dev/null && {
+        test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       }; then
+  ac_header_preproc=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+  ac_header_preproc=no
+fi
+
+rm -f conftest.err conftest.$ac_ext
+{ echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
+echo "${ECHO_T}$ac_header_preproc" >&6; }
+
+# So?  What about this header?
+case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
+  yes:no: )
+    { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5
+echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;}
+    ac_header_preproc=yes
+    ;;
+  no:yes:* )
+    { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5
+echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header:     check for missing prerequisite headers?" >&5
+echo "$as_me: WARNING: $ac_header:     check for missing prerequisite headers?" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5
+echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&5
+echo "$as_me: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5
+echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;}
+    
+    ;;
+esac
+{ echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; }
+if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  eval "$as_ac_Header=\$ac_header_preproc"
+fi
+ac_res=`eval echo '${'$as_ac_Header'}'`
+              { echo "$as_me:$LINENO: result: $ac_res" >&5
+echo "${ECHO_T}$ac_res" >&6; }
+
+fi
+if test `eval echo '${'$as_ac_Header'}'` = yes; then
+  cat >>confdefs.h <<_ACEOF
+@%:@define `echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+fi
+
+done
+
+
+{ echo "$as_me:$LINENO: checking whether byte ordering is bigendian" >&5
+echo $ECHO_N "checking whether byte ordering is bigendian... $ECHO_C" >&6; }
+if test "${ac_cv_c_bigendian+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  # See if sys/param.h defines the BYTE_ORDER macro.
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <sys/types.h>
+#include <sys/param.h>
+
+int
+main ()
+{
+#if  ! (defined BYTE_ORDER && defined BIG_ENDIAN && defined LITTLE_ENDIAN \
+       && BYTE_ORDER && BIG_ENDIAN && LITTLE_ENDIAN)
+ bogus endian macros
+#endif
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  # It does; now see whether it defined to BIG_ENDIAN or not.
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <sys/types.h>
+#include <sys/param.h>
+
+int
+main ()
+{
+#if BYTE_ORDER != BIG_ENDIAN
+ not big endian
+#endif
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_cv_c_bigendian=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_c_bigendian=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       # It does not; compile a test program.
+if test "$cross_compiling" = yes; then
+  # try to guess the endianness by grepping values into an object file
+  ac_cv_c_bigendian=unknown
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+short int ascii_mm[] = { 0x4249, 0x4765, 0x6E44, 0x6961, 0x6E53, 0x7953, 0 };
+short int ascii_ii[] = { 0x694C, 0x5454, 0x656C, 0x6E45, 0x6944, 0x6E61, 0 };
+void _ascii () { char *s = (char *) ascii_mm; s = (char *) ascii_ii; }
+short int ebcdic_ii[] = { 0x89D3, 0xE3E3, 0x8593, 0x95C5, 0x89C4, 0x9581, 0 };
+short int ebcdic_mm[] = { 0xC2C9, 0xC785, 0x95C4, 0x8981, 0x95E2, 0xA8E2, 0 };
+void _ebcdic () { char *s = (char *) ebcdic_mm; s = (char *) ebcdic_ii; }
+int
+main ()
+{
+ _ascii (); _ebcdic (); 
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  if grep BIGenDianSyS conftest.$ac_objext >/dev/null ; then
+  ac_cv_c_bigendian=yes
+fi
+if grep LiTTleEnDian conftest.$ac_objext >/dev/null ; then
+  if test "$ac_cv_c_bigendian" = unknown; then
+    ac_cv_c_bigendian=no
+  else
+    # finding both strings is unlikely to happen, but who knows?
+    ac_cv_c_bigendian=unknown
+  fi
+fi
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+int
+main ()
+{
+
+  /* Are we little or big endian?  From Harbison&Steele.  */
+  union
+  {
+    long int l;
+    char c[sizeof (long int)];
+  } u;
+  u.l = 1;
+  return u.c[sizeof (long int) - 1] == 1;
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
+  { (case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_try") 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_c_bigendian=no
+else
+  echo "$as_me: program exited with status $ac_status" >&5
+echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+( exit $ac_status )
+ac_cv_c_bigendian=yes
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+fi
+
+
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_c_bigendian" >&5
+echo "${ECHO_T}$ac_cv_c_bigendian" >&6; }
+case $ac_cv_c_bigendian in
+  yes)
+    
+cat >>confdefs.h <<\_ACEOF
+@%:@define WORDS_BIGENDIAN 1
+_ACEOF
+ ;;
+  no)
+     ;;
+  *)
+    { { echo "$as_me:$LINENO: error: unknown endianness
+presetting ac_cv_c_bigendian=no (or yes) will help" >&5
+echo "$as_me: error: unknown endianness
+presetting ac_cv_c_bigendian=no (or yes) will help" >&2;}
+   { (exit 1); exit 1; }; } ;;
+esac
+
+{ echo "$as_me:$LINENO: checking for size_t" >&5
+echo $ECHO_N "checking for size_t... $ECHO_C" >&6; }
+if test "${ac_cv_type_size_t+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+typedef size_t ac__type_new_;
+int
+main ()
+{
+if ((ac__type_new_ *) 0)
+  return 0;
+if (sizeof (ac__type_new_))
+  return 0;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_cv_type_size_t=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_type_size_t=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_type_size_t" >&5
+echo "${ECHO_T}$ac_cv_type_size_t" >&6; }
+if test $ac_cv_type_size_t = yes; then
+  :
+else
+  
+cat >>confdefs.h <<_ACEOF
+@%:@define size_t unsigned int
+_ACEOF
+
+fi
+
+{ echo "$as_me:$LINENO: checking whether time.h and sys/time.h may both be included" >&5
+echo $ECHO_N "checking whether time.h and sys/time.h may both be included... $ECHO_C" >&6; }
+if test "${ac_cv_header_time+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <sys/types.h>
+#include <sys/time.h>
+#include <time.h>
+
+int
+main ()
+{
+if ((struct tm *) 0)
+return 0;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_cv_header_time=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_header_time=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_header_time" >&5
+echo "${ECHO_T}$ac_cv_header_time" >&6; }
+if test $ac_cv_header_time = yes; then
+  
+cat >>confdefs.h <<\_ACEOF
+@%:@define TIME_WITH_SYS_TIME 1
+_ACEOF
+
+fi
+
+{ echo "$as_me:$LINENO: checking whether struct tm is in sys/time.h or time.h" >&5
+echo $ECHO_N "checking whether struct tm is in sys/time.h or time.h... $ECHO_C" >&6; }
+if test "${ac_cv_struct_tm+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <sys/types.h>
+#include <time.h>
+
+int
+main ()
+{
+struct tm tm;
+                                    int *p = &tm.tm_sec;
+                                    return !p;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_cv_struct_tm=time.h
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_struct_tm=sys/time.h
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_struct_tm" >&5
+echo "${ECHO_T}$ac_cv_struct_tm" >&6; }
+if test $ac_cv_struct_tm = sys/time.h; then
+  
+cat >>confdefs.h <<\_ACEOF
+@%:@define TM_IN_SYS_TIME 1
+_ACEOF
+
+fi
+
+{ echo "$as_me:$LINENO: checking for uid_t in sys/types.h" >&5
+echo $ECHO_N "checking for uid_t in sys/types.h... $ECHO_C" >&6; }
+if test "${ac_cv_type_uid_t+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <sys/types.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  $EGREP "uid_t" >/dev/null 2>&1; then
+  ac_cv_type_uid_t=yes
+else
+  ac_cv_type_uid_t=no
+fi
+rm -f conftest*
+
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_type_uid_t" >&5
+echo "${ECHO_T}$ac_cv_type_uid_t" >&6; }
+if test $ac_cv_type_uid_t = no; then
+  
+cat >>confdefs.h <<\_ACEOF
+@%:@define uid_t int
+_ACEOF
+
+  
+cat >>confdefs.h <<\_ACEOF
+@%:@define gid_t int
+_ACEOF
+
+fi
+
+{ echo "$as_me:$LINENO: checking for short" >&5
+echo $ECHO_N "checking for short... $ECHO_C" >&6; }
+if test "${ac_cv_type_short+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+typedef short ac__type_new_;
+int
+main ()
+{
+if ((ac__type_new_ *) 0)
+  return 0;
+if (sizeof (ac__type_new_))
+  return 0;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_cv_type_short=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_type_short=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_type_short" >&5
+echo "${ECHO_T}$ac_cv_type_short" >&6; }
+
+# The cast to long int works around a bug in the HP C Compiler
+# version HP92453-01 B.11.11.23709.GP, which incorrectly rejects
+# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'.
+# This bug is HP SR number 8606223364.
+{ echo "$as_me:$LINENO: checking size of short" >&5
+echo $ECHO_N "checking size of short... $ECHO_C" >&6; }
+if test "${ac_cv_sizeof_short+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if test "$cross_compiling" = yes; then
+  # Depending upon the size, compute the lo and hi bounds.
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+   typedef short ac__type_sizeof_;
+int
+main ()
+{
+static int test_array @<:@1 - 2 * !(((long int) (sizeof (ac__type_sizeof_))) >= 0)@:>@;
+test_array @<:@0@:>@ = 0
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_lo=0 ac_mid=0
+  while :; do
+    cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+   typedef short ac__type_sizeof_;
+int
+main ()
+{
+static int test_array @<:@1 - 2 * !(((long int) (sizeof (ac__type_sizeof_))) <= $ac_mid)@:>@;
+test_array @<:@0@:>@ = 0
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_hi=$ac_mid; break
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_lo=`expr $ac_mid + 1`
+                       if test $ac_lo -le $ac_mid; then
+                         ac_lo= ac_hi=
+                         break
+                       fi
+                       ac_mid=`expr 2 '*' $ac_mid + 1`
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+  done
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+   typedef short ac__type_sizeof_;
+int
+main ()
+{
+static int test_array @<:@1 - 2 * !(((long int) (sizeof (ac__type_sizeof_))) < 0)@:>@;
+test_array @<:@0@:>@ = 0
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_hi=-1 ac_mid=-1
+  while :; do
+    cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+   typedef short ac__type_sizeof_;
+int
+main ()
+{
+static int test_array @<:@1 - 2 * !(((long int) (sizeof (ac__type_sizeof_))) >= $ac_mid)@:>@;
+test_array @<:@0@:>@ = 0
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_lo=$ac_mid; break
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_hi=`expr '(' $ac_mid ')' - 1`
+                       if test $ac_mid -le $ac_hi; then
+                         ac_lo= ac_hi=
+                         break
+                       fi
+                       ac_mid=`expr 2 '*' $ac_mid`
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+  done
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_lo= ac_hi=
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+# Binary search between lo and hi bounds.
+while test "x$ac_lo" != "x$ac_hi"; do
+  ac_mid=`expr '(' $ac_hi - $ac_lo ')' / 2 + $ac_lo`
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+   typedef short ac__type_sizeof_;
+int
+main ()
+{
+static int test_array @<:@1 - 2 * !(((long int) (sizeof (ac__type_sizeof_))) <= $ac_mid)@:>@;
+test_array @<:@0@:>@ = 0
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_hi=$ac_mid
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_lo=`expr '(' $ac_mid ')' + 1`
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+done
+case $ac_lo in
+?*) ac_cv_sizeof_short=$ac_lo;;
+'') if test "$ac_cv_type_short" = yes; then
+     { { echo "$as_me:$LINENO: error: cannot compute sizeof (short)
+See \`config.log' for more details." >&5
+echo "$as_me: error: cannot compute sizeof (short)
+See \`config.log' for more details." >&2;}
+   { (exit 77); exit 77; }; }
+   else
+     ac_cv_sizeof_short=0
+   fi ;;
+esac
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+   typedef short ac__type_sizeof_;
+static long int longval () { return (long int) (sizeof (ac__type_sizeof_)); }
+static unsigned long int ulongval () { return (long int) (sizeof (ac__type_sizeof_)); }
+@%:@include <stdio.h>
+@%:@include <stdlib.h>
+int
+main ()
+{
+
+  FILE *f = fopen ("conftest.val", "w");
+  if (! f)
+    return 1;
+  if (((long int) (sizeof (ac__type_sizeof_))) < 0)
+    {
+      long int i = longval ();
+      if (i != ((long int) (sizeof (ac__type_sizeof_))))
+       return 1;
+      fprintf (f, "%ld\n", i);
+    }
+  else
+    {
+      unsigned long int i = ulongval ();
+      if (i != ((long int) (sizeof (ac__type_sizeof_))))
+       return 1;
+      fprintf (f, "%lu\n", i);
+    }
+  return ferror (f) || fclose (f) != 0;
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
+  { (case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_try") 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_sizeof_short=`cat conftest.val`
+else
+  echo "$as_me: program exited with status $ac_status" >&5
+echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+( exit $ac_status )
+if test "$ac_cv_type_short" = yes; then
+     { { echo "$as_me:$LINENO: error: cannot compute sizeof (short)
+See \`config.log' for more details." >&5
+echo "$as_me: error: cannot compute sizeof (short)
+See \`config.log' for more details." >&2;}
+   { (exit 77); exit 77; }; }
+   else
+     ac_cv_sizeof_short=0
+   fi
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f conftest.val
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_sizeof_short" >&5
+echo "${ECHO_T}$ac_cv_sizeof_short" >&6; }
+
+
+
+cat >>confdefs.h <<_ACEOF
+@%:@define SIZEOF_SHORT $ac_cv_sizeof_short
+_ACEOF
+
+
+{ echo "$as_me:$LINENO: checking for int" >&5
+echo $ECHO_N "checking for int... $ECHO_C" >&6; }
+if test "${ac_cv_type_int+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+typedef int ac__type_new_;
+int
+main ()
+{
+if ((ac__type_new_ *) 0)
+  return 0;
+if (sizeof (ac__type_new_))
+  return 0;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_cv_type_int=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_type_int=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_type_int" >&5
+echo "${ECHO_T}$ac_cv_type_int" >&6; }
+
+# The cast to long int works around a bug in the HP C Compiler
+# version HP92453-01 B.11.11.23709.GP, which incorrectly rejects
+# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'.
+# This bug is HP SR number 8606223364.
+{ echo "$as_me:$LINENO: checking size of int" >&5
+echo $ECHO_N "checking size of int... $ECHO_C" >&6; }
+if test "${ac_cv_sizeof_int+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if test "$cross_compiling" = yes; then
+  # Depending upon the size, compute the lo and hi bounds.
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+   typedef int ac__type_sizeof_;
+int
+main ()
+{
+static int test_array @<:@1 - 2 * !(((long int) (sizeof (ac__type_sizeof_))) >= 0)@:>@;
+test_array @<:@0@:>@ = 0
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_lo=0 ac_mid=0
+  while :; do
+    cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+   typedef int ac__type_sizeof_;
+int
+main ()
+{
+static int test_array @<:@1 - 2 * !(((long int) (sizeof (ac__type_sizeof_))) <= $ac_mid)@:>@;
+test_array @<:@0@:>@ = 0
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_hi=$ac_mid; break
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_lo=`expr $ac_mid + 1`
+                       if test $ac_lo -le $ac_mid; then
+                         ac_lo= ac_hi=
+                         break
+                       fi
+                       ac_mid=`expr 2 '*' $ac_mid + 1`
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+  done
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+   typedef int ac__type_sizeof_;
+int
+main ()
+{
+static int test_array @<:@1 - 2 * !(((long int) (sizeof (ac__type_sizeof_))) < 0)@:>@;
+test_array @<:@0@:>@ = 0
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_hi=-1 ac_mid=-1
+  while :; do
+    cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+   typedef int ac__type_sizeof_;
+int
+main ()
+{
+static int test_array @<:@1 - 2 * !(((long int) (sizeof (ac__type_sizeof_))) >= $ac_mid)@:>@;
+test_array @<:@0@:>@ = 0
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_lo=$ac_mid; break
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_hi=`expr '(' $ac_mid ')' - 1`
+                       if test $ac_mid -le $ac_hi; then
+                         ac_lo= ac_hi=
+                         break
+                       fi
+                       ac_mid=`expr 2 '*' $ac_mid`
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+  done
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_lo= ac_hi=
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+# Binary search between lo and hi bounds.
+while test "x$ac_lo" != "x$ac_hi"; do
+  ac_mid=`expr '(' $ac_hi - $ac_lo ')' / 2 + $ac_lo`
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+   typedef int ac__type_sizeof_;
+int
+main ()
+{
+static int test_array @<:@1 - 2 * !(((long int) (sizeof (ac__type_sizeof_))) <= $ac_mid)@:>@;
+test_array @<:@0@:>@ = 0
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_hi=$ac_mid
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_lo=`expr '(' $ac_mid ')' + 1`
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+done
+case $ac_lo in
+?*) ac_cv_sizeof_int=$ac_lo;;
+'') if test "$ac_cv_type_int" = yes; then
+     { { echo "$as_me:$LINENO: error: cannot compute sizeof (int)
+See \`config.log' for more details." >&5
+echo "$as_me: error: cannot compute sizeof (int)
+See \`config.log' for more details." >&2;}
+   { (exit 77); exit 77; }; }
+   else
+     ac_cv_sizeof_int=0
+   fi ;;
+esac
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+   typedef int ac__type_sizeof_;
+static long int longval () { return (long int) (sizeof (ac__type_sizeof_)); }
+static unsigned long int ulongval () { return (long int) (sizeof (ac__type_sizeof_)); }
+@%:@include <stdio.h>
+@%:@include <stdlib.h>
+int
+main ()
+{
+
+  FILE *f = fopen ("conftest.val", "w");
+  if (! f)
+    return 1;
+  if (((long int) (sizeof (ac__type_sizeof_))) < 0)
+    {
+      long int i = longval ();
+      if (i != ((long int) (sizeof (ac__type_sizeof_))))
+       return 1;
+      fprintf (f, "%ld\n", i);
+    }
+  else
+    {
+      unsigned long int i = ulongval ();
+      if (i != ((long int) (sizeof (ac__type_sizeof_))))
+       return 1;
+      fprintf (f, "%lu\n", i);
+    }
+  return ferror (f) || fclose (f) != 0;
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
+  { (case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_try") 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_sizeof_int=`cat conftest.val`
+else
+  echo "$as_me: program exited with status $ac_status" >&5
+echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+( exit $ac_status )
+if test "$ac_cv_type_int" = yes; then
+     { { echo "$as_me:$LINENO: error: cannot compute sizeof (int)
+See \`config.log' for more details." >&5
+echo "$as_me: error: cannot compute sizeof (int)
+See \`config.log' for more details." >&2;}
+   { (exit 77); exit 77; }; }
+   else
+     ac_cv_sizeof_int=0
+   fi
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f conftest.val
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_sizeof_int" >&5
+echo "${ECHO_T}$ac_cv_sizeof_int" >&6; }
+
+
+
+cat >>confdefs.h <<_ACEOF
+@%:@define SIZEOF_INT $ac_cv_sizeof_int
+_ACEOF
+
+
+{ echo "$as_me:$LINENO: checking for long" >&5
+echo $ECHO_N "checking for long... $ECHO_C" >&6; }
+if test "${ac_cv_type_long+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+typedef long ac__type_new_;
+int
+main ()
+{
+if ((ac__type_new_ *) 0)
+  return 0;
+if (sizeof (ac__type_new_))
+  return 0;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_cv_type_long=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_type_long=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_type_long" >&5
+echo "${ECHO_T}$ac_cv_type_long" >&6; }
+
+# The cast to long int works around a bug in the HP C Compiler
+# version HP92453-01 B.11.11.23709.GP, which incorrectly rejects
+# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'.
+# This bug is HP SR number 8606223364.
+{ echo "$as_me:$LINENO: checking size of long" >&5
+echo $ECHO_N "checking size of long... $ECHO_C" >&6; }
+if test "${ac_cv_sizeof_long+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if test "$cross_compiling" = yes; then
+  # Depending upon the size, compute the lo and hi bounds.
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+   typedef long ac__type_sizeof_;
+int
+main ()
+{
+static int test_array @<:@1 - 2 * !(((long int) (sizeof (ac__type_sizeof_))) >= 0)@:>@;
+test_array @<:@0@:>@ = 0
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_lo=0 ac_mid=0
+  while :; do
+    cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+   typedef long ac__type_sizeof_;
+int
+main ()
+{
+static int test_array @<:@1 - 2 * !(((long int) (sizeof (ac__type_sizeof_))) <= $ac_mid)@:>@;
+test_array @<:@0@:>@ = 0
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_hi=$ac_mid; break
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_lo=`expr $ac_mid + 1`
+                       if test $ac_lo -le $ac_mid; then
+                         ac_lo= ac_hi=
+                         break
+                       fi
+                       ac_mid=`expr 2 '*' $ac_mid + 1`
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+  done
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+   typedef long ac__type_sizeof_;
+int
+main ()
+{
+static int test_array @<:@1 - 2 * !(((long int) (sizeof (ac__type_sizeof_))) < 0)@:>@;
+test_array @<:@0@:>@ = 0
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_hi=-1 ac_mid=-1
+  while :; do
+    cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+   typedef long ac__type_sizeof_;
+int
+main ()
+{
+static int test_array @<:@1 - 2 * !(((long int) (sizeof (ac__type_sizeof_))) >= $ac_mid)@:>@;
+test_array @<:@0@:>@ = 0
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_lo=$ac_mid; break
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_hi=`expr '(' $ac_mid ')' - 1`
+                       if test $ac_mid -le $ac_hi; then
+                         ac_lo= ac_hi=
+                         break
+                       fi
+                       ac_mid=`expr 2 '*' $ac_mid`
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+  done
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_lo= ac_hi=
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+# Binary search between lo and hi bounds.
+while test "x$ac_lo" != "x$ac_hi"; do
+  ac_mid=`expr '(' $ac_hi - $ac_lo ')' / 2 + $ac_lo`
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+   typedef long ac__type_sizeof_;
+int
+main ()
+{
+static int test_array @<:@1 - 2 * !(((long int) (sizeof (ac__type_sizeof_))) <= $ac_mid)@:>@;
+test_array @<:@0@:>@ = 0
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_hi=$ac_mid
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_lo=`expr '(' $ac_mid ')' + 1`
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+done
+case $ac_lo in
+?*) ac_cv_sizeof_long=$ac_lo;;
+'') if test "$ac_cv_type_long" = yes; then
+     { { echo "$as_me:$LINENO: error: cannot compute sizeof (long)
+See \`config.log' for more details." >&5
+echo "$as_me: error: cannot compute sizeof (long)
+See \`config.log' for more details." >&2;}
+   { (exit 77); exit 77; }; }
+   else
+     ac_cv_sizeof_long=0
+   fi ;;
+esac
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+   typedef long ac__type_sizeof_;
+static long int longval () { return (long int) (sizeof (ac__type_sizeof_)); }
+static unsigned long int ulongval () { return (long int) (sizeof (ac__type_sizeof_)); }
+@%:@include <stdio.h>
+@%:@include <stdlib.h>
+int
+main ()
+{
+
+  FILE *f = fopen ("conftest.val", "w");
+  if (! f)
+    return 1;
+  if (((long int) (sizeof (ac__type_sizeof_))) < 0)
+    {
+      long int i = longval ();
+      if (i != ((long int) (sizeof (ac__type_sizeof_))))
+       return 1;
+      fprintf (f, "%ld\n", i);
+    }
+  else
+    {
+      unsigned long int i = ulongval ();
+      if (i != ((long int) (sizeof (ac__type_sizeof_))))
+       return 1;
+      fprintf (f, "%lu\n", i);
+    }
+  return ferror (f) || fclose (f) != 0;
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
+  { (case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_try") 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_sizeof_long=`cat conftest.val`
+else
+  echo "$as_me: program exited with status $ac_status" >&5
+echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+( exit $ac_status )
+if test "$ac_cv_type_long" = yes; then
+     { { echo "$as_me:$LINENO: error: cannot compute sizeof (long)
+See \`config.log' for more details." >&5
+echo "$as_me: error: cannot compute sizeof (long)
+See \`config.log' for more details." >&2;}
+   { (exit 77); exit 77; }; }
+   else
+     ac_cv_sizeof_long=0
+   fi
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f conftest.val
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_sizeof_long" >&5
+echo "${ECHO_T}$ac_cv_sizeof_long" >&6; }
+
+
+
+cat >>confdefs.h <<_ACEOF
+@%:@define SIZEOF_LONG $ac_cv_sizeof_long
+_ACEOF
+
+
+{ echo "$as_me:$LINENO: checking for void *" >&5
+echo $ECHO_N "checking for void *... $ECHO_C" >&6; }
+if test "${ac_cv_type_void_p+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+typedef void * ac__type_new_;
+int
+main ()
+{
+if ((ac__type_new_ *) 0)
+  return 0;
+if (sizeof (ac__type_new_))
+  return 0;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_cv_type_void_p=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_type_void_p=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_type_void_p" >&5
+echo "${ECHO_T}$ac_cv_type_void_p" >&6; }
+
+# The cast to long int works around a bug in the HP C Compiler
+# version HP92453-01 B.11.11.23709.GP, which incorrectly rejects
+# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'.
+# This bug is HP SR number 8606223364.
+{ echo "$as_me:$LINENO: checking size of void *" >&5
+echo $ECHO_N "checking size of void *... $ECHO_C" >&6; }
+if test "${ac_cv_sizeof_void_p+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if test "$cross_compiling" = yes; then
+  # Depending upon the size, compute the lo and hi bounds.
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+   typedef void * ac__type_sizeof_;
+int
+main ()
+{
+static int test_array @<:@1 - 2 * !(((long int) (sizeof (ac__type_sizeof_))) >= 0)@:>@;
+test_array @<:@0@:>@ = 0
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_lo=0 ac_mid=0
+  while :; do
+    cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+   typedef void * ac__type_sizeof_;
+int
+main ()
+{
+static int test_array @<:@1 - 2 * !(((long int) (sizeof (ac__type_sizeof_))) <= $ac_mid)@:>@;
+test_array @<:@0@:>@ = 0
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_hi=$ac_mid; break
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_lo=`expr $ac_mid + 1`
+                       if test $ac_lo -le $ac_mid; then
+                         ac_lo= ac_hi=
+                         break
+                       fi
+                       ac_mid=`expr 2 '*' $ac_mid + 1`
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+  done
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+   typedef void * ac__type_sizeof_;
+int
+main ()
+{
+static int test_array @<:@1 - 2 * !(((long int) (sizeof (ac__type_sizeof_))) < 0)@:>@;
+test_array @<:@0@:>@ = 0
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_hi=-1 ac_mid=-1
+  while :; do
+    cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+   typedef void * ac__type_sizeof_;
+int
+main ()
+{
+static int test_array @<:@1 - 2 * !(((long int) (sizeof (ac__type_sizeof_))) >= $ac_mid)@:>@;
+test_array @<:@0@:>@ = 0
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_lo=$ac_mid; break
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_hi=`expr '(' $ac_mid ')' - 1`
+                       if test $ac_mid -le $ac_hi; then
+                         ac_lo= ac_hi=
+                         break
+                       fi
+                       ac_mid=`expr 2 '*' $ac_mid`
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+  done
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_lo= ac_hi=
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+# Binary search between lo and hi bounds.
+while test "x$ac_lo" != "x$ac_hi"; do
+  ac_mid=`expr '(' $ac_hi - $ac_lo ')' / 2 + $ac_lo`
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+   typedef void * ac__type_sizeof_;
+int
+main ()
+{
+static int test_array @<:@1 - 2 * !(((long int) (sizeof (ac__type_sizeof_))) <= $ac_mid)@:>@;
+test_array @<:@0@:>@ = 0
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_hi=$ac_mid
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_lo=`expr '(' $ac_mid ')' + 1`
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+done
+case $ac_lo in
+?*) ac_cv_sizeof_void_p=$ac_lo;;
+'') if test "$ac_cv_type_void_p" = yes; then
+     { { echo "$as_me:$LINENO: error: cannot compute sizeof (void *)
+See \`config.log' for more details." >&5
+echo "$as_me: error: cannot compute sizeof (void *)
+See \`config.log' for more details." >&2;}
+   { (exit 77); exit 77; }; }
+   else
+     ac_cv_sizeof_void_p=0
+   fi ;;
+esac
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+   typedef void * ac__type_sizeof_;
+static long int longval () { return (long int) (sizeof (ac__type_sizeof_)); }
+static unsigned long int ulongval () { return (long int) (sizeof (ac__type_sizeof_)); }
+@%:@include <stdio.h>
+@%:@include <stdlib.h>
+int
+main ()
+{
+
+  FILE *f = fopen ("conftest.val", "w");
+  if (! f)
+    return 1;
+  if (((long int) (sizeof (ac__type_sizeof_))) < 0)
+    {
+      long int i = longval ();
+      if (i != ((long int) (sizeof (ac__type_sizeof_))))
+       return 1;
+      fprintf (f, "%ld\n", i);
+    }
+  else
+    {
+      unsigned long int i = ulongval ();
+      if (i != ((long int) (sizeof (ac__type_sizeof_))))
+       return 1;
+      fprintf (f, "%lu\n", i);
+    }
+  return ferror (f) || fclose (f) != 0;
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
+  { (case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_try") 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_sizeof_void_p=`cat conftest.val`
+else
+  echo "$as_me: program exited with status $ac_status" >&5
+echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+( exit $ac_status )
+if test "$ac_cv_type_void_p" = yes; then
+     { { echo "$as_me:$LINENO: error: cannot compute sizeof (void *)
+See \`config.log' for more details." >&5
+echo "$as_me: error: cannot compute sizeof (void *)
+See \`config.log' for more details." >&2;}
+   { (exit 77); exit 77; }; }
+   else
+     ac_cv_sizeof_void_p=0
+   fi
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f conftest.val
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_sizeof_void_p" >&5
+echo "${ECHO_T}$ac_cv_sizeof_void_p" >&6; }
+
+
+
+cat >>confdefs.h <<_ACEOF
+@%:@define SIZEOF_VOID_P $ac_cv_sizeof_void_p
+_ACEOF
+
+
+{ echo "$as_me:$LINENO: checking for int64_t" >&5
+echo $ECHO_N "checking for int64_t... $ECHO_C" >&6; }
+if test "${ac_cv_type_int64_t+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+typedef int64_t ac__type_new_;
+int
+main ()
+{
+if ((ac__type_new_ *) 0)
+  return 0;
+if (sizeof (ac__type_new_))
+  return 0;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_cv_type_int64_t=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_type_int64_t=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_type_int64_t" >&5
+echo "${ECHO_T}$ac_cv_type_int64_t" >&6; }
+
+# The cast to long int works around a bug in the HP C Compiler
+# version HP92453-01 B.11.11.23709.GP, which incorrectly rejects
+# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'.
+# This bug is HP SR number 8606223364.
+{ echo "$as_me:$LINENO: checking size of int64_t" >&5
+echo $ECHO_N "checking size of int64_t... $ECHO_C" >&6; }
+if test "${ac_cv_sizeof_int64_t+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if test "$cross_compiling" = yes; then
+  # Depending upon the size, compute the lo and hi bounds.
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+   typedef int64_t ac__type_sizeof_;
+int
+main ()
+{
+static int test_array @<:@1 - 2 * !(((long int) (sizeof (ac__type_sizeof_))) >= 0)@:>@;
+test_array @<:@0@:>@ = 0
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_lo=0 ac_mid=0
+  while :; do
+    cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+   typedef int64_t ac__type_sizeof_;
+int
+main ()
+{
+static int test_array @<:@1 - 2 * !(((long int) (sizeof (ac__type_sizeof_))) <= $ac_mid)@:>@;
+test_array @<:@0@:>@ = 0
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_hi=$ac_mid; break
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_lo=`expr $ac_mid + 1`
+                       if test $ac_lo -le $ac_mid; then
+                         ac_lo= ac_hi=
+                         break
+                       fi
+                       ac_mid=`expr 2 '*' $ac_mid + 1`
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+  done
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+   typedef int64_t ac__type_sizeof_;
+int
+main ()
+{
+static int test_array @<:@1 - 2 * !(((long int) (sizeof (ac__type_sizeof_))) < 0)@:>@;
+test_array @<:@0@:>@ = 0
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_hi=-1 ac_mid=-1
+  while :; do
+    cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+   typedef int64_t ac__type_sizeof_;
+int
+main ()
+{
+static int test_array @<:@1 - 2 * !(((long int) (sizeof (ac__type_sizeof_))) >= $ac_mid)@:>@;
+test_array @<:@0@:>@ = 0
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_lo=$ac_mid; break
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_hi=`expr '(' $ac_mid ')' - 1`
+                       if test $ac_mid -le $ac_hi; then
+                         ac_lo= ac_hi=
+                         break
+                       fi
+                       ac_mid=`expr 2 '*' $ac_mid`
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+  done
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_lo= ac_hi=
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+# Binary search between lo and hi bounds.
+while test "x$ac_lo" != "x$ac_hi"; do
+  ac_mid=`expr '(' $ac_hi - $ac_lo ')' / 2 + $ac_lo`
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+   typedef int64_t ac__type_sizeof_;
+int
+main ()
+{
+static int test_array @<:@1 - 2 * !(((long int) (sizeof (ac__type_sizeof_))) <= $ac_mid)@:>@;
+test_array @<:@0@:>@ = 0
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_hi=$ac_mid
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_lo=`expr '(' $ac_mid ')' + 1`
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+done
+case $ac_lo in
+?*) ac_cv_sizeof_int64_t=$ac_lo;;
+'') if test "$ac_cv_type_int64_t" = yes; then
+     { { echo "$as_me:$LINENO: error: cannot compute sizeof (int64_t)
+See \`config.log' for more details." >&5
+echo "$as_me: error: cannot compute sizeof (int64_t)
+See \`config.log' for more details." >&2;}
+   { (exit 77); exit 77; }; }
+   else
+     ac_cv_sizeof_int64_t=0
+   fi ;;
+esac
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+   typedef int64_t ac__type_sizeof_;
+static long int longval () { return (long int) (sizeof (ac__type_sizeof_)); }
+static unsigned long int ulongval () { return (long int) (sizeof (ac__type_sizeof_)); }
+@%:@include <stdio.h>
+@%:@include <stdlib.h>
+int
+main ()
+{
+
+  FILE *f = fopen ("conftest.val", "w");
+  if (! f)
+    return 1;
+  if (((long int) (sizeof (ac__type_sizeof_))) < 0)
+    {
+      long int i = longval ();
+      if (i != ((long int) (sizeof (ac__type_sizeof_))))
+       return 1;
+      fprintf (f, "%ld\n", i);
+    }
+  else
+    {
+      unsigned long int i = ulongval ();
+      if (i != ((long int) (sizeof (ac__type_sizeof_))))
+       return 1;
+      fprintf (f, "%lu\n", i);
+    }
+  return ferror (f) || fclose (f) != 0;
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
+  { (case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_try") 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_sizeof_int64_t=`cat conftest.val`
+else
+  echo "$as_me: program exited with status $ac_status" >&5
+echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+( exit $ac_status )
+if test "$ac_cv_type_int64_t" = yes; then
+     { { echo "$as_me:$LINENO: error: cannot compute sizeof (int64_t)
+See \`config.log' for more details." >&5
+echo "$as_me: error: cannot compute sizeof (int64_t)
+See \`config.log' for more details." >&2;}
+   { (exit 77); exit 77; }; }
+   else
+     ac_cv_sizeof_int64_t=0
+   fi
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f conftest.val
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_sizeof_int64_t" >&5
+echo "${ECHO_T}$ac_cv_sizeof_int64_t" >&6; }
+
+
+
+cat >>confdefs.h <<_ACEOF
+@%:@define SIZEOF_INT64_T $ac_cv_sizeof_int64_t
+_ACEOF
+
+
+{ echo "$as_me:$LINENO: checking for long long" >&5
+echo $ECHO_N "checking for long long... $ECHO_C" >&6; }
+if test "${ac_cv_type_long_long+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+typedef long long ac__type_new_;
+int
+main ()
+{
+if ((ac__type_new_ *) 0)
+  return 0;
+if (sizeof (ac__type_new_))
+  return 0;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_cv_type_long_long=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_type_long_long=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_type_long_long" >&5
+echo "${ECHO_T}$ac_cv_type_long_long" >&6; }
+
+# The cast to long int works around a bug in the HP C Compiler
+# version HP92453-01 B.11.11.23709.GP, which incorrectly rejects
+# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'.
+# This bug is HP SR number 8606223364.
+{ echo "$as_me:$LINENO: checking size of long long" >&5
+echo $ECHO_N "checking size of long long... $ECHO_C" >&6; }
+if test "${ac_cv_sizeof_long_long+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if test "$cross_compiling" = yes; then
+  # Depending upon the size, compute the lo and hi bounds.
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+   typedef long long ac__type_sizeof_;
+int
+main ()
+{
+static int test_array @<:@1 - 2 * !(((long int) (sizeof (ac__type_sizeof_))) >= 0)@:>@;
+test_array @<:@0@:>@ = 0
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_lo=0 ac_mid=0
+  while :; do
+    cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+   typedef long long ac__type_sizeof_;
+int
+main ()
+{
+static int test_array @<:@1 - 2 * !(((long int) (sizeof (ac__type_sizeof_))) <= $ac_mid)@:>@;
+test_array @<:@0@:>@ = 0
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_hi=$ac_mid; break
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_lo=`expr $ac_mid + 1`
+                       if test $ac_lo -le $ac_mid; then
+                         ac_lo= ac_hi=
+                         break
+                       fi
+                       ac_mid=`expr 2 '*' $ac_mid + 1`
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+  done
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+   typedef long long ac__type_sizeof_;
+int
+main ()
+{
+static int test_array @<:@1 - 2 * !(((long int) (sizeof (ac__type_sizeof_))) < 0)@:>@;
+test_array @<:@0@:>@ = 0
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_hi=-1 ac_mid=-1
+  while :; do
+    cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+   typedef long long ac__type_sizeof_;
+int
+main ()
+{
+static int test_array @<:@1 - 2 * !(((long int) (sizeof (ac__type_sizeof_))) >= $ac_mid)@:>@;
+test_array @<:@0@:>@ = 0
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_lo=$ac_mid; break
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_hi=`expr '(' $ac_mid ')' - 1`
+                       if test $ac_mid -le $ac_hi; then
+                         ac_lo= ac_hi=
+                         break
+                       fi
+                       ac_mid=`expr 2 '*' $ac_mid`
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+  done
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_lo= ac_hi=
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+# Binary search between lo and hi bounds.
+while test "x$ac_lo" != "x$ac_hi"; do
+  ac_mid=`expr '(' $ac_hi - $ac_lo ')' / 2 + $ac_lo`
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+   typedef long long ac__type_sizeof_;
+int
+main ()
+{
+static int test_array @<:@1 - 2 * !(((long int) (sizeof (ac__type_sizeof_))) <= $ac_mid)@:>@;
+test_array @<:@0@:>@ = 0
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_hi=$ac_mid
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_lo=`expr '(' $ac_mid ')' + 1`
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+done
+case $ac_lo in
+?*) ac_cv_sizeof_long_long=$ac_lo;;
+'') if test "$ac_cv_type_long_long" = yes; then
+     { { echo "$as_me:$LINENO: error: cannot compute sizeof (long long)
+See \`config.log' for more details." >&5
+echo "$as_me: error: cannot compute sizeof (long long)
+See \`config.log' for more details." >&2;}
+   { (exit 77); exit 77; }; }
+   else
+     ac_cv_sizeof_long_long=0
+   fi ;;
+esac
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+   typedef long long ac__type_sizeof_;
+static long int longval () { return (long int) (sizeof (ac__type_sizeof_)); }
+static unsigned long int ulongval () { return (long int) (sizeof (ac__type_sizeof_)); }
+@%:@include <stdio.h>
+@%:@include <stdlib.h>
+int
+main ()
+{
+
+  FILE *f = fopen ("conftest.val", "w");
+  if (! f)
+    return 1;
+  if (((long int) (sizeof (ac__type_sizeof_))) < 0)
+    {
+      long int i = longval ();
+      if (i != ((long int) (sizeof (ac__type_sizeof_))))
+       return 1;
+      fprintf (f, "%ld\n", i);
+    }
+  else
+    {
+      unsigned long int i = ulongval ();
+      if (i != ((long int) (sizeof (ac__type_sizeof_))))
+       return 1;
+      fprintf (f, "%lu\n", i);
+    }
+  return ferror (f) || fclose (f) != 0;
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
+  { (case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_try") 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_sizeof_long_long=`cat conftest.val`
+else
+  echo "$as_me: program exited with status $ac_status" >&5
+echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+( exit $ac_status )
+if test "$ac_cv_type_long_long" = yes; then
+     { { echo "$as_me:$LINENO: error: cannot compute sizeof (long long)
+See \`config.log' for more details." >&5
+echo "$as_me: error: cannot compute sizeof (long long)
+See \`config.log' for more details." >&2;}
+   { (exit 77); exit 77; }; }
+   else
+     ac_cv_sizeof_long_long=0
+   fi
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f conftest.val
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_sizeof_long_long" >&5
+echo "${ECHO_T}$ac_cv_sizeof_long_long" >&6; }
+
+
+
+cat >>confdefs.h <<_ACEOF
+@%:@define SIZEOF_LONG_LONG $ac_cv_sizeof_long_long
+_ACEOF
+
+
+if test "$ac_cv_sizeof_int" = 2 ; then
+  { echo "$as_me:$LINENO: checking for int16_t" >&5
+echo $ECHO_N "checking for int16_t... $ECHO_C" >&6; }
+if test "${ac_cv_type_int16_t+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+typedef int16_t ac__type_new_;
+int
+main ()
+{
+if ((ac__type_new_ *) 0)
+  return 0;
+if (sizeof (ac__type_new_))
+  return 0;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_cv_type_int16_t=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_type_int16_t=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_type_int16_t" >&5
+echo "${ECHO_T}$ac_cv_type_int16_t" >&6; }
+if test $ac_cv_type_int16_t = yes; then
+  :
+else
+  
+cat >>confdefs.h <<_ACEOF
+@%:@define int16_t int
+_ACEOF
+
+fi
+
+  { echo "$as_me:$LINENO: checking for uint16_t" >&5
+echo $ECHO_N "checking for uint16_t... $ECHO_C" >&6; }
+if test "${ac_cv_type_uint16_t+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+typedef uint16_t ac__type_new_;
+int
+main ()
+{
+if ((ac__type_new_ *) 0)
+  return 0;
+if (sizeof (ac__type_new_))
+  return 0;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_cv_type_uint16_t=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_type_uint16_t=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_type_uint16_t" >&5
+echo "${ECHO_T}$ac_cv_type_uint16_t" >&6; }
+if test $ac_cv_type_uint16_t = yes; then
+  :
+else
+  
+cat >>confdefs.h <<_ACEOF
+@%:@define uint16_t unsigned int
+_ACEOF
+
+fi
+
+elif test "$ac_cv_sizeof_short" = 2 ; then
+  { echo "$as_me:$LINENO: checking for int16_t" >&5
+echo $ECHO_N "checking for int16_t... $ECHO_C" >&6; }
+if test "${ac_cv_type_int16_t+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+typedef int16_t ac__type_new_;
+int
+main ()
+{
+if ((ac__type_new_ *) 0)
+  return 0;
+if (sizeof (ac__type_new_))
+  return 0;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_cv_type_int16_t=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_type_int16_t=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_type_int16_t" >&5
+echo "${ECHO_T}$ac_cv_type_int16_t" >&6; }
+if test $ac_cv_type_int16_t = yes; then
+  :
+else
+  
+cat >>confdefs.h <<_ACEOF
+@%:@define int16_t short
+_ACEOF
+
+fi
+
+  { echo "$as_me:$LINENO: checking for uint16_t" >&5
+echo $ECHO_N "checking for uint16_t... $ECHO_C" >&6; }
+if test "${ac_cv_type_uint16_t+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+typedef uint16_t ac__type_new_;
+int
+main ()
+{
+if ((ac__type_new_ *) 0)
+  return 0;
+if (sizeof (ac__type_new_))
+  return 0;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_cv_type_uint16_t=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_type_uint16_t=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_type_uint16_t" >&5
+echo "${ECHO_T}$ac_cv_type_uint16_t" >&6; }
+if test $ac_cv_type_uint16_t = yes; then
+  :
+else
+  
+cat >>confdefs.h <<_ACEOF
+@%:@define uint16_t unsigned short
+_ACEOF
+
+fi
+
+else
+  { { echo "$as_me:$LINENO: error: Cannot find a type with size of 16 bits" >&5
+echo "$as_me: error: Cannot find a type with size of 16 bits" >&2;}
+   { (exit 1); exit 1; }; }
+fi
+if test "$ac_cv_sizeof_int" = 4 ; then
+  { echo "$as_me:$LINENO: checking for int32_t" >&5
+echo $ECHO_N "checking for int32_t... $ECHO_C" >&6; }
+if test "${ac_cv_type_int32_t+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+typedef int32_t ac__type_new_;
+int
+main ()
+{
+if ((ac__type_new_ *) 0)
+  return 0;
+if (sizeof (ac__type_new_))
+  return 0;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_cv_type_int32_t=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_type_int32_t=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_type_int32_t" >&5
+echo "${ECHO_T}$ac_cv_type_int32_t" >&6; }
+if test $ac_cv_type_int32_t = yes; then
+  :
+else
+  
+cat >>confdefs.h <<_ACEOF
+@%:@define int32_t int
+_ACEOF
+
+fi
+
+  { echo "$as_me:$LINENO: checking for uint32_t" >&5
+echo $ECHO_N "checking for uint32_t... $ECHO_C" >&6; }
+if test "${ac_cv_type_uint32_t+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+typedef uint32_t ac__type_new_;
+int
+main ()
+{
+if ((ac__type_new_ *) 0)
+  return 0;
+if (sizeof (ac__type_new_))
+  return 0;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_cv_type_uint32_t=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_type_uint32_t=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_type_uint32_t" >&5
+echo "${ECHO_T}$ac_cv_type_uint32_t" >&6; }
+if test $ac_cv_type_uint32_t = yes; then
+  :
+else
+  
+cat >>confdefs.h <<_ACEOF
+@%:@define uint32_t unsigned int
+_ACEOF
+
+fi
+
+elif test "$ac_cv_sizeof_short" = 4 ; then
+  { echo "$as_me:$LINENO: checking for int32_t" >&5
+echo $ECHO_N "checking for int32_t... $ECHO_C" >&6; }
+if test "${ac_cv_type_int32_t+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+typedef int32_t ac__type_new_;
+int
+main ()
+{
+if ((ac__type_new_ *) 0)
+  return 0;
+if (sizeof (ac__type_new_))
+  return 0;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_cv_type_int32_t=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_type_int32_t=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_type_int32_t" >&5
+echo "${ECHO_T}$ac_cv_type_int32_t" >&6; }
+if test $ac_cv_type_int32_t = yes; then
+  :
+else
+  
+cat >>confdefs.h <<_ACEOF
+@%:@define int32_t short
+_ACEOF
+
+fi
+
+  { echo "$as_me:$LINENO: checking for uint32_t" >&5
+echo $ECHO_N "checking for uint32_t... $ECHO_C" >&6; }
+if test "${ac_cv_type_uint32_t+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+typedef uint32_t ac__type_new_;
+int
+main ()
+{
+if ((ac__type_new_ *) 0)
+  return 0;
+if (sizeof (ac__type_new_))
+  return 0;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_cv_type_uint32_t=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_type_uint32_t=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_type_uint32_t" >&5
+echo "${ECHO_T}$ac_cv_type_uint32_t" >&6; }
+if test $ac_cv_type_uint32_t = yes; then
+  :
+else
+  
+cat >>confdefs.h <<_ACEOF
+@%:@define uint32_t unsigned short
+_ACEOF
+
+fi
+
+elif test "$ac_cv_sizeof_long" = 4 ; then
+  { echo "$as_me:$LINENO: checking for int32_t" >&5
+echo $ECHO_N "checking for int32_t... $ECHO_C" >&6; }
+if test "${ac_cv_type_int32_t+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+typedef int32_t ac__type_new_;
+int
+main ()
+{
+if ((ac__type_new_ *) 0)
+  return 0;
+if (sizeof (ac__type_new_))
+  return 0;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_cv_type_int32_t=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_type_int32_t=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_type_int32_t" >&5
+echo "${ECHO_T}$ac_cv_type_int32_t" >&6; }
+if test $ac_cv_type_int32_t = yes; then
+  :
+else
+  
+cat >>confdefs.h <<_ACEOF
+@%:@define int32_t long
+_ACEOF
+
+fi
+
+  { echo "$as_me:$LINENO: checking for uint32_t" >&5
+echo $ECHO_N "checking for uint32_t... $ECHO_C" >&6; }
+if test "${ac_cv_type_uint32_t+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+typedef uint32_t ac__type_new_;
+int
+main ()
+{
+if ((ac__type_new_ *) 0)
+  return 0;
+if (sizeof (ac__type_new_))
+  return 0;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_cv_type_uint32_t=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_type_uint32_t=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_type_uint32_t" >&5
+echo "${ECHO_T}$ac_cv_type_uint32_t" >&6; }
+if test $ac_cv_type_uint32_t = yes; then
+  :
+else
+  
+cat >>confdefs.h <<_ACEOF
+@%:@define uint32_t unsigned long
+_ACEOF
+
+fi
+
+else
+  { { echo "$as_me:$LINENO: error: Cannot find a type with size of 32 bits" >&5
+echo "$as_me: error: Cannot find a type with size of 32 bits" >&2;}
+   { (exit 1); exit 1; }; }
+fi
+if test "$ac_cv_sizeof_int64_t" = 8 ; then
+  { echo "$as_me:$LINENO: checking for int64_t" >&5
+echo $ECHO_N "checking for int64_t... $ECHO_C" >&6; }
+if test "${ac_cv_type_int64_t+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+typedef int64_t ac__type_new_;
+int
+main ()
+{
+if ((ac__type_new_ *) 0)
+  return 0;
+if (sizeof (ac__type_new_))
+  return 0;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_cv_type_int64_t=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_type_int64_t=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_type_int64_t" >&5
+echo "${ECHO_T}$ac_cv_type_int64_t" >&6; }
+
+  { echo "$as_me:$LINENO: checking for uint64_t" >&5
+echo $ECHO_N "checking for uint64_t... $ECHO_C" >&6; }
+if test "${ac_cv_type_uint64_t+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+typedef uint64_t ac__type_new_;
+int
+main ()
+{
+if ((ac__type_new_ *) 0)
+  return 0;
+if (sizeof (ac__type_new_))
+  return 0;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_cv_type_uint64_t=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_type_uint64_t=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_type_uint64_t" >&5
+echo "${ECHO_T}$ac_cv_type_uint64_t" >&6; }
+
+elif test "$ac_cv_sizeof_long_long" = 8 ; then
+  { echo "$as_me:$LINENO: checking for int64_t" >&5
+echo $ECHO_N "checking for int64_t... $ECHO_C" >&6; }
+if test "${ac_cv_type_int64_t+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+typedef int64_t ac__type_new_;
+int
+main ()
+{
+if ((ac__type_new_ *) 0)
+  return 0;
+if (sizeof (ac__type_new_))
+  return 0;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_cv_type_int64_t=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_type_int64_t=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_type_int64_t" >&5
+echo "${ECHO_T}$ac_cv_type_int64_t" >&6; }
+if test $ac_cv_type_int64_t = yes; then
+  :
+else
+  
+cat >>confdefs.h <<_ACEOF
+@%:@define int64_t long long
+_ACEOF
+
+fi
+
+  { echo "$as_me:$LINENO: checking for uint64_t" >&5
+echo $ECHO_N "checking for uint64_t... $ECHO_C" >&6; }
+if test "${ac_cv_type_uint64_t+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+typedef uint64_t ac__type_new_;
+int
+main ()
+{
+if ((ac__type_new_ *) 0)
+  return 0;
+if (sizeof (ac__type_new_))
+  return 0;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_cv_type_uint64_t=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_type_uint64_t=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_type_uint64_t" >&5
+echo "${ECHO_T}$ac_cv_type_uint64_t" >&6; }
+if test $ac_cv_type_uint64_t = yes; then
+  :
+else
+  
+cat >>confdefs.h <<_ACEOF
+@%:@define uint64_t unsigned long long
+_ACEOF
+
+fi
+
+else
+  { { echo "$as_me:$LINENO: error: Cannot find a type with size of 64 bits" >&5
+echo "$as_me: error: Cannot find a type with size of 64 bits" >&2;}
+   { (exit 1); exit 1; }; }
+fi
+{ echo "$as_me:$LINENO: checking for struct sockaddr_in6" >&5
+echo $ECHO_N "checking for struct sockaddr_in6... $ECHO_C" >&6; }
+if test "${ac_cv_type_struct_sockaddr_in6+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <sys/types.h>
+#include <netinet/in.h>
+
+typedef struct sockaddr_in6 ac__type_new_;
+int
+main ()
+{
+if ((ac__type_new_ *) 0)
+  return 0;
+if (sizeof (ac__type_new_))
+  return 0;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_cv_type_struct_sockaddr_in6=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_type_struct_sockaddr_in6=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_type_struct_sockaddr_in6" >&5
+echo "${ECHO_T}$ac_cv_type_struct_sockaddr_in6" >&6; }
+if test $ac_cv_type_struct_sockaddr_in6 = yes; then
+  unet_have_sockaddr_in6="yes"
+else
+  unet_have_sockaddr_in6="no"
+fi
+
+
+{ echo "$as_me:$LINENO: checking for socklen_t" >&5
+echo $ECHO_N "checking for socklen_t... $ECHO_C" >&6; }
+if test "${ac_cv_type_socklen_t+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <sys/types.h>
+#include<sys/socket.h>
+
+typedef socklen_t ac__type_new_;
+int
+main ()
+{
+if ((ac__type_new_ *) 0)
+  return 0;
+if (sizeof (ac__type_new_))
+  return 0;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_cv_type_socklen_t=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_type_socklen_t=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_type_socklen_t" >&5
+echo "${ECHO_T}$ac_cv_type_socklen_t" >&6; }
+if test $ac_cv_type_socklen_t = yes; then
+  :
+else
+  
+  { echo "$as_me:$LINENO: checking for socklen_t equivalent" >&5
+echo $ECHO_N "checking for socklen_t equivalent... $ECHO_C" >&6; }
+  if test "${curl_cv_socklen_t_equiv+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  
+    curl_cv_socklen_t_equiv=
+    for arg2 in "struct sockaddr" void ; do
+      for t in int size_t unsigned long "unsigned long" ; do
+        cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <sys/types.h>
+#include <sys/socket.h>
+int getpeername (int $arg2 *, $t *);
+int
+main ()
+{
+$t len;
+  getpeername(0, 0, &len);
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  curl_cv_socklen_t_equiv="$t"
+  break
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+      done
+    done
+  
+fi
+
+  { echo "$as_me:$LINENO: result: $curl_cv_socklen_t_equiv" >&5
+echo "${ECHO_T}$curl_cv_socklen_t_equiv" >&6; }
+  
+cat >>confdefs.h <<_ACEOF
+@%:@define socklen_t $curl_cv_socklen_t_equiv
+_ACEOF
+
+fi
+
+
+
+
+
+
+for ac_func in kqueue setrlimit getrusage times
+do
+as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
+{ echo "$as_me:$LINENO: checking for $ac_func" >&5
+echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6; }
+if { as_var=$as_ac_var; eval "test \"\${$as_var+set}\" = set"; }; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+/* Define $ac_func to an innocuous variant, in case <limits.h> declares $ac_func.
+   For example, HP-UX 11i <limits.h> declares gettimeofday.  */
+#define $ac_func innocuous_$ac_func
+
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char $ac_func (); below.
+    Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+    <limits.h> exists even on freestanding compilers.  */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef $ac_func
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char $ac_func ();
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined __stub_$ac_func || defined __stub___$ac_func
+choke me
+#endif
+
+int
+main ()
+{
+return $ac_func ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext &&
+       $as_test_x conftest$ac_exeext; then
+  eval "$as_ac_var=yes"
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       eval "$as_ac_var=no"
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+fi
+ac_res=`eval echo '${'$as_ac_var'}'`
+              { echo "$as_me:$LINENO: result: $ac_res" >&5
+echo "${ECHO_T}$ac_res" >&6; }
+if test `eval echo '${'$as_ac_var'}'` = yes; then
+  cat >>confdefs.h <<_ACEOF
+@%:@define `echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+fi
+done
+
+
+{ echo "$as_me:$LINENO: checking for donuts" >&5
+echo $ECHO_N "checking for donuts... $ECHO_C" >&6; }
+{ echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6; }
+
+for ac_prog in gawk mawk nawk awk
+do
+  # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
+if test "${ac_cv_prog_AWK+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if test -n "$AWK"; then
+  ac_cv_prog_AWK="$AWK" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_AWK="$ac_prog"
+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+IFS=$as_save_IFS
+
+fi
+fi
+AWK=$ac_cv_prog_AWK
+if test -n "$AWK"; then
+  { echo "$as_me:$LINENO: result: $AWK" >&5
+echo "${ECHO_T}$AWK" >&6; }
+else
+  { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+fi
+
+
+  test -n "$AWK" && break
+done
+
+{ echo "$as_me:$LINENO: checking whether ${MAKE-make} sets \$(MAKE)" >&5
+echo $ECHO_N "checking whether ${MAKE-make} sets \$(MAKE)... $ECHO_C" >&6; }
+set x ${MAKE-make}; ac_make=`echo "$2" | sed 's/+/p/g; s/[^a-zA-Z0-9_]/_/g'`
+if { as_var=ac_cv_prog_make_${ac_make}_set; eval "test \"\${$as_var+set}\" = set"; }; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.make <<\_ACEOF
+SHELL = /bin/sh
+all:
+       @echo '@@@%%%=$(MAKE)=@@@%%%'
+_ACEOF
+# GNU make sometimes prints "make[1]: Entering...", which would confuse us.
+case `${MAKE-make} -f conftest.make 2>/dev/null` in
+  *@@@%%%=?*=@@@%%%*)
+    eval ac_cv_prog_make_${ac_make}_set=yes;;
+  *)
+    eval ac_cv_prog_make_${ac_make}_set=no;;
+esac
+rm -f conftest.make
+fi
+if eval test \$ac_cv_prog_make_${ac_make}_set = yes; then
+  { echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6; }
+  SET_MAKE=
+else
+  { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+  SET_MAKE="MAKE=${MAKE-make}"
+fi
+
+# Find a good install program.  We prefer a C program (faster),
+# so one script is as good as another.  But avoid the broken or
+# incompatible versions:
+# SysV /etc/install, /usr/sbin/install
+# SunOS /usr/etc/install
+# IRIX /sbin/install
+# AIX /bin/install
+# AmigaOS /C/install, which installs bootblocks on floppy discs
+# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag
+# AFS /usr/afsws/bin/install, which mishandles nonexistent args
+# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff"
+# OS/2's system install, which has a completely different semantic
+# ./install, which can be erroneously created by make from ./install.sh.
+{ echo "$as_me:$LINENO: checking for a BSD-compatible install" >&5
+echo $ECHO_N "checking for a BSD-compatible install... $ECHO_C" >&6; }
+if test -z "$INSTALL"; then
+if test "${ac_cv_path_install+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  # Account for people who put trailing slashes in PATH elements.
+case $as_dir/ in
+  ./ | .// | /cC/* | \
+  /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \
+  ?:\\/os2\\/install\\/* | ?:\\/OS2\\/INSTALL\\/* | \
+  /usr/ucb/* ) ;;
+  *)
+    # OSF1 and SCO ODT 3.0 have their own names for install.
+    # Don't use installbsd from OSF since it installs stuff as root
+    # by default.
+    for ac_prog in ginstall scoinst install; do
+      for ac_exec_ext in '' $ac_executable_extensions; do
+       if { test -f "$as_dir/$ac_prog$ac_exec_ext" && $as_test_x "$as_dir/$ac_prog$ac_exec_ext"; }; then
+         if test $ac_prog = install &&
+           grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then
+           # AIX install.  It has an incompatible calling convention.
+           :
+         elif test $ac_prog = install &&
+           grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then
+           # program-specific install script used by HP pwplus--don't use.
+           :
+         else
+           ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c"
+           break 3
+         fi
+       fi
+      done
+    done
+    ;;
+esac
+done
+IFS=$as_save_IFS
+
+
+fi
+  if test "${ac_cv_path_install+set}" = set; then
+    INSTALL=$ac_cv_path_install
+  else
+    # As a last resort, use the slow shell script.  Don't cache a
+    # value for INSTALL within a source directory, because that will
+    # break other packages using the cache if that directory is
+    # removed, or if the value is a relative name.
+    INSTALL=$ac_install_sh
+  fi
+fi
+{ echo "$as_me:$LINENO: result: $INSTALL" >&5
+echo "${ECHO_T}$INSTALL" >&6; }
+
+# Use test -z because SunOS4 sh mishandles braces in ${var-val}.
+# It thinks the first close brace ends the variable substitution.
+test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}'
+
+test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}'
+
+test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644'
+
+{ echo "$as_me:$LINENO: checking whether ln -s works" >&5
+echo $ECHO_N "checking whether ln -s works... $ECHO_C" >&6; }
+LN_S=$as_ln_s
+if test "$LN_S" = "ln -s"; then
+  { echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6; }
+else
+  { echo "$as_me:$LINENO: result: no, using $LN_S" >&5
+echo "${ECHO_T}no, using $LN_S" >&6; }
+fi
+
+for ac_prog in rm
+do
+  # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
+if test "${ac_cv_path_RMPROG+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  case $RMPROG in
+  [\\/]* | ?:[\\/]*)
+  ac_cv_path_RMPROG="$RMPROG" # Let the user override the test with a path.
+  ;;
+  *)
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_path_RMPROG="$as_dir/$ac_word$ac_exec_ext"
+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+IFS=$as_save_IFS
+
+  ;;
+esac
+fi
+RMPROG=$ac_cv_path_RMPROG
+if test -n "$RMPROG"; then
+  { echo "$as_me:$LINENO: result: $RMPROG" >&5
+echo "${ECHO_T}$RMPROG" >&6; }
+else
+  { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+fi
+
+
+  test -n "$RMPROG" && break
+done
+test -n "$RMPROG" || RMPROG="/bin/rm"
+
+for ac_prog in sh
+do
+  # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
+if test "${ac_cv_path_SHPROG+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  case $SHPROG in
+  [\\/]* | ?:[\\/]*)
+  ac_cv_path_SHPROG="$SHPROG" # Let the user override the test with a path.
+  ;;
+  *)
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_path_SHPROG="$as_dir/$ac_word$ac_exec_ext"
+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+IFS=$as_save_IFS
+
+  ;;
+esac
+fi
+SHPROG=$ac_cv_path_SHPROG
+if test -n "$SHPROG"; then
+  { echo "$as_me:$LINENO: result: $SHPROG" >&5
+echo "${ECHO_T}$SHPROG" >&6; }
+else
+  { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+fi
+
+
+  test -n "$SHPROG" && break
+done
+test -n "$SHPROG" || SHPROG="/bin/sh"
+
+
+for ac_prog in flex lex
+do
+  # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
+if test "${ac_cv_prog_LEX+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if test -n "$LEX"; then
+  ac_cv_prog_LEX="$LEX" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_LEX="$ac_prog"
+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+IFS=$as_save_IFS
+
+fi
+fi
+LEX=$ac_cv_prog_LEX
+if test -n "$LEX"; then
+  { echo "$as_me:$LINENO: result: $LEX" >&5
+echo "${ECHO_T}$LEX" >&6; }
+else
+  { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+fi
+
+
+  test -n "$LEX" && break
+done
+test -n "$LEX" || LEX=":"
+
+if test "x$LEX" != "x:"; then
+  cat >conftest.l <<_ACEOF
+%%
+a { ECHO; }
+b { REJECT; }
+c { yymore (); }
+d { yyless (1); }
+e { yyless (input () != 0); }
+f { unput (yytext[0]); }
+. { BEGIN INITIAL; }
+%%
+#ifdef YYTEXT_POINTER
+extern char *yytext;
+#endif
+int
+main (void)
+{
+  return ! yylex () + ! yywrap ();
+}
+_ACEOF
+{ (ac_try="$LEX conftest.l"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$LEX conftest.l") 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }
+{ echo "$as_me:$LINENO: checking lex output file root" >&5
+echo $ECHO_N "checking lex output file root... $ECHO_C" >&6; }
+if test "${ac_cv_prog_lex_root+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  
+if test -f lex.yy.c; then
+  ac_cv_prog_lex_root=lex.yy
+elif test -f lexyy.c; then
+  ac_cv_prog_lex_root=lexyy
+else
+  { { echo "$as_me:$LINENO: error: cannot find output from $LEX; giving up" >&5
+echo "$as_me: error: cannot find output from $LEX; giving up" >&2;}
+   { (exit 1); exit 1; }; }
+fi
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_prog_lex_root" >&5
+echo "${ECHO_T}$ac_cv_prog_lex_root" >&6; }
+LEX_OUTPUT_ROOT=$ac_cv_prog_lex_root
+
+if test -z "${LEXLIB+set}"; then
+  { echo "$as_me:$LINENO: checking lex library" >&5
+echo $ECHO_N "checking lex library... $ECHO_C" >&6; }
+if test "${ac_cv_lib_lex+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  
+    ac_save_LIBS=$LIBS
+    ac_cv_lib_lex='none needed'
+    for ac_lib in '' -lfl -ll; do
+      LIBS="$ac_lib $ac_save_LIBS"
+      cat >conftest.$ac_ext <<_ACEOF
+`cat $LEX_OUTPUT_ROOT.c`
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext &&
+       $as_test_x conftest$ac_exeext; then
+  ac_cv_lib_lex=$ac_lib
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+      test "$ac_cv_lib_lex" != 'none needed' && break
+    done
+    LIBS=$ac_save_LIBS
+  
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_lib_lex" >&5
+echo "${ECHO_T}$ac_cv_lib_lex" >&6; }
+  test "$ac_cv_lib_lex" != 'none needed' && LEXLIB=$ac_cv_lib_lex
+fi
+
+
+{ echo "$as_me:$LINENO: checking whether yytext is a pointer" >&5
+echo $ECHO_N "checking whether yytext is a pointer... $ECHO_C" >&6; }
+if test "${ac_cv_prog_lex_yytext_pointer+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  # POSIX says lex can declare yytext either as a pointer or an array; the
+# default is implementation-dependent.  Figure out which it is, since
+# not all implementations provide the %pointer and %array declarations.
+ac_cv_prog_lex_yytext_pointer=no
+ac_save_LIBS=$LIBS
+LIBS="$LEXLIB $ac_save_LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+#define YYTEXT_POINTER 1
+`cat $LEX_OUTPUT_ROOT.c`
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext &&
+       $as_test_x conftest$ac_exeext; then
+  ac_cv_prog_lex_yytext_pointer=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_save_LIBS
+
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_prog_lex_yytext_pointer" >&5
+echo "${ECHO_T}$ac_cv_prog_lex_yytext_pointer" >&6; }
+if test $ac_cv_prog_lex_yytext_pointer = yes; then
+  
+cat >>confdefs.h <<\_ACEOF
+@%:@define YYTEXT_POINTER 1
+_ACEOF
+
+fi
+rm -f conftest.l $LEX_OUTPUT_ROOT.c
+
+fi
+if test "$LEX" = ":" ; then
+  { { echo "$as_me:$LINENO: error: Cannot find flex." >&5
+echo "$as_me: error: Cannot find flex." >&2;}
+   { (exit 1); exit 1; }; }
+elif echo "" | $LEX -V -v --version > /dev/null 2>&1 ; then
+  :
+else
+  { { echo "$as_me:$LINENO: error: Cannot use $LEX as flex." >&5
+echo "$as_me: error: Cannot use $LEX as flex." >&2;}
+   { (exit 1); exit 1; }; }
+fi
+
+for ac_prog in 'bison -y' byacc
+do
+  # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
+if test "${ac_cv_prog_YACC+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if test -n "$YACC"; then
+  ac_cv_prog_YACC="$YACC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_YACC="$ac_prog"
+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+IFS=$as_save_IFS
+
+fi
+fi
+YACC=$ac_cv_prog_YACC
+if test -n "$YACC"; then
+  { echo "$as_me:$LINENO: result: $YACC" >&5
+echo "${ECHO_T}$YACC" >&6; }
+else
+  { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+fi
+
+
+  test -n "$YACC" && break
+done
+test -n "$YACC" || YACC="yacc"
+
+if test "$YACC" = ":" ; then
+  { { echo "$as_me:$LINENO: error: Cannot find yacc." >&5
+echo "$as_me: error: Cannot find yacc." >&2;}
+   { (exit 1); exit 1; }; }
+elif echo "" | $YACC -V -v --version > /dev/null 2>&1 ; then
+  :
+else
+  { echo "$as_me:$LINENO: WARNING: $YACC may not work as yacc." >&5
+echo "$as_me: WARNING: $YACC may not work as yacc." >&2;}
+fi
+
+{ echo "$as_me:$LINENO: checking for posix non-blocking" >&5
+echo $ECHO_N "checking for posix non-blocking... $ECHO_C" >&6; }
+if test "${unet_cv_sys_nonblocking_posix+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if test "$cross_compiling" = yes; then
+  { { echo "$as_me:$LINENO: error: cannot run test program while cross compiling
+See \`config.log' for more details." >&5
+echo "$as_me: error: cannot run test program while cross compiling
+See \`config.log' for more details." >&2;}
+   { (exit 1); exit 1; }; }
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <sys/file.h>
+#include <signal.h>
+$ac_cv_type_signal alarmed() { exit(1); }
+int main(void)
+{
+  char b[12];
+  struct sockaddr x;
+  size_t l = sizeof(x);
+  int f = socket(AF_INET, SOCK_DGRAM, 0);
+  if (f >= 0 && !(fcntl(f, F_SETFL, O_NONBLOCK)))
+  {
+    signal(SIGALRM, alarmed);
+    alarm(2);
+    recvfrom(f, b, 12, 0, &x, &l);
+    alarm(0);
+    exit(0);
+  }
+  exit(1);
+}
+_ACEOF
+rm -f conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
+  { (case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_try") 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  unet_cv_sys_nonblocking_posix=yes
+else
+  echo "$as_me: program exited with status $ac_status" >&5
+echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+( exit $ac_status )
+unet_cv_sys_nonblocking_posix=no
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+fi
+
+
+fi
+{ echo "$as_me:$LINENO: result: $unet_cv_sys_nonblocking_posix" >&5
+echo "${ECHO_T}$unet_cv_sys_nonblocking_posix" >&6; }
+if test $unet_cv_sys_nonblocking_posix = yes; then
+  
+cat >>confdefs.h <<\_ACEOF
+@%:@define NBLOCK_POSIX 
+_ACEOF
+
+else
+{ echo "$as_me:$LINENO: checking for bsd non-blocking" >&5
+echo $ECHO_N "checking for bsd non-blocking... $ECHO_C" >&6; }
+if test "${unet_cv_sys_nonblocking_bsd+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if test "$cross_compiling" = yes; then
+  { { echo "$as_me:$LINENO: error: cannot run test program while cross compiling
+See \`config.log' for more details." >&5
+echo "$as_me: error: cannot run test program while cross compiling
+See \`config.log' for more details." >&2;}
+   { (exit 1); exit 1; }; }
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <sys/file.h>
+#include <signal.h>
+$ac_cv_type_signal alarmed() { exit(1); }
+int main(void)
+{
+  char b[12];
+  struct sockaddr x;
+  size_t l = sizeof(x);
+  int f = socket(AF_INET, SOCK_DGRAM, 0);
+  if (f >= 0 && !(fcntl(f, F_SETFL, O_NDELAY)))
+  {
+    signal(SIGALRM, alarmed);
+    alarm(2);
+    recvfrom(f, b, 12, 0, &x, &l);
+    alarm(0);
+    exit(0);
+  }
+  exit(1);
+}
+_ACEOF
+rm -f conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
+  { (case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_try") 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  unet_cv_sys_nonblocking_bsd=yes
+else
+  echo "$as_me: program exited with status $ac_status" >&5
+echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+( exit $ac_status )
+unet_cv_sys_nonblocking_bsd=no
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+fi
+
+
+fi
+{ echo "$as_me:$LINENO: result: $unet_cv_sys_nonblocking_bsd" >&5
+echo "${ECHO_T}$unet_cv_sys_nonblocking_bsd" >&6; }
+if test $unet_cv_sys_nonblocking_bsd = yes; then
+  
+cat >>confdefs.h <<\_ACEOF
+@%:@define NBLOCK_BSD 
+_ACEOF
+
+else
+  
+cat >>confdefs.h <<\_ACEOF
+@%:@define NBLOCK_SYSV 
+_ACEOF
+
+fi
+fi
+{ echo "$as_me:$LINENO: checking for posix signals" >&5
+echo $ECHO_N "checking for posix signals... $ECHO_C" >&6; }
+if test "${unet_cv_sys_signal_posix+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <signal.h>
+int
+main ()
+{
+sigaction(SIGTERM, (struct sigaction *)0L, (struct sigaction *)0L)
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  unet_cv_sys_signal_posix=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       unet_cv_sys_signal_posix=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ echo "$as_me:$LINENO: result: $unet_cv_sys_signal_posix" >&5
+echo "${ECHO_T}$unet_cv_sys_signal_posix" >&6; }
+if test $unet_cv_sys_signal_posix = yes; then
+  
+cat >>confdefs.h <<\_ACEOF
+@%:@define POSIX_SIGNALS 
+_ACEOF
+
+else
+{ echo "$as_me:$LINENO: checking for bsd reliable signals" >&5
+echo $ECHO_N "checking for bsd reliable signals... $ECHO_C" >&6; }
+if test "${unet_cv_sys_signal_bsd+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if test "$cross_compiling" = yes; then
+  { { echo "$as_me:$LINENO: error: cannot run test program while cross compiling
+See \`config.log' for more details." >&5
+echo "$as_me: error: cannot run test program while cross compiling
+See \`config.log' for more details." >&2;}
+   { (exit 1); exit 1; }; }
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <signal.h>
+int calls = 0;
+$ac_cv_type_signal handler()
+{
+  if (calls) return;
+  calls++;
+  kill(getpid(), SIGTERM);
+  sleep(1);
+}
+int main(void)
+{
+  signal(SIGTERM, handler);
+  kill(getpid(), SIGTERM);
+  exit (0);
+}
+_ACEOF
+rm -f conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
+  { (case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_try") 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  unet_cv_sys_signal_bsd=yes
+else
+  echo "$as_me: program exited with status $ac_status" >&5
+echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+( exit $ac_status )
+unet_cv_sys_signal_bsd=no
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+fi
+
+
+fi
+{ echo "$as_me:$LINENO: result: $unet_cv_sys_signal_bsd" >&5
+echo "${ECHO_T}$unet_cv_sys_signal_bsd" >&6; }
+if test $unet_cv_sys_signal_bsd = yes; then
+  
+cat >>confdefs.h <<\_ACEOF
+@%:@define BSD_RELIABLE_SIGNALS 
+_ACEOF
+
+else
+  
+cat >>confdefs.h <<\_ACEOF
+@%:@define SYSV_UNRELIABLE_SIGNALS 
+_ACEOF
+
+fi
+fi
+
+{ echo "$as_me:$LINENO: checking for OS-dependent information" >&5
+echo $ECHO_N "checking for OS-dependent information... $ECHO_C" >&6; }
+case "$host" in
+    *-linux*)
+       { echo "$as_me:$LINENO: result: Linux ($host) found." >&5
+echo "${ECHO_T}Linux ($host) found." >&6; }
+       unet_poll_syscall=yes
+       ;;
+
+    *-solaris*)
+       { echo "$as_me:$LINENO: result: Solaris ($host) found." >&5
+echo "${ECHO_T}Solaris ($host) found." >&6; }
+       if test x"$ac_cv_header_poll_h" = xyes; then
+           unet_poll_syscall=yes
+       else
+           unet_poll_syscall=no
+       fi
+        
+cat >>confdefs.h <<\_ACEOF
+@%:@define IRCU_SOLARIS 1
+_ACEOF
+
+       ;;
+
+    *-sunos*)
+       { echo "$as_me:$LINENO: result: Solaris ($host) found." >&5
+echo "${ECHO_T}Solaris ($host) found." >&6; }
+       unet_poll_syscall=no
+       ;;
+
+    *-openbsd*)
+       { echo "$as_me:$LINENO: result: OpenBSD ($host) found." >&5
+echo "${ECHO_T}OpenBSD ($host) found." >&6; }
+       if test x"$ac_cv_header_poll_h" = xyes; then
+           unet_poll_syscall=yes
+       else
+           unet_poll_syscall=no
+       fi
+       ;;
+
+    *-*bsd*)
+       { echo "$as_me:$LINENO: result: Generic BSD ($host) found." >&5
+echo "${ECHO_T}Generic BSD ($host) found." >&6; }
+       if test x"$ac_cv_header_poll_h" = xyes; then
+           unet_poll_syscall=yes
+       else
+           unet_poll_syscall=no
+       fi
+       ;;
+
+    *-darwin*)
+       { echo "$as_me:$LINENO: result: Darwin (Mac OS X) ($host) found." >&5
+echo "${ECHO_T}Darwin (Mac OS X) ($host) found." >&6; }
+       unet_poll_syscall=no
+       
+cat >>confdefs.h <<\_ACEOF
+@%:@define _DARWIN_C_SOURCE 1
+_ACEOF
+
+       ;;
+
+    *)
+       { echo "$as_me:$LINENO: result: Unknown system type $host found." >&5
+echo "${ECHO_T}Unknown system type $host found." >&6; }
+       { echo "$as_me:$LINENO: WARNING: Unknown OS type; using generic routines." >&5
+echo "$as_me: WARNING: Unknown OS type; using generic routines." >&2;}
+       unet_poll_syscall=no
+       ;;
+esac
+
+{ echo "$as_me:$LINENO: checking whether to enable use of poll()" >&5
+echo $ECHO_N "checking whether to enable use of poll()... $ECHO_C" >&6; }
+# Check whether --enable-poll was given.
+if test "${enable_poll+set}" = set; then
+  enableval=$enable_poll; unet_cv_enable_poll=$enable_poll
+else
+  if test "${unet_cv_enable_poll+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  unet_cv_enable_poll=$unet_poll_syscall
+fi
+
+fi
+
+
+# Force poll to be disabled if there is no poll.h
+if test x"$ac_cv_header_poll_h" != xyes; then
+    unet_cv_enable_poll=no
+fi
+
+{ echo "$as_me:$LINENO: result: $unet_cv_enable_poll" >&5
+echo "${ECHO_T}$unet_cv_enable_poll" >&6; }
+
+if test x"$unet_cv_enable_poll" = xyes; then
+    
+cat >>confdefs.h <<\_ACEOF
+@%:@define USE_POLL 1
+_ACEOF
+
+    ENGINE_C=engine_poll.c
+else
+    ENGINE_C=engine_select.c
+fi
+
+
+{ echo "$as_me:$LINENO: checking whether to enable debug mode" >&5
+echo $ECHO_N "checking whether to enable debug mode... $ECHO_C" >&6; }
+# Check whether --enable-debug was given.
+if test "${enable_debug+set}" = set; then
+  enableval=$enable_debug; unet_cv_enable_debug=$enable_debug
+else
+  if test "${unet_cv_enable_debug+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  unet_cv_enable_debug=no
+fi
+
+fi
+
+{ echo "$as_me:$LINENO: result: $unet_cv_enable_debug" >&5
+echo "${ECHO_T}$unet_cv_enable_debug" >&6; }
+
+if test x"$unet_cv_enable_debug" = xyes; then
+    
+cat >>confdefs.h <<\_ACEOF
+@%:@define DEBUGMODE 1
+_ACEOF
+
+    CFLAGS="$CFLAGS -O0 -g"
+fi
+
+{ echo "$as_me:$LINENO: checking whether to enable leak detection" >&5
+echo $ECHO_N "checking whether to enable leak detection... $ECHO_C" >&6; }
+
+# Check whether --with-leak-detect was given.
+if test "${with_leak_detect+set}" = set; then
+  withval=$with_leak_detect; unet_cv_with_leak_detect=$with_leak_detect
+else
+  if test "${unet_cv_with_leak_detect+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  unet_cv_with_leak_detect=no
+fi
+
+fi
+
+{ echo "$as_me:$LINENO: result: $unet_cv_enable_leak_detect" >&5
+echo "${ECHO_T}$unet_cv_enable_leak_detect" >&6; }
+
+if test x"$unet_cv_with_leak_detect" != xno; then
+    LIBS="-lgc $LIBS"
+    CFLAGS="-DMDEBUG $CFLAGS"
+    if test x"$unet_cv_with_leak_detect" != xyes; then
+       LIBS="-L$unet_cv_with_leak_detect $LIBS"
+    fi
+fi
+
+
+# Check whether --with-ipv6 was given.
+if test "${with_ipv6+set}" = set; then
+  withval=$with_ipv6; ac_cv_use_ipv6=$withval
+else
+  ac_cv_use_ipv6=$unet_have_sockaddr_in6
+fi
+
+{ echo "$as_me:$LINENO: checking whether to use IPv6" >&5
+echo $ECHO_N "checking whether to use IPv6... $ECHO_C" >&6; }
+if test "${ac_cv_use_ipv6+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_cv_use_ipv6=no
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_use_ipv6" >&5
+echo "${ECHO_T}$ac_cv_use_ipv6" >&6; }
+if test x"$ac_cv_use_ipv6" != "xno" ; then
+    
+cat >>confdefs.h <<\_ACEOF
+@%:@define IPV6 1
+_ACEOF
+
+fi
+
+{ echo "$as_me:$LINENO: checking whether to enable asserts" >&5
+echo $ECHO_N "checking whether to enable asserts... $ECHO_C" >&6; }
+# Check whether --enable-asserts was given.
+if test "${enable_asserts+set}" = set; then
+  enableval=$enable_asserts; unet_cv_enable_asserts=$enable_asserts
+else
+  if test "${unet_cv_enable_asserts+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  unet_cv_enable_asserts=yes
+fi
+
+fi
+
+{ echo "$as_me:$LINENO: result: $unet_cv_enable_asserts" >&5
+echo "${ECHO_T}$unet_cv_enable_asserts" >&6; }
+
+if test x"$unet_cv_enable_asserts" = xno; then
+    
+cat >>confdefs.h <<\_ACEOF
+@%:@define NDEBUG 1
+_ACEOF
+
+fi
+
+{ echo "$as_me:$LINENO: checking whether to enable profiling support (gprof)" >&5
+echo $ECHO_N "checking whether to enable profiling support (gprof)... $ECHO_C" >&6; }
+# Check whether --enable-profile was given.
+if test "${enable_profile+set}" = set; then
+  enableval=$enable_profile; unet_cv_enable_profile=$enable_profile
+else
+  if test "${unet_cv_enable_profile+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  unet_cv_enable_profile=no
+fi
+
+fi
+
+{ echo "$as_me:$LINENO: result: $unet_cv_enable_profile" >&5
+echo "${ECHO_T}$unet_cv_enable_profile" >&6; }
+
+if test x"$unet_cv_enable_profile" = xyes; then
+    CFLAGS="-pg $CFLAGS"
+    LDFLAGS="-pg $LDFLAGS"
+fi
+
+{ echo "$as_me:$LINENO: checking whether to enable pedantic compiler warnings" >&5
+echo $ECHO_N "checking whether to enable pedantic compiler warnings... $ECHO_C" >&6; }
+# Check whether --enable-pedantic was given.
+if test "${enable_pedantic+set}" = set; then
+  enableval=$enable_pedantic; unet_cv_enable_pedantic=$enable_pedantic
+else
+  if test "${unet_cv_enable_pedantic+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  unet_cv_enable_pedantic=no
+fi
+
+fi
+
+{ echo "$as_me:$LINENO: result: $unet_cv_enable_pedantic" >&5
+echo "${ECHO_T}$unet_cv_enable_pedantic" >&6; }
+
+if test x"$unet_cv_enable_pedantic" = xyes; then
+    CFLAGS="-pedantic $CFLAGS"
+fi
+
+{ echo "$as_me:$LINENO: checking whether to enable compiler warnings" >&5
+echo $ECHO_N "checking whether to enable compiler warnings... $ECHO_C" >&6; }
+# Check whether --enable-warnings was given.
+if test "${enable_warnings+set}" = set; then
+  enableval=$enable_warnings; unet_cv_enable_warnings=$enable_warnings
+else
+  if test "${unet_cv_enable_warnings+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  unet_cv_enable_warnings=no
+fi
+
+fi
+
+{ echo "$as_me:$LINENO: result: $unet_cv_enable_warnings" >&5
+echo "${ECHO_T}$unet_cv_enable_warnings" >&6; }
+
+if test x"$unet_cv_enable_warnings" = xyes; then
+    CFLAGS="-Wall $CFLAGS"
+fi
+
+{ echo "$as_me:$LINENO: checking whether to enable inlining for a few critical functions" >&5
+echo $ECHO_N "checking whether to enable inlining for a few critical functions... $ECHO_C" >&6; }
+# Check whether --enable-inlines was given.
+if test "${enable_inlines+set}" = set; then
+  enableval=$enable_inlines; unet_cv_enable_inlines=$enable_inlines
+else
+  if test "${unet_cv_enable_inlines+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  unet_cv_enable_inlines=yes
+fi
+
+fi
+
+{ echo "$as_me:$LINENO: result: $unet_cv_enable_inlines" >&5
+echo "${ECHO_T}$unet_cv_enable_inlines" >&6; }
+
+if test x"$unet_cv_enable_inlines" = xyes; then
+    
+cat >>confdefs.h <<\_ACEOF
+@%:@define FORCEINLINE 1
+_ACEOF
+
+fi
+
+{ echo "$as_me:$LINENO: checking whether to enable the /dev/poll event engine" >&5
+echo $ECHO_N "checking whether to enable the /dev/poll event engine... $ECHO_C" >&6; }
+# Check whether --enable-devpoll was given.
+if test "${enable_devpoll+set}" = set; then
+  enableval=$enable_devpoll; unet_cv_enable_devpoll=$enable_devpoll
+else
+  if test "${unet_cv_enable_devpoll+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  unet_cv_enable_devpoll=yes
+fi
+
+fi
+
+
+if test x"$ac_cv_header_sys_devpoll_h" = xno; then
+    unet_cv_enable_devpoll=no
+fi
+
+{ echo "$as_me:$LINENO: result: $unet_cv_enable_devpoll" >&5
+echo "${ECHO_T}$unet_cv_enable_devpoll" >&6; }
+
+if test x"$unet_cv_enable_devpoll" != xno; then
+    
+cat >>confdefs.h <<\_ACEOF
+@%:@define USE_DEVPOLL 1
+_ACEOF
+
+    ENGINE_C="engine_devpoll.c $ENGINE_C"
+fi
+
+{ echo "$as_me:$LINENO: checking whether to enable the kqueue event engine" >&5
+echo $ECHO_N "checking whether to enable the kqueue event engine... $ECHO_C" >&6; }
+# Check whether --enable-kqueue was given.
+if test "${enable_kqueue+set}" = set; then
+  enableval=$enable_kqueue; unet_cv_enable_kqueue=$enable_kqueue
+else
+  if test "${unet_cv_enable_kqueue+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  unet_cv_enable_kqueue=yes
+fi
+
+fi
+
+
+if test x"$ac_cv_header_sys_event_h" = xno -o x"$ac_cv_func_kqueue" = xno; then
+    unet_cv_enable_kqueue=no
+fi
+
+{ echo "$as_me:$LINENO: result: $unet_cv_enable_kqueue" >&5
+echo "${ECHO_T}$unet_cv_enable_kqueue" >&6; }
+
+if test x"$unet_cv_enable_kqueue" != xno; then
+    
+cat >>confdefs.h <<\_ACEOF
+@%:@define USE_KQUEUE 1
+_ACEOF
+
+    ENGINE_C="engine_kqueue.c $ENGINE_C"
+fi
+
+{ echo "$as_me:$LINENO: checking whether to enable the epoll event engine" >&5
+echo $ECHO_N "checking whether to enable the epoll event engine... $ECHO_C" >&6; }
+# Check whether --enable-epoll was given.
+if test "${enable_epoll+set}" = set; then
+  enableval=$enable_epoll; unet_cv_enable_epoll=$enable_epoll
+else
+  if test "${unet_cv_enable_epoll+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  unet_cv_enable_epoll=yes
+fi
+
+fi
+
+
+if test x"$ac_cv_header_sys_epoll_h" = xno -o x"$ac_cv_func_epoll" = xno; then
+    unet_cv_enable_epoll=no
+fi
+
+{ echo "$as_me:$LINENO: result: $unet_cv_enable_epoll" >&5
+echo "${ECHO_T}$unet_cv_enable_epoll" >&6; }
+
+if test x"$unet_cv_enable_epoll" != xno; then
+    { echo "$as_me:$LINENO: checking whether epoll functions are properly defined" >&5
+echo $ECHO_N "checking whether epoll functions are properly defined... $ECHO_C" >&6; }
+    cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <sys/epoll.h>
+int
+main ()
+{
+epoll_create(10);
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext &&
+       $as_test_x conftest$ac_exeext; then
+  { echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6; }
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+         
+cat >>confdefs.h <<\_ACEOF
+@%:@define EPOLL_NEED_BODY 1
+_ACEOF
+
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+    
+cat >>confdefs.h <<\_ACEOF
+@%:@define USE_EPOLL 1
+_ACEOF
+
+    ENGINE_C="engine_epoll.c $ENGINE_C"
+fi
+
+{ echo "$as_me:$LINENO: checking for va_copy" >&5
+echo $ECHO_N "checking for va_copy... $ECHO_C" >&6; }
+if test "${unet_cv_c_va_copy+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <stdarg.h>
+int
+main ()
+{
+va_list ap1, ap2; va_copy(ap1, ap2);
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext &&
+       $as_test_x conftest$ac_exeext; then
+  unet_cv_c_va_copy="yes"
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       unet_cv_c_va_copy="no"
+
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+fi
+{ echo "$as_me:$LINENO: result: $unet_cv_c_va_copy" >&5
+echo "${ECHO_T}$unet_cv_c_va_copy" >&6; }
+if test "$unet_cv_c_va_copy" = "yes" ; then
+  
+cat >>confdefs.h <<\_ACEOF
+@%:@define HAVE_VA_COPY 1
+_ACEOF
+
+fi
+
+{ echo "$as_me:$LINENO: checking for __va_copy" >&5
+echo $ECHO_N "checking for __va_copy... $ECHO_C" >&6; }
+if test "${unet_cv_c___va_copy+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <stdarg.h>
+int
+main ()
+{
+va_list ap1, ap2; __va_copy(ap1, ap2);
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext &&
+       $as_test_x conftest$ac_exeext; then
+  unet_cv_c___va_copy="yes"
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       unet_cv_c___va_copy="no"
+
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+fi
+{ echo "$as_me:$LINENO: result: $unet_cv_c___va_copy" >&5
+echo "${ECHO_T}$unet_cv_c___va_copy" >&6; }
+if test "$unet_cv_c___va_copy" = "yes" ; then
+  
+cat >>confdefs.h <<\_ACEOF
+@%:@define HAVE___VA_COPY 1
+_ACEOF
+
+fi
+
+{ echo "$as_me:$LINENO: checking what name to give the symlink" >&5
+echo $ECHO_N "checking what name to give the symlink... $ECHO_C" >&6; }
+
+# Check whether --with-symlink was given.
+if test "${with_symlink+set}" = set; then
+  withval=$with_symlink; unet_cv_with_symlink=$with_symlink
+else
+  if test "${unet_cv_with_symlink+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  unet_cv_with_symlink="ircd"
+fi
+
+fi
+
+
+if test x"$unet_cv_with_symlink" = xyes; then
+    unet_cv_with_symlink="ircd"
+fi
+
+{ echo "$as_me:$LINENO: result: $unet_cv_with_symlink" >&5
+echo "${ECHO_T}$unet_cv_with_symlink" >&6; }
+
+if test x"$unet_cv_with_symlink" = xno; then
+    INSTALL_RULE=install-no-symlink
+    SYMLINK=
+else
+    INSTALL_RULE=install-with-symlink
+    SYMLINK=$unet_cv_with_symlink
+fi
+
+
+
+{ echo "$as_me:$LINENO: checking what permissions to set on the installed binary" >&5
+echo $ECHO_N "checking what permissions to set on the installed binary... $ECHO_C" >&6; }
+
+# Check whether --with-mode was given.
+if test "${with_mode+set}" = set; then
+  withval=$with_mode; unet_cv_with_mode=$with_mode
+else
+  if test "${unet_cv_with_mode+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  unet_cv_with_mode=711
+fi
+
+fi
+
+
+if test x"$unet_cv_with_mode" = xyes -o x"$unet_cv_with_mode" = xno; then
+    unet_cv_with_mode=711
+fi
+
+{ echo "$as_me:$LINENO: result: $unet_cv_with_mode" >&5
+echo "${ECHO_T}$unet_cv_with_mode" >&6; }
+
+IRCDMODE=$unet_cv_with_mode
+
+
+unet_uid=`id | sed -e 's/.*uid=[0-9]*(//' -e 's/).*//' 2> /dev/null`
+{ echo "$as_me:$LINENO: checking which user should own the installed binary" >&5
+echo $ECHO_N "checking which user should own the installed binary... $ECHO_C" >&6; }
+
+# Check whether --with-owner was given.
+if test "${with_owner+set}" = set; then
+  withval=$with_owner; unet_cv_with_owner=$with_owner
+else
+  if test "${unet_cv_with_owner+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  unet_cv_with_owner=$unet_uid
+fi
+
+fi
+
+
+if test x"$unet_cv_with_owner" = xyes -o x"$unet_cv_with_owner" = xno; then
+    unet_cv_with_owner=$unet_uid
+fi
+
+{ echo "$as_me:$LINENO: result: $unet_cv_with_owner" >&5
+echo "${ECHO_T}$unet_cv_with_owner" >&6; }
+
+IRCDOWN=$unet_cv_with_owner
+
+
+unet_gid=`id | sed -e 's/.*gid=[0-9]*(//' -e 's/).*//' 2> /dev/null`
+{ echo "$as_me:$LINENO: checking which group should own the installed binary" >&5
+echo $ECHO_N "checking which group should own the installed binary... $ECHO_C" >&6; }
+
+# Check whether --with-group was given.
+if test "${with_group+set}" = set; then
+  withval=$with_group; unet_cv_with_group=$with_group
+else
+  if test "${unet_cv_with_group+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  unet_cv_with_group=$unet_gid
+fi
+
+fi
+
+
+if test x"$unet_cv_with_group" = xyes -o x"$unet_cv_with_group" = xno; then
+    unet_cv_with_group=$unet_gid
+fi
+
+{ echo "$as_me:$LINENO: result: $unet_cv_with_group" >&5
+echo "${ECHO_T}$unet_cv_with_group" >&6; }
+
+IRCDGRP=$unet_cv_with_group
+
+
+unet_domain=
+if test -f /etc/resolv.conf; then
+    unet_domain=`awk '/^domain/ { print $2; exit }' /etc/resolv.conf`
+    if test x"$unet_domain" = x; then
+       unet_domain=`awk '/^search/ { print $2; exit }' /etc/resolv.conf`
+    fi
+fi
+{ echo "$as_me:$LINENO: checking for site domain name" >&5
+echo $ECHO_N "checking for site domain name... $ECHO_C" >&6; }
+
+# Check whether --with-domain was given.
+if test "${with_domain+set}" = set; then
+  withval=$with_domain; unet_cv_with_domain=$with_domain
+else
+  if test "${unet_cv_with_domain+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  unet_cv_with_domain=$unet_domain
+fi
+
+fi
+
+
+if test x"$unet_cv_with_domain" = xyes -o x"$unet_cv_with_domain" = xno; then
+    unet_cv_with_domain=$unet_domain
+fi
+if test x"$unet_cv_with_domain" = xno; then
+    { { echo "$as_me:$LINENO: error: Unable to determine server DNS domain; use --with-domain to set it" >&5
+echo "$as_me: error: Unable to determine server DNS domain; use --with-domain to set it" >&2;}
+   { (exit 1); exit 1; }; }
+fi
+
+{ echo "$as_me:$LINENO: result: $unet_cv_with_domain" >&5
+echo "${ECHO_T}$unet_cv_with_domain" >&6; }
+
+
+cat >>confdefs.h <<_ACEOF
+@%:@define DOMAINNAME "*$unet_cv_with_domain"
+_ACEOF
+
+
+{ echo "$as_me:$LINENO: checking if chroot operation is desired" >&5
+echo $ECHO_N "checking if chroot operation is desired... $ECHO_C" >&6; }
+
+# Check whether --with-chroot was given.
+if test "${with_chroot+set}" = set; then
+  withval=$with_chroot; unet_cv_with_chroot=$with_chroot
+else
+  if test "${unet_cv_with_chroot+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  unet_cv_with_chroot=no
+fi
+
+fi
+
+
+if test x"$unet_cv_with_chroot" = xyes; then
+    { { echo "$as_me:$LINENO: error: --with-chroot given with no directory.  See doc/readme.chroot." >&5
+echo "$as_me: error: --with-chroot given with no directory.  See doc/readme.chroot." >&2;}
+   { (exit 1); exit 1; }; }
+fi
+
+# Ensure there are no trailing /'s to mess us up
+unet_cv_with_chroot=`echo "$unet_cv_with_chroot" | sed 's%/*$%%'`
+
+{ echo "$as_me:$LINENO: result: $unet_cv_with_chroot" >&5
+echo "${ECHO_T}$unet_cv_with_chroot" >&6; }
+
+# Deal with the annoying value "NONE" here
+unet_save_prefix=$prefix
+if test x"$prefix" = xNONE; then
+    prefix=$ac_default_prefix
+else
+    prefix=$prefix
+fi
+
+unet_save_exec_prefix=$exec_prefix
+if test x"$exec_prefix" = xNONE; then
+    exec_prefix=$prefix
+else
+    exec_prefix=$exec_prefix
+fi
+
+# Obtain the actual interesting directories
+unet_bindir=`eval echo "$bindir"`
+unet_libdir=`eval echo "$libdir"`
+
+# Restore the original settings of $prefix and $exec_prefix
+prefix=$unet_save_prefix
+exec_prefix=$unet_save_exec_prefix
+
+{ echo "$as_me:$LINENO: checking where the binary will be for /restart" >&5
+echo $ECHO_N "checking where the binary will be for /restart... $ECHO_C" >&6; }
+if test x"$unet_cv_with_symlink" = xno; then
+    unet_spath="$unet_bindir/ircd"
+else
+    unet_spath="$unet_bindir/$unet_cv_with_symlink"
+fi
+{ echo "$as_me:$LINENO: result: $unet_spath" >&5
+echo "${ECHO_T}$unet_spath" >&6; }
+
+if test x"$unet_cv_with_chroot" != xno; then
+    if echo "$unet_spath" | grep "^$unet_cv_with_chroot" > /dev/null 2>&1; then
+       unet_spath=`echo "$unet_spath" | sed "s%^$unet_cv_with_chroot%%"`
+    else
+       { echo "$as_me:$LINENO: WARNING: Binary $unet_spath not relative to root directory $unet_cv_with_chroot; restarts will probably fail" >&5
+echo "$as_me: WARNING: Binary $unet_spath not relative to root directory $unet_cv_with_chroot; restarts will probably fail" >&2;}
+    fi
+fi
+
+
+cat >>confdefs.h <<_ACEOF
+@%:@define SPATH "$unet_spath"
+_ACEOF
+
+
+{ echo "$as_me:$LINENO: checking what the data directory should be" >&5
+echo $ECHO_N "checking what the data directory should be... $ECHO_C" >&6; }
+
+# Check whether --with-dpath was given.
+if test "${with_dpath+set}" = set; then
+  withval=$with_dpath; unet_cv_with_dpath=$with_dpath
+else
+  if test "${unet_cv_with_dpath+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  unet_cv_with_dpath=$unet_libdir
+fi
+
+fi
+
+
+if test x"$unet_cv_with_dpath" = xyes -o x"$unet_cv_with_dpath" = xno; then
+    unet_cv_with_dpath=$unet_libdir
+fi
+
+# Ensure there are no trailing /'s to mess us up
+unet_cv_with_dpath=`echo "$unet_cv_with_dpath" | sed 's%/*$%%'`
+
+{ echo "$as_me:$LINENO: result: $unet_cv_with_dpath" >&5
+echo "${ECHO_T}$unet_cv_with_dpath" >&6; }
+
+if test x"$unet_cv_with_chroot" != xno; then
+    if echo "$unet_cv_with_dpath" | grep "^$unet_cv_with_chroot" > /dev/null 2>&1; then
+       unet_dpath=`echo "$unet_cv_with_dpath" | sed "s%^$unet_cv_with_chroot%%"`
+    else
+       { { echo "$as_me:$LINENO: error: Data directory $unet_cv_with_dpath not relative to root directory $unet_cv_with_chroot" >&5
+echo "$as_me: error: Data directory $unet_cv_with_dpath not relative to root directory $unet_cv_with_chroot" >&2;}
+   { (exit 1); exit 1; }; }
+    fi
+else
+    unet_dpath=$unet_cv_with_dpath
+fi
+
+
+cat >>confdefs.h <<_ACEOF
+@%:@define DPATH "$unet_dpath"
+_ACEOF
+
+
+DPATH=$unet_cv_with_dpath
+
+
+{ echo "$as_me:$LINENO: checking where the default configuration file resides" >&5
+echo $ECHO_N "checking where the default configuration file resides... $ECHO_C" >&6; }
+
+# Check whether --with-cpath was given.
+if test "${with_cpath+set}" = set; then
+  withval=$with_cpath; unet_cv_with_cpath=$with_cpath
+else
+  if test "${unet_cv_with_cpath+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  unet_cv_with_cpath="ircd.conf"
+fi
+
+fi
+
+
+if test x"$unet_cv_with_cpath" = xyes -o x"$unet_cv_with_cpath" = xno; then
+    unet_cv_with_cpath="ircd.conf"
+fi
+
+{ echo "$as_me:$LINENO: result: $unet_cv_with_cpath" >&5
+echo "${ECHO_T}$unet_cv_with_cpath" >&6; }
+
+if echo "$unet_cv_with_cpath" | grep '^/' > /dev/null 2>&1; then
+    # Absolute path; check against chroot stuff
+    if test x"$unet_cv_with_chroot" != xno; then
+       if echo "$unet_cv_with_cpath" | grep "^$unet_cv_with_chroot" > /dev/null 2>&1; then
+           unet_cpath=`echo "$unet_cv_with_cpath" | sed "s%^$unet_cv_with_chroot%%"`
+       else
+           { { echo "$as_me:$LINENO: error: Configuration file $unet_cv_with_cpath not relative to root directory $unet_cv_with_chroot" >&5
+echo "$as_me: error: Configuration file $unet_cv_with_cpath not relative to root directory $unet_cv_with_chroot" >&2;}
+   { (exit 1); exit 1; }; }
+       fi
+    else
+       unet_cpath=$unet_cv_with_cpath
+    fi
+else
+    unet_cpath=$unet_cv_with_cpath
+fi
+
+
+cat >>confdefs.h <<_ACEOF
+@%:@define CPATH "$unet_cpath"
+_ACEOF
+
+
+{ echo "$as_me:$LINENO: checking where to put the debugging log if debugging enabled" >&5
+echo $ECHO_N "checking where to put the debugging log if debugging enabled... $ECHO_C" >&6; }
+
+# Check whether --with-lpath was given.
+if test "${with_lpath+set}" = set; then
+  withval=$with_lpath; unet_cv_with_lpath=$with_lpath
+else
+  if test "${unet_cv_with_lpath+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  unet_cv_with_lpath="ircd.log"
+fi
+
+fi
+
+
+if test x"$unet_cv_with_lpath" = xyes -o x"$unet_cv_with_lpath" = xno; then
+    unet_cv_with_lpath="ircd.log"
+fi
+
+{ echo "$as_me:$LINENO: result: $unet_cv_with_lpath" >&5
+echo "${ECHO_T}$unet_cv_with_lpath" >&6; }
+
+if echo "$unet_cv_with_lpath" | grep '^/' > /dev/null 2>&1; then
+    # Absolute path; check against chroot stuff
+    if test x"$unet_cv_with_chroot" != xno; then
+       if echo "$unet_cv_with_lpath" | grep "^$unet_cv_with_chroot" > /dev/null 2>&1; then
+           unet_lpath=`echo "$unet_cv_with_lpath" | sed "s%^$unet_cv_with_chroot%%"`
+       else
+           { echo "$as_me:$LINENO: WARNING: Log file $unet_cv_with_lpath not relative to root directory $unet_cv_with_chroot; using default ircd.log instead" >&5
+echo "$as_me: WARNING: Log file $unet_cv_with_lpath not relative to root directory $unet_cv_with_chroot; using default ircd.log instead" >&2;}
+           unet_cv_with_lpath="ircd.log"
+           unet_lpath="ircd.log"
+       fi
+    else
+       unet_lpath=$unet_cv_with_lpath
+    fi
+else
+    unet_lpath=$unet_cv_with_lpath
+fi
+
+
+cat >>confdefs.h <<_ACEOF
+@%:@define LPATH "$unet_lpath"
+_ACEOF
+
+
+unet_maxcon=`ulimit -Hn`
+if test x"$unet_maxcon" = xunlimited; then
+    unet_maxcon=`ulimit -Sn`
+fi
+unet_maxcon=`expr $unet_maxcon - 4`
+{ echo "$as_me:$LINENO: checking max connections" >&5
+echo $ECHO_N "checking max connections... $ECHO_C" >&6; }
+
+# Check whether --with-maxcon was given.
+if test "${with_maxcon+set}" = set; then
+  withval=$with_maxcon; unet_cv_with_maxcon=$with_maxcon
+else
+  if test "${unet_cv_with_maxcon+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  unet_cv_with_maxcon=$unet_maxcon
+fi
+
+fi
+
+
+if test x"$unet_cv_with_maxcon" = xyes -o x"$unet_cv_with_maxcon" = xno; then
+    if test "$unet_maxcon" -lt 32; then
+      { { echo "$as_me:$LINENO: error: Maximum connections (number of open files minus 4) must be at least 32." >&5
+echo "$as_me: error: Maximum connections (number of open files minus 4) must be at least 32." >&2;}
+   { (exit 1); exit 1; }; }
+    fi
+    unet_cv_with_maxcon=$unet_maxcon
+elif test "$unet_cv_with_maxcon" -lt 32; then
+    { { echo "$as_me:$LINENO: error: Maximum connections (--with-maxcon) must be at least 32." >&5
+echo "$as_me: error: Maximum connections (--with-maxcon) must be at least 32." >&2;}
+   { (exit 1); exit 1; }; }
+fi
+
+{ echo "$as_me:$LINENO: result: $unet_cv_with_maxcon" >&5
+echo "${ECHO_T}$unet_cv_with_maxcon" >&6; }
+
+
+cat >>confdefs.h <<_ACEOF
+@%:@define MAXCONNECTIONS $unet_cv_with_maxcon
+_ACEOF
+
+
+unet_cv_enable_compat="yes"
+{ echo "$as_me:$LINENO: checking whether to enable OGN-compat mode" >&5
+echo $ECHO_N "checking whether to enable OGN-compat mode... $ECHO_C" >&6; }
+# Check whether --enable-compat was given.
+if test "${enable_compat+set}" = set; then
+  enableval=$enable_compat; unet_cv_enable_compat=$enable_compat
+fi
+
+{ echo "$as_me:$LINENO: result: $unet_cv_enable_compat" >&5
+echo "${ECHO_T}$unet_cv_enable_compat" >&6; }
+
+if test $unet_cv_enable_compat = "no" ; then
+    # do nothing
+    unet_cv_enable_compat="no"
+else
+    
+cat >>confdefs.h <<\_ACEOF
+@%:@define OLD_OGN_IRCU_COMPAT 1
+_ACEOF
+
+fi
+
+unet_cv_enable_unstable="no"
+{ echo "$as_me:$LINENO: checking whether to enable unstable features" >&5
+echo $ECHO_N "checking whether to enable unstable features... $ECHO_C" >&6; }
+# Check whether --enable-unstable was given.
+if test "${enable_unstable+set}" = set; then
+  enableval=$enable_unstable; unet_cv_enable_unstable=$enable_unstable
+fi
+
+{ echo "$as_me:$LINENO: result: $unet_cv_enable_unstable" >&5
+echo "${ECHO_T}$unet_cv_enable_unstable" >&6; }
+
+if test $unet_cv_enable_unstable = "yes" ; then
+    
+cat >>confdefs.h <<\_ACEOF
+@%:@define WITH_UNSTABLE_FEAT 1
+_ACEOF
+
+fi
+
+
+unet_cv_enable_gnutls="no"
+unet_cv_enable_openssl="yes"
+
+{ echo "$as_me:$LINENO: checking for GnuTLS" >&5
+echo $ECHO_N "checking for GnuTLS... $ECHO_C" >&6; }
+# Check whether --enable-gnutls was given.
+if test "${enable_gnutls+set}" = set; then
+  enableval=$enable_gnutls; unet_cv_enable_gnutls=$enable_gnutls
+fi
+
+{ echo "$as_me:$LINENO: result: $unet_cv_enable_gnutls" >&5
+echo "${ECHO_T}$unet_cv_enable_gnutls" >&6; }
+
+{ echo "$as_me:$LINENO: checking for OpenSSL" >&5
+echo $ECHO_N "checking for OpenSSL... $ECHO_C" >&6; }
+# Check whether --enable-openssl was given.
+if test "${enable_openssl+set}" = set; then
+  enableval=$enable_openssl; unet_cv_enable_openssl=$enable_openssl
+fi
+
+{ echo "$as_me:$LINENO: result: $unet_cv_enable_openssl" >&5
+echo "${ECHO_T}$unet_cv_enable_openssl" >&6; }
+
+if test x"$unet_cv_enable_gnutls" = xyes; then
+  unet_cv_enable_gnutls="no";
+  { echo "$as_me:$LINENO: checking for gnutls_init in -lgnutls" >&5
+echo $ECHO_N "checking for gnutls_init in -lgnutls... $ECHO_C" >&6; }
+if test "${ac_cv_lib_gnutls_gnutls_init+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lgnutls  $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char gnutls_init ();
+int
+main ()
+{
+return gnutls_init ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext &&
+       $as_test_x conftest$ac_exeext; then
+  ac_cv_lib_gnutls_gnutls_init=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_lib_gnutls_gnutls_init=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_lib_gnutls_gnutls_init" >&5
+echo "${ECHO_T}$ac_cv_lib_gnutls_gnutls_init" >&6; }
+if test $ac_cv_lib_gnutls_gnutls_init = yes; then
+  
+    
+for ac_header in gnutls/gnutls.h
+do
+as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
+if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
+  { echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; }
+if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+fi
+ac_res=`eval echo '${'$as_ac_Header'}'`
+              { echo "$as_me:$LINENO: result: $ac_res" >&5
+echo "${ECHO_T}$ac_res" >&6; }
+else
+  # Is the header compilable?
+{ echo "$as_me:$LINENO: checking $ac_header usability" >&5
+echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6; }
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+@%:@include <$ac_header>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_header_compiler=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_header_compiler=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+{ echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
+echo "${ECHO_T}$ac_header_compiler" >&6; }
+
+# Is the header present?
+{ echo "$as_me:$LINENO: checking $ac_header presence" >&5
+echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6; }
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+@%:@include <$ac_header>
+_ACEOF
+if { (ac_try="$ac_cpp conftest.$ac_ext"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } >/dev/null && {
+        test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       }; then
+  ac_header_preproc=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+  ac_header_preproc=no
+fi
+
+rm -f conftest.err conftest.$ac_ext
+{ echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
+echo "${ECHO_T}$ac_header_preproc" >&6; }
+
+# So?  What about this header?
+case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
+  yes:no: )
+    { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5
+echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;}
+    ac_header_preproc=yes
+    ;;
+  no:yes:* )
+    { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5
+echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header:     check for missing prerequisite headers?" >&5
+echo "$as_me: WARNING: $ac_header:     check for missing prerequisite headers?" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5
+echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&5
+echo "$as_me: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5
+echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;}
+    
+    ;;
+esac
+{ echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; }
+if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  eval "$as_ac_Header=\$ac_header_preproc"
+fi
+ac_res=`eval echo '${'$as_ac_Header'}'`
+              { echo "$as_me:$LINENO: result: $ac_res" >&5
+echo "${ECHO_T}$ac_res" >&6; }
+
+fi
+if test `eval echo '${'$as_ac_Header'}'` = yes; then
+  cat >>confdefs.h <<_ACEOF
+@%:@define `echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+      unet_cv_enable_gnutls="yes";
+    
+fi
+
+done
+
+  
+fi
+
+fi
+
+if test x"$unet_cv_enable_openssl" = xyes; then
+  unet_cv_enable_openssl="no";
+  { echo "$as_me:$LINENO: checking for SSL_read in -lssl" >&5
+echo $ECHO_N "checking for SSL_read in -lssl... $ECHO_C" >&6; }
+if test "${ac_cv_lib_ssl_SSL_read+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lssl  $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char SSL_read ();
+int
+main ()
+{
+return SSL_read ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext &&
+       $as_test_x conftest$ac_exeext; then
+  ac_cv_lib_ssl_SSL_read=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_lib_ssl_SSL_read=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_lib_ssl_SSL_read" >&5
+echo "${ECHO_T}$ac_cv_lib_ssl_SSL_read" >&6; }
+if test $ac_cv_lib_ssl_SSL_read = yes; then
+  
+    { echo "$as_me:$LINENO: checking for X509_new in -lcrypto" >&5
+echo $ECHO_N "checking for X509_new in -lcrypto... $ECHO_C" >&6; }
+if test "${ac_cv_lib_crypto_X509_new+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lcrypto  $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char X509_new ();
+int
+main ()
+{
+return X509_new ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext &&
+       $as_test_x conftest$ac_exeext; then
+  ac_cv_lib_crypto_X509_new=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_lib_crypto_X509_new=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_lib_crypto_X509_new" >&5
+echo "${ECHO_T}$ac_cv_lib_crypto_X509_new" >&6; }
+if test $ac_cv_lib_crypto_X509_new = yes; then
+  
+      
+
+for ac_header in openssl/ssl.h openssl/err.h
+do
+as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
+if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
+  { echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; }
+if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+fi
+ac_res=`eval echo '${'$as_ac_Header'}'`
+              { echo "$as_me:$LINENO: result: $ac_res" >&5
+echo "${ECHO_T}$ac_res" >&6; }
+else
+  # Is the header compilable?
+{ echo "$as_me:$LINENO: checking $ac_header usability" >&5
+echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6; }
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+@%:@include <$ac_header>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_header_compiler=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_header_compiler=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+{ echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
+echo "${ECHO_T}$ac_header_compiler" >&6; }
+
+# Is the header present?
+{ echo "$as_me:$LINENO: checking $ac_header presence" >&5
+echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6; }
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+@%:@include <$ac_header>
+_ACEOF
+if { (ac_try="$ac_cpp conftest.$ac_ext"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } >/dev/null && {
+        test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       }; then
+  ac_header_preproc=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+  ac_header_preproc=no
+fi
+
+rm -f conftest.err conftest.$ac_ext
+{ echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
+echo "${ECHO_T}$ac_header_preproc" >&6; }
+
+# So?  What about this header?
+case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
+  yes:no: )
+    { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5
+echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;}
+    ac_header_preproc=yes
+    ;;
+  no:yes:* )
+    { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5
+echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header:     check for missing prerequisite headers?" >&5
+echo "$as_me: WARNING: $ac_header:     check for missing prerequisite headers?" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5
+echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&5
+echo "$as_me: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5
+echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;}
+    
+    ;;
+esac
+{ echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; }
+if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  eval "$as_ac_Header=\$ac_header_preproc"
+fi
+ac_res=`eval echo '${'$as_ac_Header'}'`
+              { echo "$as_me:$LINENO: result: $ac_res" >&5
+echo "${ECHO_T}$ac_res" >&6; }
+
+fi
+if test `eval echo '${'$as_ac_Header'}'` = yes; then
+  cat >>confdefs.h <<_ACEOF
+@%:@define `echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+        unet_cv_enable_openssl="yes";
+      
+fi
+
+done
+
+    
+fi
+
+  
+fi
+
+fi
+
+if test x"$unet_cv_enable_gnutls" = xyes; then
+    LIBS="$LIBS -lgnutls"
+    
+cat >>confdefs.h <<\_ACEOF
+@%:@define HAVE_GNUTLS 1
+_ACEOF
+
+fi
+
+if test x"$unet_cv_enable_openssl" = xyes ; then
+    LIBS="$LIBS -lssl -lcrypto"
+    
+cat >>confdefs.h <<\_ACEOF
+@%:@define HAVE_OPENSSL 1
+_ACEOF
+
+fi
+
+ac_config_files="$ac_config_files Makefile ircd/Makefile doc/Makefile"
+
+ac_config_commands="$ac_config_commands default"
+
+cat >confcache <<\_ACEOF
+# This file is a shell script that caches the results of configure
+# tests run on this system so they can be shared between configure
+# scripts and configure runs, see configure's option --config-cache.
+# It is not useful on other systems.  If it contains results you don't
+# want to keep, you may remove or edit it.
+#
+# config.status only pays attention to the cache file if you give it
+# the --recheck option to rerun configure.
+#
+# `ac_cv_env_foo' variables (set or unset) will be overridden when
+# loading this file, other *unset* `ac_cv_foo' will be assigned the
+# following values.
+
+_ACEOF
+
+# The following way of writing the cache mishandles newlines in values,
+# but we know of no workaround that is simple, portable, and efficient.
+# So, we kill variables containing newlines.
+# Ultrix sh set writes to stderr and can't be redirected directly,
+# and sets the high bit in the cache file unless we assign to the vars.
+(
+  for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do
+    eval ac_val=\$$ac_var
+    case $ac_val in #(
+    *${as_nl}*)
+      case $ac_var in #(
+      *_cv_*) { echo "$as_me:$LINENO: WARNING: Cache variable $ac_var contains a newline." >&5
+echo "$as_me: WARNING: Cache variable $ac_var contains a newline." >&2;} ;;
+      esac
+      case $ac_var in #(
+      _ | IFS | as_nl) ;; #(
+      *) $as_unset $ac_var ;;
+      esac ;;
+    esac
+  done
+
+  (set) 2>&1 |
+    case $as_nl`(ac_space=' '; set) 2>&1` in #(
+    *${as_nl}ac_space=\ *)
+      # `set' does not quote correctly, so add quotes (double-quote
+      # substitution turns \\\\ into \\, and sed turns \\ into \).
+      sed -n \
+       "s/'/'\\\\''/g;
+         s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p"
+      ;; #(
+    *)
+      # `set' quotes correctly as required by POSIX, so do not add quotes.
+      sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p"
+      ;;
+    esac |
+    sort
+) |
+  sed '
+     /^ac_cv_env_/b end
+     t clear
+     :clear
+     s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/
+     t end
+     s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/
+     :end' >>confcache
+if diff "$cache_file" confcache >/dev/null 2>&1; then :; else
+  if test -w "$cache_file"; then
+    test "x$cache_file" != "x/dev/null" &&
+      { echo "$as_me:$LINENO: updating cache $cache_file" >&5
+echo "$as_me: updating cache $cache_file" >&6;}
+    cat confcache >$cache_file
+  else
+    { echo "$as_me:$LINENO: not updating unwritable cache $cache_file" >&5
+echo "$as_me: not updating unwritable cache $cache_file" >&6;}
+  fi
+fi
+rm -f confcache
+
+test "x$prefix" = xNONE && prefix=$ac_default_prefix
+# Let make expand exec_prefix.
+test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
+
+DEFS=-DHAVE_CONFIG_H
+
+ac_libobjs=
+ac_ltlibobjs=
+for ac_i in : $LIB@&t@OBJS; do test "x$ac_i" = x: && continue
+  # 1. Remove the extension, and $U if already installed.
+  ac_script='s/\$U\././;s/\.o$//;s/\.obj$//'
+  ac_i=`echo "$ac_i" | sed "$ac_script"`
+  # 2. Prepend LIBOBJDIR.  When used with automake>=1.10 LIBOBJDIR
+  #    will be set to the directory where LIBOBJS objects are built.
+  ac_libobjs="$ac_libobjs \${LIBOBJDIR}$ac_i\$U.$ac_objext"
+  ac_ltlibobjs="$ac_ltlibobjs \${LIBOBJDIR}$ac_i"'$U.lo'
+done
+LIB@&t@OBJS=$ac_libobjs
+
+LTLIBOBJS=$ac_ltlibobjs
+
+
+
+: ${CONFIG_STATUS=./config.status}
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files $CONFIG_STATUS"
+{ echo "$as_me:$LINENO: creating $CONFIG_STATUS" >&5
+echo "$as_me: creating $CONFIG_STATUS" >&6;}
+cat >$CONFIG_STATUS <<_ACEOF
+#! $SHELL
+# Generated by $as_me.
+# Run this file to recreate the current configuration.
+# Compiler output produced by configure, useful for debugging
+# configure, is in config.log if it exists.
+
+debug=false
+ac_cs_recheck=false
+ac_cs_silent=false
+SHELL=\${CONFIG_SHELL-$SHELL}
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF
+## --------------------- ##
+## M4sh Initialization.  ##
+## --------------------- ##
+
+# Be more Bourne compatible
+DUALCASE=1; export DUALCASE # for MKS sh
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then
+  emulate sh
+  NULLCMD=:
+  # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which
+  # is contrary to our usage.  Disable this feature.
+  alias -g '${1+"$@"}'='"$@"'
+  setopt NO_GLOB_SUBST
+else
+  case `(set -o) 2>/dev/null` in
+  *posix*) set -o posix ;;
+esac
+
+fi
+
+
+
+
+# PATH needs CR
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+  echo "#! /bin/sh" >conf$$.sh
+  echo  "exit 0"   >>conf$$.sh
+  chmod +x conf$$.sh
+  if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then
+    PATH_SEPARATOR=';'
+  else
+    PATH_SEPARATOR=:
+  fi
+  rm -f conf$$.sh
+fi
+
+# Support unset when possible.
+if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then
+  as_unset=unset
+else
+  as_unset=false
+fi
+
+
+# IFS
+# We need space, tab and new line, in precisely that order.  Quoting is
+# there to prevent editors from complaining about space-tab.
+# (If _AS_PATH_WALK were called with IFS unset, it would disable word
+# splitting by setting IFS to empty value.)
+as_nl='
+'
+IFS=" ""       $as_nl"
+
+# Find who we are.  Look in the path if we contain no directory separator.
+case $0 in
+  *[\\/]* ) as_myself=$0 ;;
+  *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+done
+IFS=$as_save_IFS
+
+     ;;
+esac
+# We did not find ourselves, most probably we were run as `sh COMMAND'
+# in which case we are not to be found in the path.
+if test "x$as_myself" = x; then
+  as_myself=$0
+fi
+if test ! -f "$as_myself"; then
+  echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
+  { (exit 1); exit 1; }
+fi
+
+# Work around bugs in pre-3.0 UWIN ksh.
+for as_var in ENV MAIL MAILPATH
+do ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var
+done
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+for as_var in \
+  LANG LANGUAGE LC_ADDRESS LC_ALL LC_COLLATE LC_CTYPE LC_IDENTIFICATION \
+  LC_MEASUREMENT LC_MESSAGES LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER \
+  LC_TELEPHONE LC_TIME
+do
+  if (set +x; test -z "`(eval $as_var=C; export $as_var) 2>&1`"); then
+    eval $as_var=C; export $as_var
+  else
+    ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var
+  fi
+done
+
+# Required to use basename.
+if expr a : '\(a\)' >/dev/null 2>&1 &&
+   test "X`expr 00001 : '.*\(...\)'`" = X001; then
+  as_expr=expr
+else
+  as_expr=false
+fi
+
+if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then
+  as_basename=basename
+else
+  as_basename=false
+fi
+
+
+# Name of the executable.
+as_me=`$as_basename -- "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+        X"$0" : 'X\(//\)$' \| \
+        X"$0" : 'X\(/\)' \| . 2>/dev/null ||
+echo X/"$0" |
+    sed '/^.*\/\([^/][^/]*\)\/*$/{
+           s//\1/
+           q
+         }
+         /^X\/\(\/\/\)$/{
+           s//\1/
+           q
+         }
+         /^X\/\(\/\).*/{
+           s//\1/
+           q
+         }
+         s/.*/./; q'`
+
+# CDPATH.
+$as_unset CDPATH
+
+
+
+  as_lineno_1=$LINENO
+  as_lineno_2=$LINENO
+  test "x$as_lineno_1" != "x$as_lineno_2" &&
+  test "x`expr $as_lineno_1 + 1`" = "x$as_lineno_2" || {
+
+  # Create $as_me.lineno as a copy of $as_myself, but with $LINENO
+  # uniformly replaced by the line number.  The first 'sed' inserts a
+  # line-number line after each line using $LINENO; the second 'sed'
+  # does the real work.  The second script uses 'N' to pair each
+  # line-number line with the line containing $LINENO, and appends
+  # trailing '-' during substitution so that $LINENO is not a special
+  # case at line end.
+  # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the
+  # scripts with optimization help from Paolo Bonzini.  Blame Lee
+  # E. McMahon (1931-1989) for sed's syntax.  :-)
+  sed -n '
+    p
+    /[$]LINENO/=
+  ' <$as_myself |
+    sed '
+      s/[$]LINENO.*/&-/
+      t lineno
+      b
+      :lineno
+      N
+      :loop
+      s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/
+      t loop
+      s/-\n.*//
+    ' >$as_me.lineno &&
+  chmod +x "$as_me.lineno" ||
+    { echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2
+   { (exit 1); exit 1; }; }
+
+  # Don't try to exec as it changes $[0], causing all sort of problems
+  # (the dirname of $[0] is not the place where we might find the
+  # original and so on.  Autoconf is especially sensitive to this).
+  . "./$as_me.lineno"
+  # Exit status is that of the last command.
+  exit
+}
+
+
+if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
+  as_dirname=dirname
+else
+  as_dirname=false
+fi
+
+ECHO_C= ECHO_N= ECHO_T=
+case `echo -n x` in
+-n*)
+  case `echo 'x\c'` in
+  *c*) ECHO_T='        ';;     # ECHO_T is single tab character.
+  *)   ECHO_C='\c';;
+  esac;;
+*)
+  ECHO_N='-n';;
+esac
+
+if expr a : '\(a\)' >/dev/null 2>&1 &&
+   test "X`expr 00001 : '.*\(...\)'`" = X001; then
+  as_expr=expr
+else
+  as_expr=false
+fi
+
+rm -f conf$$ conf$$.exe conf$$.file
+if test -d conf$$.dir; then
+  rm -f conf$$.dir/conf$$.file
+else
+  rm -f conf$$.dir
+  mkdir conf$$.dir
+fi
+echo >conf$$.file
+if ln -s conf$$.file conf$$ 2>/dev/null; then
+  as_ln_s='ln -s'
+  # ... but there are two gotchas:
+  # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
+  # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
+  # In both cases, we have to default to `cp -p'.
+  ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
+    as_ln_s='cp -p'
+elif ln conf$$.file conf$$ 2>/dev/null; then
+  as_ln_s=ln
+else
+  as_ln_s='cp -p'
+fi
+rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
+rmdir conf$$.dir 2>/dev/null
+
+if mkdir -p . 2>/dev/null; then
+  as_mkdir_p=:
+else
+  test -d ./-p && rmdir ./-p
+  as_mkdir_p=false
+fi
+
+if test -x / >/dev/null 2>&1; then
+  as_test_x='test -x'
+else
+  if ls -dL / >/dev/null 2>&1; then
+    as_ls_L_option=L
+  else
+    as_ls_L_option=
+  fi
+  as_test_x='
+    eval sh -c '\''
+      if test -d "$1"; then
+        test -d "$1/.";
+      else
+       case $1 in
+        -*)set "./$1";;
+       esac;
+       case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in
+       ???[sx]*):;;*)false;;esac;fi
+    '\'' sh
+  '
+fi
+as_executable_p=$as_test_x
+
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
+
+# Sed expression to map a string onto a valid variable name.
+as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
+
+
+exec 6>&1
+
+# Save the log message, to keep $[0] and so on meaningful, and to
+# report actual input values of CONFIG_FILES etc. instead of their
+# values after options handling.
+ac_log="
+This file was extended by $as_me, which was
+generated by GNU Autoconf 2.61.  Invocation command line was
+
+  CONFIG_FILES    = $CONFIG_FILES
+  CONFIG_HEADERS  = $CONFIG_HEADERS
+  CONFIG_LINKS    = $CONFIG_LINKS
+  CONFIG_COMMANDS = $CONFIG_COMMANDS
+  $ $0 $@
+
+on `(hostname || uname -n) 2>/dev/null | sed 1q`
+"
+
+_ACEOF
+
+cat >>$CONFIG_STATUS <<_ACEOF
+# Files that config.status was made for.
+config_files="$ac_config_files"
+config_headers="$ac_config_headers"
+config_commands="$ac_config_commands"
+
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF
+ac_cs_usage="\
+\`$as_me' instantiates files from templates according to the
+current configuration.
+
+Usage: $0 [OPTIONS] [FILE]...
+
+  -h, --help       print this help, then exit
+  -V, --version    print version number and configuration settings, then exit
+  -q, --quiet      do not print progress messages
+  -d, --debug      don't remove temporary files
+      --recheck    update $as_me by reconfiguring in the same conditions
+  --file=FILE[:TEMPLATE]
+                  instantiate the configuration file FILE
+  --header=FILE[:TEMPLATE]
+                  instantiate the configuration header FILE
+
+Configuration files:
+$config_files
+
+Configuration headers:
+$config_headers
+
+Configuration commands:
+$config_commands
+
+Report bugs to <bug-autoconf@gnu.org>."
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF
+ac_cs_version="\\
+config.status
+configured by $0, generated by GNU Autoconf 2.61,
+  with options \\"`echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`\\"
+
+Copyright (C) 2006 Free Software Foundation, Inc.
+This config.status script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it."
+
+ac_pwd='$ac_pwd'
+srcdir='$srcdir'
+INSTALL='$INSTALL'
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF
+# If no file are specified by the user, then we need to provide default
+# value.  By we need to know if files were specified by the user.
+ac_need_defaults=:
+while test $# != 0
+do
+  case $1 in
+  --*=*)
+    ac_option=`expr "X$1" : 'X\([^=]*\)='`
+    ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'`
+    ac_shift=:
+    ;;
+  *)
+    ac_option=$1
+    ac_optarg=$2
+    ac_shift=shift
+    ;;
+  esac
+
+  case $ac_option in
+  # Handling of the options.
+  -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
+    ac_cs_recheck=: ;;
+  --version | --versio | --versi | --vers | --ver | --ve | --v | -V )
+    echo "$ac_cs_version"; exit ;;
+  --debug | --debu | --deb | --de | --d | -d )
+    debug=: ;;
+  --file | --fil | --fi | --f )
+    $ac_shift
+    CONFIG_FILES="$CONFIG_FILES $ac_optarg"
+    ac_need_defaults=false;;
+  --header | --heade | --head | --hea )
+    $ac_shift
+    CONFIG_HEADERS="$CONFIG_HEADERS $ac_optarg"
+    ac_need_defaults=false;;
+  --he | --h)
+    # Conflict between --help and --header
+    { echo "$as_me: error: ambiguous option: $1
+Try \`$0 --help' for more information." >&2
+   { (exit 1); exit 1; }; };;
+  --help | --hel | -h )
+    echo "$ac_cs_usage"; exit ;;
+  -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+  | -silent | --silent | --silen | --sile | --sil | --si | --s)
+    ac_cs_silent=: ;;
+
+  # This is an error.
+  -*) { echo "$as_me: error: unrecognized option: $1
+Try \`$0 --help' for more information." >&2
+   { (exit 1); exit 1; }; } ;;
+
+  *) ac_config_targets="$ac_config_targets $1"
+     ac_need_defaults=false ;;
+
+  esac
+  shift
+done
+
+ac_configure_extra_args=
+
+if $ac_cs_silent; then
+  exec 6>/dev/null
+  ac_configure_extra_args="$ac_configure_extra_args --silent"
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF
+if \$ac_cs_recheck; then
+  echo "running CONFIG_SHELL=$SHELL $SHELL $0 "$ac_configure_args \$ac_configure_extra_args " --no-create --no-recursion" >&6
+  CONFIG_SHELL=$SHELL
+  export CONFIG_SHELL
+  exec $SHELL "$0"$ac_configure_args \$ac_configure_extra_args --no-create --no-recursion
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF
+exec 5>>config.log
+{
+  echo
+  sed 'h;s/./-/g;s/^.../@%:@@%:@ /;s/...$/ @%:@@%:@/;p;x;p;x' <<_ASBOX
+@%:@@%:@ Running $as_me. @%:@@%:@
+_ASBOX
+  echo "$ac_log"
+} >&5
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF
+
+# Handling of arguments.
+for ac_config_target in $ac_config_targets
+do
+  case $ac_config_target in
+    "config.h") CONFIG_HEADERS="$CONFIG_HEADERS config.h" ;;
+    "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;;
+    "ircd/Makefile") CONFIG_FILES="$CONFIG_FILES ircd/Makefile" ;;
+    "doc/Makefile") CONFIG_FILES="$CONFIG_FILES doc/Makefile" ;;
+    "default") CONFIG_COMMANDS="$CONFIG_COMMANDS default" ;;
+
+  *) { { echo "$as_me:$LINENO: error: invalid argument: $ac_config_target" >&5
+echo "$as_me: error: invalid argument: $ac_config_target" >&2;}
+   { (exit 1); exit 1; }; };;
+  esac
+done
+
+
+# If the user did not use the arguments to specify the items to instantiate,
+# then the envvar interface is used.  Set only those that are not.
+# We use the long form for the default assignment because of an extremely
+# bizarre bug on SunOS 4.1.3.
+if $ac_need_defaults; then
+  test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files
+  test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers
+  test "${CONFIG_COMMANDS+set}" = set || CONFIG_COMMANDS=$config_commands
+fi
+
+# Have a temporary directory for convenience.  Make it in the build tree
+# simply because there is no reason against having it here, and in addition,
+# creating and moving files from /tmp can sometimes cause problems.
+# Hook for its removal unless debugging.
+# Note that there is a small window in which the directory will not be cleaned:
+# after its creation but before its name has been assigned to `$tmp'.
+$debug ||
+{
+  tmp=
+  trap 'exit_status=$?
+  { test -z "$tmp" || test ! -d "$tmp" || rm -fr "$tmp"; } && exit $exit_status
+' 0
+  trap '{ (exit 1); exit 1; }' 1 2 13 15
+}
+# Create a (secure) tmp directory for tmp files.
+
+{
+  tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` &&
+  test -n "$tmp" && test -d "$tmp"
+}  ||
+{
+  tmp=./conf$$-$RANDOM
+  (umask 077 && mkdir "$tmp")
+} ||
+{
+   echo "$me: cannot create a temporary directory in ." >&2
+   { (exit 1); exit 1; }
+}
+
+#
+# Set up the sed scripts for CONFIG_FILES section.
+#
+
+# No need to generate the scripts if there are no CONFIG_FILES.
+# This happens for instance when ./config.status config.h
+if test -n "$CONFIG_FILES"; then
+
+_ACEOF
+
+
+
+ac_delim='%!_!# '
+for ac_last_try in false false false false false :; do
+  cat >conf$$subs.sed <<_ACEOF
+SHELL!$SHELL$ac_delim
+PATH_SEPARATOR!$PATH_SEPARATOR$ac_delim
+PACKAGE_NAME!$PACKAGE_NAME$ac_delim
+PACKAGE_TARNAME!$PACKAGE_TARNAME$ac_delim
+PACKAGE_VERSION!$PACKAGE_VERSION$ac_delim
+PACKAGE_STRING!$PACKAGE_STRING$ac_delim
+PACKAGE_BUGREPORT!$PACKAGE_BUGREPORT$ac_delim
+exec_prefix!$exec_prefix$ac_delim
+prefix!$prefix$ac_delim
+program_transform_name!$program_transform_name$ac_delim
+bindir!$bindir$ac_delim
+sbindir!$sbindir$ac_delim
+libexecdir!$libexecdir$ac_delim
+datarootdir!$datarootdir$ac_delim
+datadir!$datadir$ac_delim
+sysconfdir!$sysconfdir$ac_delim
+sharedstatedir!$sharedstatedir$ac_delim
+localstatedir!$localstatedir$ac_delim
+includedir!$includedir$ac_delim
+oldincludedir!$oldincludedir$ac_delim
+docdir!$docdir$ac_delim
+infodir!$infodir$ac_delim
+htmldir!$htmldir$ac_delim
+dvidir!$dvidir$ac_delim
+pdfdir!$pdfdir$ac_delim
+psdir!$psdir$ac_delim
+libdir!$libdir$ac_delim
+localedir!$localedir$ac_delim
+mandir!$mandir$ac_delim
+DEFS!$DEFS$ac_delim
+ECHO_C!$ECHO_C$ac_delim
+ECHO_N!$ECHO_N$ac_delim
+ECHO_T!$ECHO_T$ac_delim
+LIBS!$LIBS$ac_delim
+build_alias!$build_alias$ac_delim
+host_alias!$host_alias$ac_delim
+target_alias!$target_alias$ac_delim
+build!$build$ac_delim
+build_cpu!$build_cpu$ac_delim
+build_vendor!$build_vendor$ac_delim
+build_os!$build_os$ac_delim
+host!$host$ac_delim
+host_cpu!$host_cpu$ac_delim
+host_vendor!$host_vendor$ac_delim
+host_os!$host_os$ac_delim
+CC!$CC$ac_delim
+CFLAGS!$CFLAGS$ac_delim
+LDFLAGS!$LDFLAGS$ac_delim
+CPPFLAGS!$CPPFLAGS$ac_delim
+ac_ct_CC!$ac_ct_CC$ac_delim
+EXEEXT!$EXEEXT$ac_delim
+OBJEXT!$OBJEXT$ac_delim
+CPP!$CPP$ac_delim
+GREP!$GREP$ac_delim
+EGREP!$EGREP$ac_delim
+AWK!$AWK$ac_delim
+SET_MAKE!$SET_MAKE$ac_delim
+INSTALL_PROGRAM!$INSTALL_PROGRAM$ac_delim
+INSTALL_SCRIPT!$INSTALL_SCRIPT$ac_delim
+INSTALL_DATA!$INSTALL_DATA$ac_delim
+LN_S!$LN_S$ac_delim
+RMPROG!$RMPROG$ac_delim
+SHPROG!$SHPROG$ac_delim
+LEX!$LEX$ac_delim
+LEX_OUTPUT_ROOT!$LEX_OUTPUT_ROOT$ac_delim
+LEXLIB!$LEXLIB$ac_delim
+YACC!$YACC$ac_delim
+YFLAGS!$YFLAGS$ac_delim
+ENGINE_C!$ENGINE_C$ac_delim
+INSTALL_RULE!$INSTALL_RULE$ac_delim
+SYMLINK!$SYMLINK$ac_delim
+IRCDMODE!$IRCDMODE$ac_delim
+IRCDOWN!$IRCDOWN$ac_delim
+IRCDGRP!$IRCDGRP$ac_delim
+DPATH!$DPATH$ac_delim
+LIB@&t@OBJS!$LIB@&t@OBJS$ac_delim
+LTLIBOBJS!$LTLIBOBJS$ac_delim
+_ACEOF
+
+  if test `sed -n "s/.*$ac_delim\$/X/p" conf$$subs.sed | grep -c X` = 77; then
+    break
+  elif $ac_last_try; then
+    { { echo "$as_me:$LINENO: error: could not make $CONFIG_STATUS" >&5
+echo "$as_me: error: could not make $CONFIG_STATUS" >&2;}
+   { (exit 1); exit 1; }; }
+  else
+    ac_delim="$ac_delim!$ac_delim _$ac_delim!! "
+  fi
+done
+
+ac_eof=`sed -n '/^CEOF[0-9]*$/s/CEOF/0/p' conf$$subs.sed`
+if test -n "$ac_eof"; then
+  ac_eof=`echo "$ac_eof" | sort -nru | sed 1q`
+  ac_eof=`expr $ac_eof + 1`
+fi
+
+cat >>$CONFIG_STATUS <<_ACEOF
+cat >"\$tmp/subs-1.sed" <<\CEOF$ac_eof
+/@[a-zA-Z_][a-zA-Z_0-9]*@/!b end
+_ACEOF
+sed '
+s/[,\\&]/\\&/g; s/@/@|#_!!_#|/g
+s/^/s,@/; s/!/@,|#_!!_#|/
+:n
+t n
+s/'"$ac_delim"'$/,g/; t
+s/$/\\/; p
+N; s/^.*\n//; s/[,\\&]/\\&/g; s/@/@|#_!!_#|/g; b n
+' >>$CONFIG_STATUS <conf$$subs.sed
+rm -f conf$$subs.sed
+cat >>$CONFIG_STATUS <<_ACEOF
+:end
+s/|#_!!_#|//g
+CEOF$ac_eof
+_ACEOF
+
+
+# VPATH may cause trouble with some makes, so we remove $(srcdir),
+# ${srcdir} and @srcdir@ from VPATH if srcdir is ".", strip leading and
+# trailing colons and then remove the whole line if VPATH becomes empty
+# (actually we leave an empty line to preserve line numbers).
+if test "x$srcdir" = x.; then
+  ac_vpsub='/^[         ]*VPATH[        ]*=/{
+s/:*\$(srcdir):*/:/
+s/:*\${srcdir}:*/:/
+s/:*@srcdir@:*/:/
+s/^\([^=]*=[    ]*\):*/\1/
+s/:*$//
+s/^[^=]*=[      ]*$//
+}'
+fi
+
+cat >>$CONFIG_STATUS <<\_ACEOF
+fi # test -n "$CONFIG_FILES"
+
+
+for ac_tag in  :F $CONFIG_FILES  :H $CONFIG_HEADERS    :C $CONFIG_COMMANDS
+do
+  case $ac_tag in
+  :[FHLC]) ac_mode=$ac_tag; continue;;
+  esac
+  case $ac_mode$ac_tag in
+  :[FHL]*:*);;
+  :L* | :C*:*) { { echo "$as_me:$LINENO: error: Invalid tag $ac_tag." >&5
+echo "$as_me: error: Invalid tag $ac_tag." >&2;}
+   { (exit 1); exit 1; }; };;
+  :[FH]-) ac_tag=-:-;;
+  :[FH]*) ac_tag=$ac_tag:$ac_tag.in;;
+  esac
+  ac_save_IFS=$IFS
+  IFS=:
+  set x $ac_tag
+  IFS=$ac_save_IFS
+  shift
+  ac_file=$1
+  shift
+
+  case $ac_mode in
+  :L) ac_source=$1;;
+  :[FH])
+    ac_file_inputs=
+    for ac_f
+    do
+      case $ac_f in
+      -) ac_f="$tmp/stdin";;
+      *) # Look for the file first in the build tree, then in the source tree
+        # (if the path is not absolute).  The absolute path cannot be DOS-style,
+        # because $ac_f cannot contain `:'.
+        test -f "$ac_f" ||
+          case $ac_f in
+          [\\/$]*) false;;
+          *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";;
+          esac ||
+          { { echo "$as_me:$LINENO: error: cannot find input file: $ac_f" >&5
+echo "$as_me: error: cannot find input file: $ac_f" >&2;}
+   { (exit 1); exit 1; }; };;
+      esac
+      ac_file_inputs="$ac_file_inputs $ac_f"
+    done
+
+    # Let's still pretend it is `configure' which instantiates (i.e., don't
+    # use $as_me), people would be surprised to read:
+    #    /* config.h.  Generated by config.status.  */
+    configure_input="Generated from "`IFS=:
+         echo $* | sed 's|^[^:]*/||;s|:[^:]*/|, |g'`" by configure."
+    if test x"$ac_file" != x-; then
+      configure_input="$ac_file.  $configure_input"
+      { echo "$as_me:$LINENO: creating $ac_file" >&5
+echo "$as_me: creating $ac_file" >&6;}
+    fi
+
+    case $ac_tag in
+    *:-:* | *:-) cat >"$tmp/stdin";;
+    esac
+    ;;
+  esac
+
+  ac_dir=`$as_dirname -- "$ac_file" ||
+$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+        X"$ac_file" : 'X\(//\)[^/]' \| \
+        X"$ac_file" : 'X\(//\)$' \| \
+        X"$ac_file" : 'X\(/\)' \| . 2>/dev/null ||
+echo X"$ac_file" |
+    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+           s//\1/
+           q
+         }
+         /^X\(\/\/\)[^/].*/{
+           s//\1/
+           q
+         }
+         /^X\(\/\/\)$/{
+           s//\1/
+           q
+         }
+         /^X\(\/\).*/{
+           s//\1/
+           q
+         }
+         s/.*/./; q'`
+  { as_dir="$ac_dir"
+  case $as_dir in #(
+  -*) as_dir=./$as_dir;;
+  esac
+  test -d "$as_dir" || { $as_mkdir_p && mkdir -p "$as_dir"; } || {
+    as_dirs=
+    while :; do
+      case $as_dir in #(
+      *\'*) as_qdir=`echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #(
+      *) as_qdir=$as_dir;;
+      esac
+      as_dirs="'$as_qdir' $as_dirs"
+      as_dir=`$as_dirname -- "$as_dir" ||
+$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+        X"$as_dir" : 'X\(//\)[^/]' \| \
+        X"$as_dir" : 'X\(//\)$' \| \
+        X"$as_dir" : 'X\(/\)' \| . 2>/dev/null ||
+echo X"$as_dir" |
+    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+           s//\1/
+           q
+         }
+         /^X\(\/\/\)[^/].*/{
+           s//\1/
+           q
+         }
+         /^X\(\/\/\)$/{
+           s//\1/
+           q
+         }
+         /^X\(\/\).*/{
+           s//\1/
+           q
+         }
+         s/.*/./; q'`
+      test -d "$as_dir" && break
+    done
+    test -z "$as_dirs" || eval "mkdir $as_dirs"
+  } || test -d "$as_dir" || { { echo "$as_me:$LINENO: error: cannot create directory $as_dir" >&5
+echo "$as_me: error: cannot create directory $as_dir" >&2;}
+   { (exit 1); exit 1; }; }; }
+  ac_builddir=.
+
+case "$ac_dir" in
+.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
+*)
+  ac_dir_suffix=/`echo "$ac_dir" | sed 's,^\.[\\/],,'`
+  # A ".." for each directory in $ac_dir_suffix.
+  ac_top_builddir_sub=`echo "$ac_dir_suffix" | sed 's,/[^\\/]*,/..,g;s,/,,'`
+  case $ac_top_builddir_sub in
+  "") ac_top_builddir_sub=. ac_top_build_prefix= ;;
+  *)  ac_top_build_prefix=$ac_top_builddir_sub/ ;;
+  esac ;;
+esac
+ac_abs_top_builddir=$ac_pwd
+ac_abs_builddir=$ac_pwd$ac_dir_suffix
+# for backward compatibility:
+ac_top_builddir=$ac_top_build_prefix
+
+case $srcdir in
+  .)  # We are building in place.
+    ac_srcdir=.
+    ac_top_srcdir=$ac_top_builddir_sub
+    ac_abs_top_srcdir=$ac_pwd ;;
+  [\\/]* | ?:[\\/]* )  # Absolute name.
+    ac_srcdir=$srcdir$ac_dir_suffix;
+    ac_top_srcdir=$srcdir
+    ac_abs_top_srcdir=$srcdir ;;
+  *) # Relative name.
+    ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix
+    ac_top_srcdir=$ac_top_build_prefix$srcdir
+    ac_abs_top_srcdir=$ac_pwd/$srcdir ;;
+esac
+ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix
+
+
+  case $ac_mode in
+  :F)
+  #
+  # CONFIG_FILE
+  #
+
+  case $INSTALL in
+  [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;;
+  *) ac_INSTALL=$ac_top_build_prefix$INSTALL ;;
+  esac
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF
+# If the template does not know about datarootdir, expand it.
+# FIXME: This hack should be removed a few years after 2.60.
+ac_datarootdir_hack=; ac_datarootdir_seen=
+
+case `sed -n '/datarootdir/ {
+  p
+  q
+}
+/@datadir@/p
+/@docdir@/p
+/@infodir@/p
+/@localedir@/p
+/@mandir@/p
+' $ac_file_inputs` in
+*datarootdir*) ac_datarootdir_seen=yes;;
+*@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*)
+  { echo "$as_me:$LINENO: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5
+echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;}
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF
+  ac_datarootdir_hack='
+  s&@datadir@&$datadir&g
+  s&@docdir@&$docdir&g
+  s&@infodir@&$infodir&g
+  s&@localedir@&$localedir&g
+  s&@mandir@&$mandir&g
+    s&\\\${datarootdir}&$datarootdir&g' ;;
+esac
+_ACEOF
+
+# Neutralize VPATH when `$srcdir' = `.'.
+# Shell code in configure.ac might set extrasub.
+# FIXME: do we really want to maintain this feature?
+cat >>$CONFIG_STATUS <<_ACEOF
+  sed "$ac_vpsub
+$extrasub
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF
+:t
+/@[a-zA-Z_][a-zA-Z_0-9]*@/!b
+s&@configure_input@&$configure_input&;t t
+s&@top_builddir@&$ac_top_builddir_sub&;t t
+s&@srcdir@&$ac_srcdir&;t t
+s&@abs_srcdir@&$ac_abs_srcdir&;t t
+s&@top_srcdir@&$ac_top_srcdir&;t t
+s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t
+s&@builddir@&$ac_builddir&;t t
+s&@abs_builddir@&$ac_abs_builddir&;t t
+s&@abs_top_builddir@&$ac_abs_top_builddir&;t t
+s&@INSTALL@&$ac_INSTALL&;t t
+$ac_datarootdir_hack
+" $ac_file_inputs | sed -f "$tmp/subs-1.sed" >$tmp/out
+
+test -z "$ac_datarootdir_hack$ac_datarootdir_seen" &&
+  { ac_out=`sed -n '/\${datarootdir}/p' "$tmp/out"`; test -n "$ac_out"; } &&
+  { ac_out=`sed -n '/^[         ]*datarootdir[  ]*:*=/p' "$tmp/out"`; test -z "$ac_out"; } &&
+  { echo "$as_me:$LINENO: WARNING: $ac_file contains a reference to the variable \`datarootdir'
+which seems to be undefined.  Please make sure it is defined." >&5
+echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir'
+which seems to be undefined.  Please make sure it is defined." >&2;}
+
+  rm -f "$tmp/stdin"
+  case $ac_file in
+  -) cat "$tmp/out"; rm -f "$tmp/out";;
+  *) rm -f "$ac_file"; mv "$tmp/out" $ac_file;;
+  esac
+ ;;
+  :H)
+  #
+  # CONFIG_HEADER
+  #
+_ACEOF
+
+# Transform confdefs.h into a sed script `conftest.defines', that
+# substitutes the proper values into config.h.in to produce config.h.
+rm -f conftest.defines conftest.tail
+# First, append a space to every undef/define line, to ease matching.
+echo 's/$/ /' >conftest.defines
+# Then, protect against being on the right side of a sed subst, or in
+# an unquoted here document, in config.status.  If some macros were
+# called several times there might be several #defines for the same
+# symbol, which is useless.  But do not sort them, since the last
+# AC_DEFINE must be honored.
+ac_word_re=[_$as_cr_Letters][_$as_cr_alnum]*
+# These sed commands are passed to sed as "A NAME B PARAMS C VALUE D", where
+# NAME is the cpp macro being defined, VALUE is the value it is being given.
+# PARAMS is the parameter list in the macro definition--in most cases, it's
+# just an empty string.
+ac_dA='s,^\\([  #]*\\)[^        ]*\\([  ]*'
+ac_dB='\\)[     (].*,\\1define\\2'
+ac_dC=' '
+ac_dD=' ,'
+
+uniq confdefs.h |
+  sed -n '
+       t rset
+       :rset
+       s/^[     ]*#[    ]*define[       ][      ]*//
+       t ok
+       d
+       :ok
+       s/[\\&,]/\\&/g
+       s/^\('"$ac_word_re"'\)\(([^()]*)\)[      ]*\(.*\)/ '"$ac_dA"'\1'"$ac_dB"'\2'"${ac_dC}"'\3'"$ac_dD"'/p
+       s/^\('"$ac_word_re"'\)[  ]*\(.*\)/'"$ac_dA"'\1'"$ac_dB$ac_dC"'\2'"$ac_dD"'/p
+  ' >>conftest.defines
+
+# Remove the space that was appended to ease matching.
+# Then replace #undef with comments.  This is necessary, for
+# example, in the case of _POSIX_SOURCE, which is predefined and required
+# on some systems where configure will not decide to define it.
+# (The regexp can be short, since the line contains either #define or #undef.)
+echo 's/ $//
+s,^[    #]*u.*,/* & */,' >>conftest.defines
+
+# Break up conftest.defines:
+ac_max_sed_lines=50
+
+# First sed command is:         sed -f defines.sed $ac_file_inputs >"$tmp/out1"
+# Second one is:        sed -f defines.sed "$tmp/out1" >"$tmp/out2"
+# Third one will be:    sed -f defines.sed "$tmp/out2" >"$tmp/out1"
+# et cetera.
+ac_in='$ac_file_inputs'
+ac_out='"$tmp/out1"'
+ac_nxt='"$tmp/out2"'
+
+while :
+do
+  # Write a here document:
+    cat >>$CONFIG_STATUS <<_ACEOF
+    # First, check the format of the line:
+    cat >"\$tmp/defines.sed" <<\\CEOF
+/^[     ]*#[    ]*undef[        ][      ]*$ac_word_re[  ]*\$/b def
+/^[     ]*#[    ]*define[       ][      ]*$ac_word_re[(         ]/b def
+b
+:def
+_ACEOF
+  sed ${ac_max_sed_lines}q conftest.defines >>$CONFIG_STATUS
+  echo 'CEOF
+    sed -f "$tmp/defines.sed"' "$ac_in >$ac_out" >>$CONFIG_STATUS
+  ac_in=$ac_out; ac_out=$ac_nxt; ac_nxt=$ac_in
+  sed 1,${ac_max_sed_lines}d conftest.defines >conftest.tail
+  grep . conftest.tail >/dev/null || break
+  rm -f conftest.defines
+  mv conftest.tail conftest.defines
+done
+rm -f conftest.defines conftest.tail
+
+echo "ac_result=$ac_in" >>$CONFIG_STATUS
+cat >>$CONFIG_STATUS <<\_ACEOF
+  if test x"$ac_file" != x-; then
+    echo "/* $configure_input  */" >"$tmp/config.h"
+    cat "$ac_result" >>"$tmp/config.h"
+    if diff $ac_file "$tmp/config.h" >/dev/null 2>&1; then
+      { echo "$as_me:$LINENO: $ac_file is unchanged" >&5
+echo "$as_me: $ac_file is unchanged" >&6;}
+    else
+      rm -f $ac_file
+      mv "$tmp/config.h" $ac_file
+    fi
+  else
+    echo "/* $configure_input  */"
+    cat "$ac_result"
+  fi
+  rm -f "$tmp/out12"
+ ;;
+  
+  :C)  { echo "$as_me:$LINENO: executing $ac_file commands" >&5
+echo "$as_me: executing $ac_file commands" >&6;}
+ ;;
+  esac
+
+
+  case $ac_file$ac_mode in
+    "default":C) echo timestamp > stamp-h ;;
+
+  esac
+done # for ac_tag
+
+
+{ (exit 0); exit 0; }
+_ACEOF
+chmod +x $CONFIG_STATUS
+ac_clean_files=$ac_clean_files_save
+
+
+# configure is writing to config.log, and then calls config.status.
+# config.status does its own redirection, appending to config.log.
+# Unfortunately, on DOS this fails, as config.log is still kept open
+# by configure, so config.status won't be able to write to it; its
+# output is simply discarded.  So we exec the FD to /dev/null,
+# effectively closing config.log, so it can be properly (re)opened and
+# appended to by config.status.  When coming back to configure, we
+# need to make the FD available again.
+if test "$no_create" != yes; then
+  ac_cs_success=:
+  ac_config_status_args=
+  test "$silent" = yes &&
+    ac_config_status_args="$ac_config_status_args --quiet"
+  exec 5>/dev/null
+  $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false
+  exec 5>>config.log
+  # Use ||, not &&, to avoid exiting from the if with $? = 1, which
+  # would make configure fail if this is the last instruction.
+  $ac_cs_success || { (exit 1); exit 1; }
+fi
+
+
+{ echo "$as_me:$LINENO: result: 
+ircu is now hopefully configured for your system.
+
+  Host system:         $host_os
+  Prefix:              $prefix
+  Asserts:             $unet_cv_enable_asserts
+  Warnings:            $unet_cv_enable_warnings
+  Debug:               $unet_cv_enable_debug
+  Profile:             $unet_cv_enable_profile
+  Owner/mode:          $unet_cv_with_owner.$unet_cv_with_group ($unet_cv_with_mode)
+  Chroot:              $unet_cv_with_chroot
+  OpenSSL:             $unet_cv_enable_openssl
+  GnuTLS:              $unet_cv_enable_gnutls
+  Compatibility mode:  $unet_cv_enable_compat
+  Unstable features:   $unet_cv_enable_unstable
+
+  Domain:              $unet_cv_with_domain
+  DPath:               $unet_cv_with_dpath
+  CPath:               $unet_cv_with_cpath
+  LPath:               $unet_cv_with_lpath
+  Maximum connections: $unet_cv_with_maxcon
+
+  poll() engine:       $unet_cv_enable_poll
+  kqueue() engine:     $unet_cv_enable_kqueue
+  /dev/poll engine:    $unet_cv_enable_devpoll
+  epoll() engine:      $unet_cv_enable_epoll
+" >&5
+echo "${ECHO_T}
+ircu is now hopefully configured for your system.
+
+  Host system:         $host_os
+  Prefix:              $prefix
+  Asserts:             $unet_cv_enable_asserts
+  Warnings:            $unet_cv_enable_warnings
+  Debug:               $unet_cv_enable_debug
+  Profile:             $unet_cv_enable_profile
+  Owner/mode:          $unet_cv_with_owner.$unet_cv_with_group ($unet_cv_with_mode)
+  Chroot:              $unet_cv_with_chroot
+  OpenSSL:             $unet_cv_enable_openssl
+  GnuTLS:              $unet_cv_enable_gnutls
+  Compatibility mode:  $unet_cv_enable_compat
+  Unstable features:   $unet_cv_enable_unstable
+
+  Domain:              $unet_cv_with_domain
+  DPath:               $unet_cv_with_dpath
+  CPath:               $unet_cv_with_cpath
+  LPath:               $unet_cv_with_lpath
+  Maximum connections: $unet_cv_with_maxcon
+
+  poll() engine:       $unet_cv_enable_poll
+  kqueue() engine:     $unet_cv_enable_kqueue
+  /dev/poll engine:    $unet_cv_enable_devpoll
+  epoll() engine:      $unet_cv_enable_epoll
+" >&6; }
diff --git a/autom4te.cache/requests b/autom4te.cache/requests
new file mode 100644 (file)
index 0000000..892c4b5
--- /dev/null
@@ -0,0 +1,94 @@
+# This file was generated by Autom4te Mon Aug 11 20:59:21 PDT 2008.
+# It contains the lists of macros which have been traced.
+# It can be safely removed.
+
+@request = (
+             bless( [
+                      '0',
+                      1,
+                      [
+                        '/usr/share/autoconf'
+                      ],
+                      [
+                        '/usr/share/autoconf/autoconf/autoconf.m4f',
+                        '/usr/share/aclocal-1.10/ccstdc.m4',
+                        'acinclude.m4',
+                        'configure.in'
+                      ],
+                      {
+                        'AC_LIBRARY_NET' => 1,
+                        '_AM_AUTOCONF_VERSION' => 1,
+                        'm4_pattern_allow' => 1,
+                        'm4_pattern_forbid' => 1,
+                        'include' => 1,
+                        'AC_DEFUN_ONCE' => 1,
+                        'unet_CHECK_TYPE_SIZES' => 1,
+                        'm4_include' => 1,
+                        'AC_DEFUN' => 1,
+                        'unet_SIGNALS' => 1,
+                        '_m4_warn' => 1,
+                        'AM_PROG_CC_STDC' => 1,
+                        'AU_DEFUN' => 1,
+                        'unet_NONBLOCKING' => 1,
+                        'fp_PROG_CC_STDC' => 1
+                      }
+                    ], 'Autom4te::Request' ),
+             bless( [
+                      '1',
+                      1,
+                      [
+                        '/usr/share/autoconf'
+                      ],
+                      [
+                        '/usr/share/autoconf/autoconf/autoconf.m4f',
+                        'aclocal.m4',
+                        'configure.in'
+                      ],
+                      {
+                        '_LT_AC_TAGCONFIG' => 1,
+                        'AM_PROG_F77_C_O' => 1,
+                        'AC_INIT' => 1,
+                        'm4_pattern_forbid' => 1,
+                        'AC_CANONICAL_TARGET' => 1,
+                        'AC_SUBST' => 1,
+                        'AC_CONFIG_LIBOBJ_DIR' => 1,
+                        'AC_FC_SRCEXT' => 1,
+                        'AC_CANONICAL_HOST' => 1,
+                        'AC_PROG_LIBTOOL' => 1,
+                        'AM_INIT_AUTOMAKE' => 1,
+                        'AC_CONFIG_SUBDIRS' => 1,
+                        'AM_AUTOMAKE_VERSION' => 1,
+                        'LT_CONFIG_LTDL_DIR' => 1,
+                        'AC_REQUIRE_AUX_FILE' => 1,
+                        'AC_CONFIG_LINKS' => 1,
+                        'm4_sinclude' => 1,
+                        'LT_SUPPORTED_TAG' => 1,
+                        'AM_MAINTAINER_MODE' => 1,
+                        'AM_GNU_GETTEXT_INTL_SUBDIR' => 1,
+                        '_m4_warn' => 1,
+                        'AM_PROG_CXX_C_O' => 1,
+                        'AM_ENABLE_MULTILIB' => 1,
+                        'AC_CONFIG_FILES' => 1,
+                        'include' => 1,
+                        'LT_INIT' => 1,
+                        'AM_GNU_GETTEXT' => 1,
+                        'AC_LIBSOURCE' => 1,
+                        'AM_PROG_FC_C_O' => 1,
+                        'AC_CANONICAL_BUILD' => 1,
+                        'AC_FC_FREEFORM' => 1,
+                        'AH_OUTPUT' => 1,
+                        '_AM_SUBST_NOTMAKE' => 1,
+                        'AC_CONFIG_AUX_DIR' => 1,
+                        'sinclude' => 1,
+                        'm4_pattern_allow' => 1,
+                        'AM_PROG_CC_C_O' => 1,
+                        'AC_CANONICAL_SYSTEM' => 1,
+                        'AM_CONDITIONAL' => 1,
+                        'AC_CONFIG_HEADERS' => 1,
+                        'AC_DEFINE_TRACE_LITERAL' => 1,
+                        'm4_include' => 1,
+                        'AC_SUBST_TRACE' => 1
+                      }
+                    ], 'Autom4te::Request' )
+           );
+
diff --git a/autom4te.cache/traces.0 b/autom4te.cache/traces.0
new file mode 100644 (file)
index 0000000..14469aa
--- /dev/null
@@ -0,0 +1,409 @@
+m4trace:/usr/share/aclocal-1.10/ccstdc.m4:17: -1- AU_DEFUN([AM_PROG_CC_STDC], [AC_PROG_CC
+AC_DIAGNOSE([obsolete], [$0:
+       your code should no longer depend upon `am_cv_prog_cc_stdc', but upon
+       `ac_cv_prog_cc_stdc'.  Remove this warning and the assignment when
+       you adjust the code.  You can also remove the above call to
+       AC_PROG_CC if you already called it elsewhere.])
+am_cv_prog_cc_stdc=$ac_cv_prog_cc_stdc
+])
+m4trace:/usr/share/aclocal-1.10/ccstdc.m4:17: -1- AC_DEFUN([AM_PROG_CC_STDC], [AC_DIAGNOSE([obsolete], [The macro `AM_PROG_CC_STDC' is obsolete.
+You should run autoupdate.])dnl
+AC_PROG_CC
+AC_DIAGNOSE([obsolete], [$0:
+       your code should no longer depend upon `am_cv_prog_cc_stdc', but upon
+       `ac_cv_prog_cc_stdc'.  Remove this warning and the assignment when
+       you adjust the code.  You can also remove the above call to
+       AC_PROG_CC if you already called it elsewhere.])
+am_cv_prog_cc_stdc=$ac_cv_prog_cc_stdc
+])
+m4trace:/usr/share/aclocal-1.10/ccstdc.m4:26: -1- AU_DEFUN([fp_PROG_CC_STDC])
+m4trace:/usr/share/aclocal-1.10/ccstdc.m4:26: -1- AC_DEFUN([fp_PROG_CC_STDC], [AC_DIAGNOSE([obsolete], [The macro `fp_PROG_CC_STDC' is obsolete.
+You should run autoupdate.])dnl
+])
+m4trace:acinclude.m4:7: -1- AC_DEFUN([unet_NONBLOCKING], [dnl Do we have posix, bsd or sysv non-blocking stuff ?
+AC_CACHE_CHECK([for posix non-blocking], unet_cv_sys_nonblocking_posix,
+[AC_TRY_RUN([#include <sys/types.h>
+#include <sys/socket.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <sys/file.h>
+#include <signal.h>
+$ac_cv_type_signal alarmed() { exit(1); }
+int main(void)
+{
+  char b[12];
+  struct sockaddr x;
+  size_t l = sizeof(x);
+  int f = socket(AF_INET, SOCK_DGRAM, 0);
+  if (f >= 0 && !(fcntl(f, F_SETFL, O_NONBLOCK)))
+  {
+    signal(SIGALRM, alarmed);
+    alarm(2);
+    recvfrom(f, b, 12, 0, &x, &l);
+    alarm(0);
+    exit(0);
+  }
+  exit(1);
+}], unet_cv_sys_nonblocking_posix=yes, unet_cv_sys_nonblocking_posix=no)])
+if test $unet_cv_sys_nonblocking_posix = yes; then
+  AC_DEFINE([NBLOCK_POSIX],,[Define if you have POSIX non-blocking sockets.])
+else
+AC_CACHE_CHECK([for bsd non-blocking], unet_cv_sys_nonblocking_bsd,
+[AC_TRY_RUN([#include <sys/types.h>
+#include <sys/socket.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <sys/file.h>
+#include <signal.h>
+$ac_cv_type_signal alarmed() { exit(1); }
+int main(void)
+{
+  char b[12];
+  struct sockaddr x;
+  size_t l = sizeof(x);
+  int f = socket(AF_INET, SOCK_DGRAM, 0);
+  if (f >= 0 && !(fcntl(f, F_SETFL, O_NDELAY)))
+  {
+    signal(SIGALRM, alarmed);
+    alarm(2);
+    recvfrom(f, b, 12, 0, &x, &l);
+    alarm(0);
+    exit(0);
+  }
+  exit(1);
+}], unet_cv_sys_nonblocking_bsd=yes, unet_cv_sys_nonblocking_bsd=no)])
+if test $unet_cv_sys_nonblocking_bsd = yes; then
+  AC_DEFINE([NBLOCK_BSD],,[Define if you have BSD non-blocking sockets.])
+else
+  AC_DEFINE([NBLOCK_SYSV],,[Define if you have SysV non-blocking sockets.])
+fi
+fi])
+m4trace:acinclude.m4:74: -1- AC_DEFUN([unet_SIGNALS], [dnl Do we have posix signals, reliable bsd signals or unreliable sysv signals ?
+AC_CACHE_CHECK([for posix signals], unet_cv_sys_signal_posix,
+[AC_TRY_COMPILE([#include <signal.h>],
+[sigaction(SIGTERM, (struct sigaction *)0L, (struct sigaction *)0L)],
+unet_cv_sys_signal_posix=yes, unet_cv_sys_signal_posix=no)])
+if test $unet_cv_sys_signal_posix = yes; then
+  AC_DEFINE([POSIX_SIGNALS],,[Define if you have POSIX signals.])
+else
+AC_CACHE_CHECK([for bsd reliable signals], unet_cv_sys_signal_bsd,
+[AC_TRY_RUN([#include <signal.h>
+int calls = 0;
+$ac_cv_type_signal handler()
+{
+  if (calls) return;
+  calls++;
+  kill(getpid(), SIGTERM);
+  sleep(1);
+}
+int main(void)
+{
+  signal(SIGTERM, handler);
+  kill(getpid(), SIGTERM);
+  exit (0);
+}], unet_cv_sys_signal_bsd=yes, unet_cv_sys_signal_bsd=no)])
+if test $unet_cv_sys_signal_bsd = yes; then
+  AC_DEFINE([BSD_RELIABLE_SIGNALS],,[Define if you have (reliable) BSD signals.])
+else
+  AC_DEFINE([SYSV_UNRELIABLE_SIGNALS],,[Define if you have (unreliable) SysV signals.])
+fi
+fi])
+m4trace:acinclude.m4:111: -1- AC_DEFUN([unet_CHECK_TYPE_SIZES], [dnl Check type sizes
+AC_CHECK_SIZEOF(short)
+AC_CHECK_SIZEOF(int)
+AC_CHECK_SIZEOF(long)
+AC_CHECK_SIZEOF(void *)
+AC_CHECK_SIZEOF(int64_t)
+AC_CHECK_SIZEOF(long long)
+if test "$ac_cv_sizeof_int" = 2 ; then
+  AC_CHECK_TYPE(int16_t, int)
+  AC_CHECK_TYPE(uint16_t, unsigned int)
+elif test "$ac_cv_sizeof_short" = 2 ; then
+  AC_CHECK_TYPE(int16_t, short)
+  AC_CHECK_TYPE(uint16_t, unsigned short)
+else
+  AC_MSG_ERROR([Cannot find a type with size of 16 bits])
+fi
+if test "$ac_cv_sizeof_int" = 4 ; then
+  AC_CHECK_TYPE(int32_t, int)
+  AC_CHECK_TYPE(uint32_t, unsigned int)
+elif test "$ac_cv_sizeof_short" = 4 ; then
+  AC_CHECK_TYPE(int32_t, short)
+  AC_CHECK_TYPE(uint32_t, unsigned short)
+elif test "$ac_cv_sizeof_long" = 4 ; then
+  AC_CHECK_TYPE(int32_t, long)
+  AC_CHECK_TYPE(uint32_t, unsigned long)
+else
+  AC_MSG_ERROR([Cannot find a type with size of 32 bits])
+fi
+if test "$ac_cv_sizeof_int64_t" = 8 ; then
+  AC_CHECK_TYPE(int64_t)
+  AC_CHECK_TYPE(uint64_t)
+elif test "$ac_cv_sizeof_long_long" = 8 ; then
+  AC_CHECK_TYPE(int64_t, long long)
+  AC_CHECK_TYPE(uint64_t, unsigned long long)
+else
+  AC_MSG_ERROR([Cannot find a type with size of 64 bits])
+fi])
+m4trace:acinclude.m4:182: -1- AC_DEFUN([AC_LIBRARY_NET], [
+   # Most operating systems have gethostbyname() in the default searched
+   # libraries (i.e. libc):
+   AC_CHECK_FUNC(gethostbyname, ,
+     # Some OSes (eg. Solaris) place it in libnsl:
+     AC_CHECK_LIB(nsl, gethostbyname, , 
+       # Some strange OSes (SINIX) have it in libsocket:
+       AC_CHECK_LIB(socket, gethostbyname, ,
+          # Unfortunately libsocket sometimes depends on libnsl.
+          # AC_CHECK_LIB's API is essentially broken so the following
+          # ugliness is necessary:
+          AC_CHECK_LIB(socket, gethostbyname,
+             LIBS="-lsocket -lnsl $LIBS",
+               AC_CHECK_LIB(resolv, gethostbyname),
+             -lnsl)
+       )
+     )
+   )
+  AC_CHECK_FUNC(socket, , AC_CHECK_LIB(socket, socket, ,
+    AC_CHECK_LIB(socket, socket, LIBS="-lsocket -lnsl $LIBS", , -lnsl)))
+  ])
+m4trace:configure.in:26: -1- m4_pattern_forbid([^_?A[CHUM]_])
+m4trace:configure.in:26: -1- m4_pattern_forbid([_AC_])
+m4trace:configure.in:26: -1- m4_pattern_forbid([^LIBOBJS$], [do not use LIBOBJS directly, use AC_LIBOBJ (see section `AC_LIBOBJ vs LIBOBJS'])
+m4trace:configure.in:26: -1- m4_pattern_allow([^AS_FLAGS$])
+m4trace:configure.in:26: -1- m4_pattern_forbid([^_?m4_])
+m4trace:configure.in:26: -1- m4_pattern_forbid([^dnl$])
+m4trace:configure.in:26: -1- m4_pattern_forbid([^_?AS_])
+m4trace:configure.in:26: -1- m4_pattern_allow([^SHELL$])
+m4trace:configure.in:26: -1- m4_pattern_allow([^PATH_SEPARATOR$])
+m4trace:configure.in:26: -1- m4_pattern_allow([^PACKAGE_NAME$])
+m4trace:configure.in:26: -1- m4_pattern_allow([^PACKAGE_TARNAME$])
+m4trace:configure.in:26: -1- m4_pattern_allow([^PACKAGE_VERSION$])
+m4trace:configure.in:26: -1- m4_pattern_allow([^PACKAGE_STRING$])
+m4trace:configure.in:26: -1- m4_pattern_allow([^PACKAGE_BUGREPORT$])
+m4trace:configure.in:26: -1- m4_pattern_allow([^exec_prefix$])
+m4trace:configure.in:26: -1- m4_pattern_allow([^prefix$])
+m4trace:configure.in:26: -1- m4_pattern_allow([^program_transform_name$])
+m4trace:configure.in:26: -1- m4_pattern_allow([^bindir$])
+m4trace:configure.in:26: -1- m4_pattern_allow([^sbindir$])
+m4trace:configure.in:26: -1- m4_pattern_allow([^libexecdir$])
+m4trace:configure.in:26: -1- m4_pattern_allow([^datarootdir$])
+m4trace:configure.in:26: -1- m4_pattern_allow([^datadir$])
+m4trace:configure.in:26: -1- m4_pattern_allow([^sysconfdir$])
+m4trace:configure.in:26: -1- m4_pattern_allow([^sharedstatedir$])
+m4trace:configure.in:26: -1- m4_pattern_allow([^localstatedir$])
+m4trace:configure.in:26: -1- m4_pattern_allow([^includedir$])
+m4trace:configure.in:26: -1- m4_pattern_allow([^oldincludedir$])
+m4trace:configure.in:26: -1- m4_pattern_allow([^docdir$])
+m4trace:configure.in:26: -1- m4_pattern_allow([^infodir$])
+m4trace:configure.in:26: -1- m4_pattern_allow([^htmldir$])
+m4trace:configure.in:26: -1- m4_pattern_allow([^dvidir$])
+m4trace:configure.in:26: -1- m4_pattern_allow([^pdfdir$])
+m4trace:configure.in:26: -1- m4_pattern_allow([^psdir$])
+m4trace:configure.in:26: -1- m4_pattern_allow([^libdir$])
+m4trace:configure.in:26: -1- m4_pattern_allow([^localedir$])
+m4trace:configure.in:26: -1- m4_pattern_allow([^mandir$])
+m4trace:configure.in:26: -1- m4_pattern_allow([^PACKAGE_NAME$])
+m4trace:configure.in:26: -1- m4_pattern_allow([^PACKAGE_TARNAME$])
+m4trace:configure.in:26: -1- m4_pattern_allow([^PACKAGE_VERSION$])
+m4trace:configure.in:26: -1- m4_pattern_allow([^PACKAGE_STRING$])
+m4trace:configure.in:26: -1- m4_pattern_allow([^PACKAGE_BUGREPORT$])
+m4trace:configure.in:26: -1- m4_pattern_allow([^DEFS$])
+m4trace:configure.in:26: -1- m4_pattern_allow([^ECHO_C$])
+m4trace:configure.in:26: -1- m4_pattern_allow([^ECHO_N$])
+m4trace:configure.in:26: -1- m4_pattern_allow([^ECHO_T$])
+m4trace:configure.in:26: -1- m4_pattern_allow([^LIBS$])
+m4trace:configure.in:26: -1- m4_pattern_allow([^build_alias$])
+m4trace:configure.in:26: -1- m4_pattern_allow([^host_alias$])
+m4trace:configure.in:26: -1- m4_pattern_allow([^target_alias$])
+m4trace:configure.in:48: -1- m4_pattern_allow([^build$])
+m4trace:configure.in:48: -1- m4_pattern_allow([^build_cpu$])
+m4trace:configure.in:48: -1- m4_pattern_allow([^build_vendor$])
+m4trace:configure.in:48: -1- m4_pattern_allow([^build_os$])
+m4trace:configure.in:48: -1- m4_pattern_allow([^host$])
+m4trace:configure.in:48: -1- m4_pattern_allow([^host_cpu$])
+m4trace:configure.in:48: -1- m4_pattern_allow([^host_vendor$])
+m4trace:configure.in:48: -1- m4_pattern_allow([^host_os$])
+m4trace:configure.in:51: -1- m4_pattern_allow([^CC$])
+m4trace:configure.in:51: -1- m4_pattern_allow([^CFLAGS$])
+m4trace:configure.in:51: -1- m4_pattern_allow([^LDFLAGS$])
+m4trace:configure.in:51: -1- m4_pattern_allow([^LIBS$])
+m4trace:configure.in:51: -1- m4_pattern_allow([^CPPFLAGS$])
+m4trace:configure.in:51: -1- m4_pattern_allow([^CC$])
+m4trace:configure.in:51: -1- m4_pattern_allow([^CC$])
+m4trace:configure.in:51: -1- m4_pattern_allow([^CC$])
+m4trace:configure.in:51: -1- m4_pattern_allow([^CC$])
+m4trace:configure.in:51: -1- m4_pattern_allow([^ac_ct_CC$])
+m4trace:configure.in:51: -1- m4_pattern_allow([^EXEEXT$])
+m4trace:configure.in:51: -1- m4_pattern_allow([^OBJEXT$])
+m4trace:configure.in:54: -1- AM_PROG_CC_STDC
+m4trace:configure.in:54: -1- _m4_warn([obsolete], [The macro `AM_PROG_CC_STDC' is obsolete.
+You should run autoupdate.], [/usr/share/aclocal-1.10/ccstdc.m4:17: AM_PROG_CC_STDC is expanded from...
+configure.in:54: the top level])
+m4trace:configure.in:54: -1- m4_pattern_allow([^CC$])
+m4trace:configure.in:54: -1- m4_pattern_allow([^CFLAGS$])
+m4trace:configure.in:54: -1- m4_pattern_allow([^LDFLAGS$])
+m4trace:configure.in:54: -1- m4_pattern_allow([^LIBS$])
+m4trace:configure.in:54: -1- m4_pattern_allow([^CPPFLAGS$])
+m4trace:configure.in:54: -1- m4_pattern_allow([^CC$])
+m4trace:configure.in:54: -1- m4_pattern_allow([^CC$])
+m4trace:configure.in:54: -1- m4_pattern_allow([^CC$])
+m4trace:configure.in:54: -1- m4_pattern_allow([^CC$])
+m4trace:configure.in:54: -1- m4_pattern_allow([^ac_ct_CC$])
+m4trace:configure.in:54: -1- _m4_warn([obsolete], [AM_PROG_CC_STDC:
+       your code should no longer depend upon `am_cv_prog_cc_stdc', but upon
+       `ac_cv_prog_cc_stdc'.  Remove this warning and the assignment when
+       you adjust the code.  You can also remove the above call to
+       AC_PROG_CC if you already called it elsewhere.], [/usr/share/aclocal-1.10/ccstdc.m4:17: AM_PROG_CC_STDC is expanded from...
+configure.in:54: the top level])
+m4trace:configure.in:63: -1- AC_LIBRARY_NET
+m4trace:configure.in:63: -5- m4_pattern_allow([^HAVE_LIBRESOLV$])
+m4trace:configure.in:63: -3- m4_pattern_allow([^HAVE_LIBSOCKET$])
+m4trace:configure.in:63: -2- m4_pattern_allow([^HAVE_LIBNSL$])
+m4trace:configure.in:63: -2- m4_pattern_allow([^HAVE_LIBSOCKET$])
+m4trace:configure.in:66: -1- m4_pattern_allow([^CPP$])
+m4trace:configure.in:66: -1- m4_pattern_allow([^CPPFLAGS$])
+m4trace:configure.in:66: -1- m4_pattern_allow([^CPP$])
+m4trace:configure.in:66: -1- m4_pattern_allow([^GREP$])
+m4trace:configure.in:66: -1- m4_pattern_allow([^GREP$])
+m4trace:configure.in:66: -1- m4_pattern_allow([^EGREP$])
+m4trace:configure.in:66: -1- m4_pattern_allow([^EGREP$])
+m4trace:configure.in:66: -1- m4_pattern_allow([^STDC_HEADERS$])
+m4trace:configure.in:71: -1- m4_pattern_allow([^WORDS_BIGENDIAN$])
+m4trace:configure.in:72: -1- m4_pattern_allow([^size_t$])
+m4trace:configure.in:73: -1- m4_pattern_allow([^TIME_WITH_SYS_TIME$])
+m4trace:configure.in:74: -1- m4_pattern_allow([^TM_IN_SYS_TIME$])
+m4trace:configure.in:75: -1- m4_pattern_allow([^uid_t$])
+m4trace:configure.in:75: -1- m4_pattern_allow([^gid_t$])
+m4trace:configure.in:76: -1- unet_CHECK_TYPE_SIZES
+m4trace:configure.in:76: -1- m4_pattern_allow([^SIZEOF_SHORT$])
+m4trace:configure.in:76: -1- m4_pattern_allow([^SIZEOF_INT$])
+m4trace:configure.in:76: -1- m4_pattern_allow([^SIZEOF_LONG$])
+m4trace:configure.in:76: -1- m4_pattern_allow([^SIZEOF_VOID_P$])
+m4trace:configure.in:76: -1- m4_pattern_allow([^SIZEOF_INT64_T$])
+m4trace:configure.in:76: -1- m4_pattern_allow([^SIZEOF_LONG_LONG$])
+m4trace:configure.in:76: -1- m4_pattern_allow([^int16_t$])
+m4trace:configure.in:76: -1- m4_pattern_allow([^uint16_t$])
+m4trace:configure.in:76: -1- m4_pattern_allow([^int16_t$])
+m4trace:configure.in:76: -1- m4_pattern_allow([^uint16_t$])
+m4trace:configure.in:76: -1- m4_pattern_allow([^int32_t$])
+m4trace:configure.in:76: -1- m4_pattern_allow([^uint32_t$])
+m4trace:configure.in:76: -1- m4_pattern_allow([^int32_t$])
+m4trace:configure.in:76: -1- m4_pattern_allow([^uint32_t$])
+m4trace:configure.in:76: -1- m4_pattern_allow([^int32_t$])
+m4trace:configure.in:76: -1- m4_pattern_allow([^uint32_t$])
+m4trace:configure.in:76: -1- m4_pattern_allow([^int64_t$])
+m4trace:configure.in:76: -1- m4_pattern_allow([^uint64_t$])
+m4trace:configure.in:83: -1- _m4_warn([obsolete], [The macro `AC_TRY_COMPILE' is obsolete.
+You should run autoupdate.], [../../lib/autoconf/general.m4:2367: AC_TRY_COMPILE is expanded from...
+../../lib/m4sugar/m4sh.m4:516: AS_IF is expanded from...
+../../lib/autoconf/general.m4:1898: AC_CACHE_VAL is expanded from...
+../../lib/m4sugar/m4sh.m4:516: AS_IF is expanded from...
+../../lib/autoconf/types.m4:232: AC_CHECK_TYPE is expanded from...
+configure.in:83: the top level])
+m4trace:configure.in:83: -1- m4_pattern_allow([^socklen_t$])
+m4trace:configure.in:114: -1- m4_pattern_allow([^AWK$])
+m4trace:configure.in:115: -1- m4_pattern_allow([^SET_MAKE$])
+m4trace:configure.in:116: -1- m4_pattern_allow([^INSTALL_PROGRAM$])
+m4trace:configure.in:116: -1- m4_pattern_allow([^INSTALL_SCRIPT$])
+m4trace:configure.in:116: -1- m4_pattern_allow([^INSTALL_DATA$])
+m4trace:configure.in:117: -1- m4_pattern_allow([^LN_S$])
+m4trace:configure.in:118: -1- m4_pattern_allow([^RMPROG$])
+m4trace:configure.in:119: -1- m4_pattern_allow([^SHPROG$])
+m4trace:configure.in:122: -1- m4_pattern_allow([^LEX$])
+m4trace:configure.in:122: -1- m4_pattern_allow([^LEX_OUTPUT_ROOT$])
+m4trace:configure.in:122: -1- m4_pattern_allow([^LEXLIB$])
+m4trace:configure.in:122: -1- m4_pattern_allow([^YYTEXT_POINTER$])
+m4trace:configure.in:133: -1- m4_pattern_allow([^YACC$])
+m4trace:configure.in:133: -1- m4_pattern_allow([^YACC$])
+m4trace:configure.in:133: -1- m4_pattern_allow([^YFLAGS$])
+m4trace:configure.in:145: -1- unet_NONBLOCKING
+m4trace:configure.in:145: -1- _m4_warn([obsolete], [The macro `AC_TRY_RUN' is obsolete.
+You should run autoupdate.], [../../lib/autoconf/general.m4:2478: AC_TRY_RUN is expanded from...
+../../lib/m4sugar/m4sh.m4:516: AS_IF is expanded from...
+../../lib/autoconf/general.m4:1898: AC_CACHE_VAL is expanded from...
+../../lib/autoconf/general.m4:1911: AC_CACHE_CHECK is expanded from...
+acinclude.m4:7: unet_NONBLOCKING is expanded from...
+configure.in:145: the top level])
+m4trace:configure.in:145: -1- _m4_warn([cross], [AC_RUN_IFELSE called without default to allow cross compiling], [../../lib/autoconf/general.m4:2462: AC_RUN_IFELSE is expanded from...
+../../lib/autoconf/general.m4:2478: AC_TRY_RUN is expanded from...
+../../lib/m4sugar/m4sh.m4:516: AS_IF is expanded from...
+../../lib/autoconf/general.m4:1898: AC_CACHE_VAL is expanded from...
+../../lib/autoconf/general.m4:1911: AC_CACHE_CHECK is expanded from...
+acinclude.m4:7: unet_NONBLOCKING is expanded from...
+configure.in:145: the top level])
+m4trace:configure.in:145: -1- m4_pattern_allow([^NBLOCK_POSIX$])
+m4trace:configure.in:145: -1- _m4_warn([obsolete], [The macro `AC_TRY_RUN' is obsolete.
+You should run autoupdate.], [../../lib/autoconf/general.m4:2478: AC_TRY_RUN is expanded from...
+../../lib/m4sugar/m4sh.m4:516: AS_IF is expanded from...
+../../lib/autoconf/general.m4:1898: AC_CACHE_VAL is expanded from...
+../../lib/autoconf/general.m4:1911: AC_CACHE_CHECK is expanded from...
+acinclude.m4:7: unet_NONBLOCKING is expanded from...
+configure.in:145: the top level])
+m4trace:configure.in:145: -1- _m4_warn([cross], [AC_RUN_IFELSE called without default to allow cross compiling], [../../lib/autoconf/general.m4:2462: AC_RUN_IFELSE is expanded from...
+../../lib/autoconf/general.m4:2478: AC_TRY_RUN is expanded from...
+../../lib/m4sugar/m4sh.m4:516: AS_IF is expanded from...
+../../lib/autoconf/general.m4:1898: AC_CACHE_VAL is expanded from...
+../../lib/autoconf/general.m4:1911: AC_CACHE_CHECK is expanded from...
+acinclude.m4:7: unet_NONBLOCKING is expanded from...
+configure.in:145: the top level])
+m4trace:configure.in:145: -1- m4_pattern_allow([^NBLOCK_BSD$])
+m4trace:configure.in:145: -1- m4_pattern_allow([^NBLOCK_SYSV$])
+m4trace:configure.in:146: -1- unet_SIGNALS
+m4trace:configure.in:146: -1- _m4_warn([obsolete], [The macro `AC_TRY_COMPILE' is obsolete.
+You should run autoupdate.], [../../lib/autoconf/general.m4:2367: AC_TRY_COMPILE is expanded from...
+../../lib/m4sugar/m4sh.m4:516: AS_IF is expanded from...
+../../lib/autoconf/general.m4:1898: AC_CACHE_VAL is expanded from...
+../../lib/autoconf/general.m4:1911: AC_CACHE_CHECK is expanded from...
+acinclude.m4:74: unet_SIGNALS is expanded from...
+configure.in:146: the top level])
+m4trace:configure.in:146: -1- m4_pattern_allow([^POSIX_SIGNALS$])
+m4trace:configure.in:146: -1- _m4_warn([obsolete], [The macro `AC_TRY_RUN' is obsolete.
+You should run autoupdate.], [../../lib/autoconf/general.m4:2478: AC_TRY_RUN is expanded from...
+../../lib/m4sugar/m4sh.m4:516: AS_IF is expanded from...
+../../lib/autoconf/general.m4:1898: AC_CACHE_VAL is expanded from...
+../../lib/autoconf/general.m4:1911: AC_CACHE_CHECK is expanded from...
+acinclude.m4:74: unet_SIGNALS is expanded from...
+configure.in:146: the top level])
+m4trace:configure.in:146: -1- _m4_warn([cross], [AC_RUN_IFELSE called without default to allow cross compiling], [../../lib/autoconf/general.m4:2462: AC_RUN_IFELSE is expanded from...
+../../lib/autoconf/general.m4:2478: AC_TRY_RUN is expanded from...
+../../lib/m4sugar/m4sh.m4:516: AS_IF is expanded from...
+../../lib/autoconf/general.m4:1898: AC_CACHE_VAL is expanded from...
+../../lib/autoconf/general.m4:1911: AC_CACHE_CHECK is expanded from...
+acinclude.m4:74: unet_SIGNALS is expanded from...
+configure.in:146: the top level])
+m4trace:configure.in:146: -1- m4_pattern_allow([^BSD_RELIABLE_SIGNALS$])
+m4trace:configure.in:146: -1- m4_pattern_allow([^SYSV_UNRELIABLE_SIGNALS$])
+m4trace:configure.in:163: -1- m4_pattern_allow([^IRCU_SOLARIS$])
+m4trace:configure.in:192: -1- m4_pattern_allow([^_DARWIN_C_SOURCE$])
+m4trace:configure.in:220: -1- m4_pattern_allow([^USE_POLL$])
+m4trace:configure.in:225: -1- m4_pattern_allow([^ENGINE_C$])
+m4trace:configure.in:237: -1- m4_pattern_allow([^DEBUGMODE$])
+m4trace:configure.in:264: -1- m4_pattern_allow([^IPV6$])
+m4trace:configure.in:277: -1- m4_pattern_allow([^NDEBUG$])
+m4trace:configure.in:330: -1- m4_pattern_allow([^FORCEINLINE$])
+m4trace:configure.in:348: -1- m4_pattern_allow([^USE_DEVPOLL$])
+m4trace:configure.in:367: -1- m4_pattern_allow([^USE_KQUEUE$])
+m4trace:configure.in:389: -1- m4_pattern_allow([^EPOLL_NEED_BODY$])
+m4trace:configure.in:393: -1- m4_pattern_allow([^USE_EPOLL$])
+m4trace:configure.in:404: -1- m4_pattern_allow([^HAVE_VA_COPY$])
+m4trace:configure.in:413: -1- m4_pattern_allow([^HAVE___VA_COPY$])
+m4trace:configure.in:438: -1- m4_pattern_allow([^INSTALL_RULE$])
+m4trace:configure.in:439: -1- m4_pattern_allow([^SYMLINK$])
+m4trace:configure.in:456: -1- m4_pattern_allow([^IRCDMODE$])
+m4trace:configure.in:476: -1- m4_pattern_allow([^IRCDOWN$])
+m4trace:configure.in:496: -1- m4_pattern_allow([^IRCDGRP$])
+m4trace:configure.in:522: -1- m4_pattern_allow([^DOMAINNAME$])
+m4trace:configure.in:592: -1- m4_pattern_allow([^SPATH$])
+m4trace:configure.in:621: -1- m4_pattern_allow([^DPATH$])
+m4trace:configure.in:624: -1- m4_pattern_allow([^DPATH$])
+m4trace:configure.in:655: -1- m4_pattern_allow([^CPATH$])
+m4trace:configure.in:688: -1- m4_pattern_allow([^LPATH$])
+m4trace:configure.in:714: -1- m4_pattern_allow([^MAXCONNECTIONS$])
+m4trace:configure.in:730: -1- m4_pattern_allow([^OLD_OGN_IRCU_COMPAT$])
+m4trace:configure.in:743: -1- m4_pattern_allow([^WITH_UNSTABLE_FEAT$])
+m4trace:configure.in:786: -1- m4_pattern_allow([^HAVE_GNUTLS$])
+m4trace:configure.in:791: -1- m4_pattern_allow([^HAVE_OPENSSL$])
+m4trace:configure.in:795: -1- _m4_warn([obsolete], [AC_OUTPUT should be used without arguments.
+You should run autoupdate.], [])
+m4trace:configure.in:795: -1- m4_pattern_allow([^LIB@&t@OBJS$])
+m4trace:configure.in:795: -1- m4_pattern_allow([^LTLIBOBJS$])
diff --git a/autom4te.cache/traces.1 b/autom4te.cache/traces.1
new file mode 100644 (file)
index 0000000..8cf838e
--- /dev/null
@@ -0,0 +1,699 @@
+m4trace:aclocal.m4:37: -1- m4_include([acinclude.m4])
+m4trace:configure.in:26: -1- AC_INIT([ircd/ircd.c])
+m4trace:configure.in:26: -1- m4_pattern_forbid([^_?A[CHUM]_])
+m4trace:configure.in:26: -1- m4_pattern_forbid([_AC_])
+m4trace:configure.in:26: -1- m4_pattern_forbid([^LIBOBJS$], [do not use LIBOBJS directly, use AC_LIBOBJ (see section `AC_LIBOBJ vs LIBOBJS'])
+m4trace:configure.in:26: -1- m4_pattern_allow([^AS_FLAGS$])
+m4trace:configure.in:26: -1- m4_pattern_forbid([^_?m4_])
+m4trace:configure.in:26: -1- m4_pattern_forbid([^dnl$])
+m4trace:configure.in:26: -1- m4_pattern_forbid([^_?AS_])
+m4trace:configure.in:26: -1- AC_SUBST([SHELL], [${CONFIG_SHELL-/bin/sh}])
+m4trace:configure.in:26: -1- AC_SUBST_TRACE([SHELL])
+m4trace:configure.in:26: -1- m4_pattern_allow([^SHELL$])
+m4trace:configure.in:26: -1- AC_SUBST([PATH_SEPARATOR])
+m4trace:configure.in:26: -1- AC_SUBST_TRACE([PATH_SEPARATOR])
+m4trace:configure.in:26: -1- m4_pattern_allow([^PATH_SEPARATOR$])
+m4trace:configure.in:26: -1- AC_SUBST([PACKAGE_NAME], [m4_ifdef([AC_PACKAGE_NAME],      ['AC_PACKAGE_NAME'])])
+m4trace:configure.in:26: -1- AC_SUBST_TRACE([PACKAGE_NAME])
+m4trace:configure.in:26: -1- m4_pattern_allow([^PACKAGE_NAME$])
+m4trace:configure.in:26: -1- AC_SUBST([PACKAGE_TARNAME], [m4_ifdef([AC_PACKAGE_TARNAME],   ['AC_PACKAGE_TARNAME'])])
+m4trace:configure.in:26: -1- AC_SUBST_TRACE([PACKAGE_TARNAME])
+m4trace:configure.in:26: -1- m4_pattern_allow([^PACKAGE_TARNAME$])
+m4trace:configure.in:26: -1- AC_SUBST([PACKAGE_VERSION], [m4_ifdef([AC_PACKAGE_VERSION],   ['AC_PACKAGE_VERSION'])])
+m4trace:configure.in:26: -1- AC_SUBST_TRACE([PACKAGE_VERSION])
+m4trace:configure.in:26: -1- m4_pattern_allow([^PACKAGE_VERSION$])
+m4trace:configure.in:26: -1- AC_SUBST([PACKAGE_STRING], [m4_ifdef([AC_PACKAGE_STRING],    ['AC_PACKAGE_STRING'])])
+m4trace:configure.in:26: -1- AC_SUBST_TRACE([PACKAGE_STRING])
+m4trace:configure.in:26: -1- m4_pattern_allow([^PACKAGE_STRING$])
+m4trace:configure.in:26: -1- AC_SUBST([PACKAGE_BUGREPORT], [m4_ifdef([AC_PACKAGE_BUGREPORT], ['AC_PACKAGE_BUGREPORT'])])
+m4trace:configure.in:26: -1- AC_SUBST_TRACE([PACKAGE_BUGREPORT])
+m4trace:configure.in:26: -1- m4_pattern_allow([^PACKAGE_BUGREPORT$])
+m4trace:configure.in:26: -1- AC_SUBST([exec_prefix], [NONE])
+m4trace:configure.in:26: -1- AC_SUBST_TRACE([exec_prefix])
+m4trace:configure.in:26: -1- m4_pattern_allow([^exec_prefix$])
+m4trace:configure.in:26: -1- AC_SUBST([prefix], [NONE])
+m4trace:configure.in:26: -1- AC_SUBST_TRACE([prefix])
+m4trace:configure.in:26: -1- m4_pattern_allow([^prefix$])
+m4trace:configure.in:26: -1- AC_SUBST([program_transform_name], [s,x,x,])
+m4trace:configure.in:26: -1- AC_SUBST_TRACE([program_transform_name])
+m4trace:configure.in:26: -1- m4_pattern_allow([^program_transform_name$])
+m4trace:configure.in:26: -1- AC_SUBST([bindir], ['${exec_prefix}/bin'])
+m4trace:configure.in:26: -1- AC_SUBST_TRACE([bindir])
+m4trace:configure.in:26: -1- m4_pattern_allow([^bindir$])
+m4trace:configure.in:26: -1- AC_SUBST([sbindir], ['${exec_prefix}/sbin'])
+m4trace:configure.in:26: -1- AC_SUBST_TRACE([sbindir])
+m4trace:configure.in:26: -1- m4_pattern_allow([^sbindir$])
+m4trace:configure.in:26: -1- AC_SUBST([libexecdir], ['${exec_prefix}/libexec'])
+m4trace:configure.in:26: -1- AC_SUBST_TRACE([libexecdir])
+m4trace:configure.in:26: -1- m4_pattern_allow([^libexecdir$])
+m4trace:configure.in:26: -1- AC_SUBST([datarootdir], ['${prefix}/share'])
+m4trace:configure.in:26: -1- AC_SUBST_TRACE([datarootdir])
+m4trace:configure.in:26: -1- m4_pattern_allow([^datarootdir$])
+m4trace:configure.in:26: -1- AC_SUBST([datadir], ['${datarootdir}'])
+m4trace:configure.in:26: -1- AC_SUBST_TRACE([datadir])
+m4trace:configure.in:26: -1- m4_pattern_allow([^datadir$])
+m4trace:configure.in:26: -1- AC_SUBST([sysconfdir], ['${prefix}/etc'])
+m4trace:configure.in:26: -1- AC_SUBST_TRACE([sysconfdir])
+m4trace:configure.in:26: -1- m4_pattern_allow([^sysconfdir$])
+m4trace:configure.in:26: -1- AC_SUBST([sharedstatedir], ['${prefix}/com'])
+m4trace:configure.in:26: -1- AC_SUBST_TRACE([sharedstatedir])
+m4trace:configure.in:26: -1- m4_pattern_allow([^sharedstatedir$])
+m4trace:configure.in:26: -1- AC_SUBST([localstatedir], ['${prefix}/var'])
+m4trace:configure.in:26: -1- AC_SUBST_TRACE([localstatedir])
+m4trace:configure.in:26: -1- m4_pattern_allow([^localstatedir$])
+m4trace:configure.in:26: -1- AC_SUBST([includedir], ['${prefix}/include'])
+m4trace:configure.in:26: -1- AC_SUBST_TRACE([includedir])
+m4trace:configure.in:26: -1- m4_pattern_allow([^includedir$])
+m4trace:configure.in:26: -1- AC_SUBST([oldincludedir], ['/usr/include'])
+m4trace:configure.in:26: -1- AC_SUBST_TRACE([oldincludedir])
+m4trace:configure.in:26: -1- m4_pattern_allow([^oldincludedir$])
+m4trace:configure.in:26: -1- AC_SUBST([docdir], [m4_ifset([AC_PACKAGE_TARNAME],
+                                    ['${datarootdir}/doc/${PACKAGE_TARNAME}'],
+                                    ['${datarootdir}/doc/${PACKAGE}'])])
+m4trace:configure.in:26: -1- AC_SUBST_TRACE([docdir])
+m4trace:configure.in:26: -1- m4_pattern_allow([^docdir$])
+m4trace:configure.in:26: -1- AC_SUBST([infodir], ['${datarootdir}/info'])
+m4trace:configure.in:26: -1- AC_SUBST_TRACE([infodir])
+m4trace:configure.in:26: -1- m4_pattern_allow([^infodir$])
+m4trace:configure.in:26: -1- AC_SUBST([htmldir], ['${docdir}'])
+m4trace:configure.in:26: -1- AC_SUBST_TRACE([htmldir])
+m4trace:configure.in:26: -1- m4_pattern_allow([^htmldir$])
+m4trace:configure.in:26: -1- AC_SUBST([dvidir], ['${docdir}'])
+m4trace:configure.in:26: -1- AC_SUBST_TRACE([dvidir])
+m4trace:configure.in:26: -1- m4_pattern_allow([^dvidir$])
+m4trace:configure.in:26: -1- AC_SUBST([pdfdir], ['${docdir}'])
+m4trace:configure.in:26: -1- AC_SUBST_TRACE([pdfdir])
+m4trace:configure.in:26: -1- m4_pattern_allow([^pdfdir$])
+m4trace:configure.in:26: -1- AC_SUBST([psdir], ['${docdir}'])
+m4trace:configure.in:26: -1- AC_SUBST_TRACE([psdir])
+m4trace:configure.in:26: -1- m4_pattern_allow([^psdir$])
+m4trace:configure.in:26: -1- AC_SUBST([libdir], ['${exec_prefix}/lib'])
+m4trace:configure.in:26: -1- AC_SUBST_TRACE([libdir])
+m4trace:configure.in:26: -1- m4_pattern_allow([^libdir$])
+m4trace:configure.in:26: -1- AC_SUBST([localedir], ['${datarootdir}/locale'])
+m4trace:configure.in:26: -1- AC_SUBST_TRACE([localedir])
+m4trace:configure.in:26: -1- m4_pattern_allow([^localedir$])
+m4trace:configure.in:26: -1- AC_SUBST([mandir], ['${datarootdir}/man'])
+m4trace:configure.in:26: -1- AC_SUBST_TRACE([mandir])
+m4trace:configure.in:26: -1- m4_pattern_allow([^mandir$])
+m4trace:configure.in:26: -1- AC_DEFINE_TRACE_LITERAL([PACKAGE_NAME])
+m4trace:configure.in:26: -1- m4_pattern_allow([^PACKAGE_NAME$])
+m4trace:configure.in:26: -1- AH_OUTPUT([PACKAGE_NAME], [/* Define to the full name of this package. */
+#undef PACKAGE_NAME])
+m4trace:configure.in:26: -1- AC_DEFINE_TRACE_LITERAL([PACKAGE_TARNAME])
+m4trace:configure.in:26: -1- m4_pattern_allow([^PACKAGE_TARNAME$])
+m4trace:configure.in:26: -1- AH_OUTPUT([PACKAGE_TARNAME], [/* Define to the one symbol short name of this package. */
+#undef PACKAGE_TARNAME])
+m4trace:configure.in:26: -1- AC_DEFINE_TRACE_LITERAL([PACKAGE_VERSION])
+m4trace:configure.in:26: -1- m4_pattern_allow([^PACKAGE_VERSION$])
+m4trace:configure.in:26: -1- AH_OUTPUT([PACKAGE_VERSION], [/* Define to the version of this package. */
+#undef PACKAGE_VERSION])
+m4trace:configure.in:26: -1- AC_DEFINE_TRACE_LITERAL([PACKAGE_STRING])
+m4trace:configure.in:26: -1- m4_pattern_allow([^PACKAGE_STRING$])
+m4trace:configure.in:26: -1- AH_OUTPUT([PACKAGE_STRING], [/* Define to the full name and version of this package. */
+#undef PACKAGE_STRING])
+m4trace:configure.in:26: -1- AC_DEFINE_TRACE_LITERAL([PACKAGE_BUGREPORT])
+m4trace:configure.in:26: -1- m4_pattern_allow([^PACKAGE_BUGREPORT$])
+m4trace:configure.in:26: -1- AH_OUTPUT([PACKAGE_BUGREPORT], [/* Define to the address where bug reports for this package should be sent. */
+#undef PACKAGE_BUGREPORT])
+m4trace:configure.in:26: -1- AC_SUBST([DEFS])
+m4trace:configure.in:26: -1- AC_SUBST_TRACE([DEFS])
+m4trace:configure.in:26: -1- m4_pattern_allow([^DEFS$])
+m4trace:configure.in:26: -1- AC_SUBST([ECHO_C])
+m4trace:configure.in:26: -1- AC_SUBST_TRACE([ECHO_C])
+m4trace:configure.in:26: -1- m4_pattern_allow([^ECHO_C$])
+m4trace:configure.in:26: -1- AC_SUBST([ECHO_N])
+m4trace:configure.in:26: -1- AC_SUBST_TRACE([ECHO_N])
+m4trace:configure.in:26: -1- m4_pattern_allow([^ECHO_N$])
+m4trace:configure.in:26: -1- AC_SUBST([ECHO_T])
+m4trace:configure.in:26: -1- AC_SUBST_TRACE([ECHO_T])
+m4trace:configure.in:26: -1- m4_pattern_allow([^ECHO_T$])
+m4trace:configure.in:26: -1- AC_SUBST([LIBS])
+m4trace:configure.in:26: -1- AC_SUBST_TRACE([LIBS])
+m4trace:configure.in:26: -1- m4_pattern_allow([^LIBS$])
+m4trace:configure.in:26: -1- AC_SUBST([build_alias])
+m4trace:configure.in:26: -1- AC_SUBST_TRACE([build_alias])
+m4trace:configure.in:26: -1- m4_pattern_allow([^build_alias$])
+m4trace:configure.in:26: -1- AC_SUBST([host_alias])
+m4trace:configure.in:26: -1- AC_SUBST_TRACE([host_alias])
+m4trace:configure.in:26: -1- m4_pattern_allow([^host_alias$])
+m4trace:configure.in:26: -1- AC_SUBST([target_alias])
+m4trace:configure.in:26: -1- AC_SUBST_TRACE([target_alias])
+m4trace:configure.in:26: -1- m4_pattern_allow([^target_alias$])
+m4trace:configure.in:42: -1- AC_CONFIG_HEADERS([config.h])
+m4trace:configure.in:48: -1- AC_CANONICAL_HOST
+m4trace:configure.in:48: -1- AC_CANONICAL_BUILD
+m4trace:configure.in:48: -1- AC_REQUIRE_AUX_FILE([config.sub])
+m4trace:configure.in:48: -1- AC_REQUIRE_AUX_FILE([config.guess])
+m4trace:configure.in:48: -1- AC_SUBST([build], [$ac_cv_build])
+m4trace:configure.in:48: -1- AC_SUBST_TRACE([build])
+m4trace:configure.in:48: -1- m4_pattern_allow([^build$])
+m4trace:configure.in:48: -1- AC_SUBST([build_cpu], [$[1]])
+m4trace:configure.in:48: -1- AC_SUBST_TRACE([build_cpu])
+m4trace:configure.in:48: -1- m4_pattern_allow([^build_cpu$])
+m4trace:configure.in:48: -1- AC_SUBST([build_vendor], [$[2]])
+m4trace:configure.in:48: -1- AC_SUBST_TRACE([build_vendor])
+m4trace:configure.in:48: -1- m4_pattern_allow([^build_vendor$])
+m4trace:configure.in:48: -1- AC_SUBST([build_os])
+m4trace:configure.in:48: -1- AC_SUBST_TRACE([build_os])
+m4trace:configure.in:48: -1- m4_pattern_allow([^build_os$])
+m4trace:configure.in:48: -1- AC_SUBST([host], [$ac_cv_host])
+m4trace:configure.in:48: -1- AC_SUBST_TRACE([host])
+m4trace:configure.in:48: -1- m4_pattern_allow([^host$])
+m4trace:configure.in:48: -1- AC_SUBST([host_cpu], [$[1]])
+m4trace:configure.in:48: -1- AC_SUBST_TRACE([host_cpu])
+m4trace:configure.in:48: -1- m4_pattern_allow([^host_cpu$])
+m4trace:configure.in:48: -1- AC_SUBST([host_vendor], [$[2]])
+m4trace:configure.in:48: -1- AC_SUBST_TRACE([host_vendor])
+m4trace:configure.in:48: -1- m4_pattern_allow([^host_vendor$])
+m4trace:configure.in:48: -1- AC_SUBST([host_os])
+m4trace:configure.in:48: -1- AC_SUBST_TRACE([host_os])
+m4trace:configure.in:48: -1- m4_pattern_allow([^host_os$])
+m4trace:configure.in:51: -1- AC_SUBST([CC])
+m4trace:configure.in:51: -1- AC_SUBST_TRACE([CC])
+m4trace:configure.in:51: -1- m4_pattern_allow([^CC$])
+m4trace:configure.in:51: -1- AC_SUBST([CFLAGS])
+m4trace:configure.in:51: -1- AC_SUBST_TRACE([CFLAGS])
+m4trace:configure.in:51: -1- m4_pattern_allow([^CFLAGS$])
+m4trace:configure.in:51: -1- AC_SUBST([LDFLAGS])
+m4trace:configure.in:51: -1- AC_SUBST_TRACE([LDFLAGS])
+m4trace:configure.in:51: -1- m4_pattern_allow([^LDFLAGS$])
+m4trace:configure.in:51: -1- AC_SUBST([LIBS])
+m4trace:configure.in:51: -1- AC_SUBST_TRACE([LIBS])
+m4trace:configure.in:51: -1- m4_pattern_allow([^LIBS$])
+m4trace:configure.in:51: -1- AC_SUBST([CPPFLAGS])
+m4trace:configure.in:51: -1- AC_SUBST_TRACE([CPPFLAGS])
+m4trace:configure.in:51: -1- m4_pattern_allow([^CPPFLAGS$])
+m4trace:configure.in:51: -1- AC_SUBST([CC])
+m4trace:configure.in:51: -1- AC_SUBST_TRACE([CC])
+m4trace:configure.in:51: -1- m4_pattern_allow([^CC$])
+m4trace:configure.in:51: -1- AC_SUBST([CC])
+m4trace:configure.in:51: -1- AC_SUBST_TRACE([CC])
+m4trace:configure.in:51: -1- m4_pattern_allow([^CC$])
+m4trace:configure.in:51: -1- AC_SUBST([CC])
+m4trace:configure.in:51: -1- AC_SUBST_TRACE([CC])
+m4trace:configure.in:51: -1- m4_pattern_allow([^CC$])
+m4trace:configure.in:51: -1- AC_SUBST([CC])
+m4trace:configure.in:51: -1- AC_SUBST_TRACE([CC])
+m4trace:configure.in:51: -1- m4_pattern_allow([^CC$])
+m4trace:configure.in:51: -1- AC_SUBST([ac_ct_CC])
+m4trace:configure.in:51: -1- AC_SUBST_TRACE([ac_ct_CC])
+m4trace:configure.in:51: -1- m4_pattern_allow([^ac_ct_CC$])
+m4trace:configure.in:51: -1- AC_SUBST([EXEEXT], [$ac_cv_exeext])
+m4trace:configure.in:51: -1- AC_SUBST_TRACE([EXEEXT])
+m4trace:configure.in:51: -1- m4_pattern_allow([^EXEEXT$])
+m4trace:configure.in:51: -1- AC_SUBST([OBJEXT], [$ac_cv_objext])
+m4trace:configure.in:51: -1- AC_SUBST_TRACE([OBJEXT])
+m4trace:configure.in:51: -1- m4_pattern_allow([^OBJEXT$])
+m4trace:configure.in:54: -1- _m4_warn([obsolete], [The macro `AM_PROG_CC_STDC' is obsolete.
+You should run autoupdate.], [aclocal.m4:26: AM_PROG_CC_STDC is expanded from...
+configure.in:54: the top level])
+m4trace:configure.in:54: -1- AC_SUBST([CC])
+m4trace:configure.in:54: -1- AC_SUBST_TRACE([CC])
+m4trace:configure.in:54: -1- m4_pattern_allow([^CC$])
+m4trace:configure.in:54: -1- AC_SUBST([CFLAGS])
+m4trace:configure.in:54: -1- AC_SUBST_TRACE([CFLAGS])
+m4trace:configure.in:54: -1- m4_pattern_allow([^CFLAGS$])
+m4trace:configure.in:54: -1- AC_SUBST([LDFLAGS])
+m4trace:configure.in:54: -1- AC_SUBST_TRACE([LDFLAGS])
+m4trace:configure.in:54: -1- m4_pattern_allow([^LDFLAGS$])
+m4trace:configure.in:54: -1- AC_SUBST([LIBS])
+m4trace:configure.in:54: -1- AC_SUBST_TRACE([LIBS])
+m4trace:configure.in:54: -1- m4_pattern_allow([^LIBS$])
+m4trace:configure.in:54: -1- AC_SUBST([CPPFLAGS])
+m4trace:configure.in:54: -1- AC_SUBST_TRACE([CPPFLAGS])
+m4trace:configure.in:54: -1- m4_pattern_allow([^CPPFLAGS$])
+m4trace:configure.in:54: -1- AC_SUBST([CC])
+m4trace:configure.in:54: -1- AC_SUBST_TRACE([CC])
+m4trace:configure.in:54: -1- m4_pattern_allow([^CC$])
+m4trace:configure.in:54: -1- AC_SUBST([CC])
+m4trace:configure.in:54: -1- AC_SUBST_TRACE([CC])
+m4trace:configure.in:54: -1- m4_pattern_allow([^CC$])
+m4trace:configure.in:54: -1- AC_SUBST([CC])
+m4trace:configure.in:54: -1- AC_SUBST_TRACE([CC])
+m4trace:configure.in:54: -1- m4_pattern_allow([^CC$])
+m4trace:configure.in:54: -1- AC_SUBST([CC])
+m4trace:configure.in:54: -1- AC_SUBST_TRACE([CC])
+m4trace:configure.in:54: -1- m4_pattern_allow([^CC$])
+m4trace:configure.in:54: -1- AC_SUBST([ac_ct_CC])
+m4trace:configure.in:54: -1- AC_SUBST_TRACE([ac_ct_CC])
+m4trace:configure.in:54: -1- m4_pattern_allow([^ac_ct_CC$])
+m4trace:configure.in:54: -1- _m4_warn([obsolete], [AM_PROG_CC_STDC:
+       your code should no longer depend upon `am_cv_prog_cc_stdc', but upon
+       `ac_cv_prog_cc_stdc'.  Remove this warning and the assignment when
+       you adjust the code.  You can also remove the above call to
+       AC_PROG_CC if you already called it elsewhere.], [aclocal.m4:26: AM_PROG_CC_STDC is expanded from...
+configure.in:54: the top level])
+m4trace:configure.in:63: -5- AH_OUTPUT([HAVE_LIBRESOLV], [/* Define to 1 if you have the `resolv\' library (-lresolv). */
+#undef HAVE_LIBRESOLV])
+m4trace:configure.in:63: -5- AC_DEFINE_TRACE_LITERAL([HAVE_LIBRESOLV])
+m4trace:configure.in:63: -5- m4_pattern_allow([^HAVE_LIBRESOLV$])
+m4trace:configure.in:63: -3- AH_OUTPUT([HAVE_LIBSOCKET], [/* Define to 1 if you have the `socket\' library (-lsocket). */
+#undef HAVE_LIBSOCKET])
+m4trace:configure.in:63: -3- AC_DEFINE_TRACE_LITERAL([HAVE_LIBSOCKET])
+m4trace:configure.in:63: -3- m4_pattern_allow([^HAVE_LIBSOCKET$])
+m4trace:configure.in:63: -2- AH_OUTPUT([HAVE_LIBNSL], [/* Define to 1 if you have the `nsl\' library (-lnsl). */
+#undef HAVE_LIBNSL])
+m4trace:configure.in:63: -2- AC_DEFINE_TRACE_LITERAL([HAVE_LIBNSL])
+m4trace:configure.in:63: -2- m4_pattern_allow([^HAVE_LIBNSL$])
+m4trace:configure.in:63: -2- AH_OUTPUT([HAVE_LIBSOCKET], [/* Define to 1 if you have the `socket\' library (-lsocket). */
+#undef HAVE_LIBSOCKET])
+m4trace:configure.in:63: -2- AC_DEFINE_TRACE_LITERAL([HAVE_LIBSOCKET])
+m4trace:configure.in:63: -2- m4_pattern_allow([^HAVE_LIBSOCKET$])
+m4trace:configure.in:66: -1- AC_SUBST([CPP])
+m4trace:configure.in:66: -1- AC_SUBST_TRACE([CPP])
+m4trace:configure.in:66: -1- m4_pattern_allow([^CPP$])
+m4trace:configure.in:66: -1- AC_SUBST([CPPFLAGS])
+m4trace:configure.in:66: -1- AC_SUBST_TRACE([CPPFLAGS])
+m4trace:configure.in:66: -1- m4_pattern_allow([^CPPFLAGS$])
+m4trace:configure.in:66: -1- AC_SUBST([CPP])
+m4trace:configure.in:66: -1- AC_SUBST_TRACE([CPP])
+m4trace:configure.in:66: -1- m4_pattern_allow([^CPP$])
+m4trace:configure.in:66: -1- AC_SUBST([GREP])
+m4trace:configure.in:66: -1- AC_SUBST_TRACE([GREP])
+m4trace:configure.in:66: -1- m4_pattern_allow([^GREP$])
+m4trace:configure.in:66: -1- AC_SUBST([GREP])
+m4trace:configure.in:66: -1- AC_SUBST_TRACE([GREP])
+m4trace:configure.in:66: -1- m4_pattern_allow([^GREP$])
+m4trace:configure.in:66: -1- AC_SUBST([EGREP])
+m4trace:configure.in:66: -1- AC_SUBST_TRACE([EGREP])
+m4trace:configure.in:66: -1- m4_pattern_allow([^EGREP$])
+m4trace:configure.in:66: -1- AC_SUBST([EGREP])
+m4trace:configure.in:66: -1- AC_SUBST_TRACE([EGREP])
+m4trace:configure.in:66: -1- m4_pattern_allow([^EGREP$])
+m4trace:configure.in:66: -1- AC_DEFINE_TRACE_LITERAL([STDC_HEADERS])
+m4trace:configure.in:66: -1- m4_pattern_allow([^STDC_HEADERS$])
+m4trace:configure.in:66: -1- AH_OUTPUT([STDC_HEADERS], [/* Define to 1 if you have the ANSI C header files. */
+#undef STDC_HEADERS])
+m4trace:configure.in:67: -1- AH_OUTPUT([HAVE_CRYPT_H], [/* Define to 1 if you have the <crypt.h> header file. */
+#undef HAVE_CRYPT_H])
+m4trace:configure.in:67: -1- AH_OUTPUT([HAVE_POLL_H], [/* Define to 1 if you have the <poll.h> header file. */
+#undef HAVE_POLL_H])
+m4trace:configure.in:67: -1- AH_OUTPUT([HAVE_INTTYPES_H], [/* Define to 1 if you have the <inttypes.h> header file. */
+#undef HAVE_INTTYPES_H])
+m4trace:configure.in:67: -1- AH_OUTPUT([HAVE_STDINT_H], [/* Define to 1 if you have the <stdint.h> header file. */
+#undef HAVE_STDINT_H])
+m4trace:configure.in:67: -1- AH_OUTPUT([HAVE_SYS_DEVPOLL_H], [/* Define to 1 if you have the <sys/devpoll.h> header file. */
+#undef HAVE_SYS_DEVPOLL_H])
+m4trace:configure.in:67: -1- AH_OUTPUT([HAVE_SYS_EPOLL_H], [/* Define to 1 if you have the <sys/epoll.h> header file. */
+#undef HAVE_SYS_EPOLL_H])
+m4trace:configure.in:67: -1- AH_OUTPUT([HAVE_SYS_EVENT_H], [/* Define to 1 if you have the <sys/event.h> header file. */
+#undef HAVE_SYS_EVENT_H])
+m4trace:configure.in:67: -1- AH_OUTPUT([HAVE_SYS_PARAM_H], [/* Define to 1 if you have the <sys/param.h> header file. */
+#undef HAVE_SYS_PARAM_H])
+m4trace:configure.in:67: -1- AH_OUTPUT([HAVE_SYS_RESOURCE_H], [/* Define to 1 if you have the <sys/resource.h> header file. */
+#undef HAVE_SYS_RESOURCE_H])
+m4trace:configure.in:67: -1- AH_OUTPUT([HAVE_SYS_SOCKET_H], [/* Define to 1 if you have the <sys/socket.h> header file. */
+#undef HAVE_SYS_SOCKET_H])
+m4trace:configure.in:67: -1- AH_OUTPUT([HAVE_SYS_TYPES_H], [/* Define to 1 if you have the <sys/types.h> header file. */
+#undef HAVE_SYS_TYPES_H])
+m4trace:configure.in:67: -1- AH_OUTPUT([HAVE_SYS_STAT_H], [/* Define to 1 if you have the <sys/stat.h> header file. */
+#undef HAVE_SYS_STAT_H])
+m4trace:configure.in:67: -1- AH_OUTPUT([HAVE_STDLIB_H], [/* Define to 1 if you have the <stdlib.h> header file. */
+#undef HAVE_STDLIB_H])
+m4trace:configure.in:67: -1- AH_OUTPUT([HAVE_STRING_H], [/* Define to 1 if you have the <string.h> header file. */
+#undef HAVE_STRING_H])
+m4trace:configure.in:67: -1- AH_OUTPUT([HAVE_MEMORY_H], [/* Define to 1 if you have the <memory.h> header file. */
+#undef HAVE_MEMORY_H])
+m4trace:configure.in:67: -1- AH_OUTPUT([HAVE_STRINGS_H], [/* Define to 1 if you have the <strings.h> header file. */
+#undef HAVE_STRINGS_H])
+m4trace:configure.in:67: -1- AH_OUTPUT([HAVE_INTTYPES_H], [/* Define to 1 if you have the <inttypes.h> header file. */
+#undef HAVE_INTTYPES_H])
+m4trace:configure.in:67: -1- AH_OUTPUT([HAVE_STDINT_H], [/* Define to 1 if you have the <stdint.h> header file. */
+#undef HAVE_STDINT_H])
+m4trace:configure.in:67: -1- AH_OUTPUT([HAVE_UNISTD_H], [/* Define to 1 if you have the <unistd.h> header file. */
+#undef HAVE_UNISTD_H])
+m4trace:configure.in:71: -1- AC_DEFINE_TRACE_LITERAL([WORDS_BIGENDIAN])
+m4trace:configure.in:71: -1- m4_pattern_allow([^WORDS_BIGENDIAN$])
+m4trace:configure.in:71: -1- AH_OUTPUT([WORDS_BIGENDIAN], [/* Define to 1 if your processor stores words with the most significant byte
+   first (like Motorola and SPARC, unlike Intel and VAX). */
+#undef WORDS_BIGENDIAN])
+m4trace:configure.in:72: -1- AC_DEFINE_TRACE_LITERAL([size_t])
+m4trace:configure.in:72: -1- m4_pattern_allow([^size_t$])
+m4trace:configure.in:72: -1- AH_OUTPUT([size_t], [/* Define to `unsigned int\' if <sys/types.h> does not define. */
+#undef size_t])
+m4trace:configure.in:73: -1- AC_DEFINE_TRACE_LITERAL([TIME_WITH_SYS_TIME])
+m4trace:configure.in:73: -1- m4_pattern_allow([^TIME_WITH_SYS_TIME$])
+m4trace:configure.in:73: -1- AH_OUTPUT([TIME_WITH_SYS_TIME], [/* Define to 1 if you can safely include both <sys/time.h> and <time.h>. */
+#undef TIME_WITH_SYS_TIME])
+m4trace:configure.in:74: -1- AC_DEFINE_TRACE_LITERAL([TM_IN_SYS_TIME])
+m4trace:configure.in:74: -1- m4_pattern_allow([^TM_IN_SYS_TIME$])
+m4trace:configure.in:74: -1- AH_OUTPUT([TM_IN_SYS_TIME], [/* Define to 1 if your <sys/time.h> declares `struct tm\'. */
+#undef TM_IN_SYS_TIME])
+m4trace:configure.in:75: -1- AC_DEFINE_TRACE_LITERAL([uid_t])
+m4trace:configure.in:75: -1- m4_pattern_allow([^uid_t$])
+m4trace:configure.in:75: -1- AH_OUTPUT([uid_t], [/* Define to `int\' if <sys/types.h> doesn\'t define. */
+#undef uid_t])
+m4trace:configure.in:75: -1- AC_DEFINE_TRACE_LITERAL([gid_t])
+m4trace:configure.in:75: -1- m4_pattern_allow([^gid_t$])
+m4trace:configure.in:75: -1- AH_OUTPUT([gid_t], [/* Define to `int\' if <sys/types.h> doesn\'t define. */
+#undef gid_t])
+m4trace:configure.in:76: -1- AC_DEFINE_TRACE_LITERAL([SIZEOF_SHORT])
+m4trace:configure.in:76: -1- m4_pattern_allow([^SIZEOF_SHORT$])
+m4trace:configure.in:76: -1- AH_OUTPUT([SIZEOF_SHORT], [/* The size of `short\', as computed by sizeof. */
+#undef SIZEOF_SHORT])
+m4trace:configure.in:76: -1- AC_DEFINE_TRACE_LITERAL([SIZEOF_INT])
+m4trace:configure.in:76: -1- m4_pattern_allow([^SIZEOF_INT$])
+m4trace:configure.in:76: -1- AH_OUTPUT([SIZEOF_INT], [/* The size of `int\', as computed by sizeof. */
+#undef SIZEOF_INT])
+m4trace:configure.in:76: -1- AC_DEFINE_TRACE_LITERAL([SIZEOF_LONG])
+m4trace:configure.in:76: -1- m4_pattern_allow([^SIZEOF_LONG$])
+m4trace:configure.in:76: -1- AH_OUTPUT([SIZEOF_LONG], [/* The size of `long\', as computed by sizeof. */
+#undef SIZEOF_LONG])
+m4trace:configure.in:76: -1- AC_DEFINE_TRACE_LITERAL([SIZEOF_VOID_P])
+m4trace:configure.in:76: -1- m4_pattern_allow([^SIZEOF_VOID_P$])
+m4trace:configure.in:76: -1- AH_OUTPUT([SIZEOF_VOID_P], [/* The size of `void *\', as computed by sizeof. */
+#undef SIZEOF_VOID_P])
+m4trace:configure.in:76: -1- AC_DEFINE_TRACE_LITERAL([SIZEOF_INT64_T])
+m4trace:configure.in:76: -1- m4_pattern_allow([^SIZEOF_INT64_T$])
+m4trace:configure.in:76: -1- AH_OUTPUT([SIZEOF_INT64_T], [/* The size of `int64_t\', as computed by sizeof. */
+#undef SIZEOF_INT64_T])
+m4trace:configure.in:76: -1- AC_DEFINE_TRACE_LITERAL([SIZEOF_LONG_LONG])
+m4trace:configure.in:76: -1- m4_pattern_allow([^SIZEOF_LONG_LONG$])
+m4trace:configure.in:76: -1- AH_OUTPUT([SIZEOF_LONG_LONG], [/* The size of `long long\', as computed by sizeof. */
+#undef SIZEOF_LONG_LONG])
+m4trace:configure.in:76: -1- AC_DEFINE_TRACE_LITERAL([int16_t])
+m4trace:configure.in:76: -1- m4_pattern_allow([^int16_t$])
+m4trace:configure.in:76: -1- AH_OUTPUT([int16_t], [/* Define to `int\' if <sys/types.h> does not define. */
+#undef int16_t])
+m4trace:configure.in:76: -1- AC_DEFINE_TRACE_LITERAL([uint16_t])
+m4trace:configure.in:76: -1- m4_pattern_allow([^uint16_t$])
+m4trace:configure.in:76: -1- AH_OUTPUT([uint16_t], [/* Define to `unsigned int\' if <sys/types.h> does not define. */
+#undef uint16_t])
+m4trace:configure.in:76: -1- AC_DEFINE_TRACE_LITERAL([int16_t])
+m4trace:configure.in:76: -1- m4_pattern_allow([^int16_t$])
+m4trace:configure.in:76: -1- AH_OUTPUT([int16_t], [/* Define to `short\' if <sys/types.h> does not define. */
+#undef int16_t])
+m4trace:configure.in:76: -1- AC_DEFINE_TRACE_LITERAL([uint16_t])
+m4trace:configure.in:76: -1- m4_pattern_allow([^uint16_t$])
+m4trace:configure.in:76: -1- AH_OUTPUT([uint16_t], [/* Define to `unsigned short\' if <sys/types.h> does not define. */
+#undef uint16_t])
+m4trace:configure.in:76: -1- AC_DEFINE_TRACE_LITERAL([int32_t])
+m4trace:configure.in:76: -1- m4_pattern_allow([^int32_t$])
+m4trace:configure.in:76: -1- AH_OUTPUT([int32_t], [/* Define to `int\' if <sys/types.h> does not define. */
+#undef int32_t])
+m4trace:configure.in:76: -1- AC_DEFINE_TRACE_LITERAL([uint32_t])
+m4trace:configure.in:76: -1- m4_pattern_allow([^uint32_t$])
+m4trace:configure.in:76: -1- AH_OUTPUT([uint32_t], [/* Define to `unsigned int\' if <sys/types.h> does not define. */
+#undef uint32_t])
+m4trace:configure.in:76: -1- AC_DEFINE_TRACE_LITERAL([int32_t])
+m4trace:configure.in:76: -1- m4_pattern_allow([^int32_t$])
+m4trace:configure.in:76: -1- AH_OUTPUT([int32_t], [/* Define to `short\' if <sys/types.h> does not define. */
+#undef int32_t])
+m4trace:configure.in:76: -1- AC_DEFINE_TRACE_LITERAL([uint32_t])
+m4trace:configure.in:76: -1- m4_pattern_allow([^uint32_t$])
+m4trace:configure.in:76: -1- AH_OUTPUT([uint32_t], [/* Define to `unsigned short\' if <sys/types.h> does not define. */
+#undef uint32_t])
+m4trace:configure.in:76: -1- AC_DEFINE_TRACE_LITERAL([int32_t])
+m4trace:configure.in:76: -1- m4_pattern_allow([^int32_t$])
+m4trace:configure.in:76: -1- AH_OUTPUT([int32_t], [/* Define to `long\' if <sys/types.h> does not define. */
+#undef int32_t])
+m4trace:configure.in:76: -1- AC_DEFINE_TRACE_LITERAL([uint32_t])
+m4trace:configure.in:76: -1- m4_pattern_allow([^uint32_t$])
+m4trace:configure.in:76: -1- AH_OUTPUT([uint32_t], [/* Define to `unsigned long\' if <sys/types.h> does not define. */
+#undef uint32_t])
+m4trace:configure.in:76: -1- AC_DEFINE_TRACE_LITERAL([int64_t])
+m4trace:configure.in:76: -1- m4_pattern_allow([^int64_t$])
+m4trace:configure.in:76: -1- AH_OUTPUT([int64_t], [/* Define to `long long\' if <sys/types.h> does not define. */
+#undef int64_t])
+m4trace:configure.in:76: -1- AC_DEFINE_TRACE_LITERAL([uint64_t])
+m4trace:configure.in:76: -1- m4_pattern_allow([^uint64_t$])
+m4trace:configure.in:76: -1- AH_OUTPUT([uint64_t], [/* Define to `unsigned long long\' if <sys/types.h> does not define. */
+#undef uint64_t])
+m4trace:configure.in:83: -1- _m4_warn([obsolete], [The macro `AC_TRY_COMPILE' is obsolete.
+You should run autoupdate.], [../../lib/autoconf/general.m4:2367: AC_TRY_COMPILE is expanded from...
+../../lib/m4sugar/m4sh.m4:516: AS_IF is expanded from...
+../../lib/autoconf/general.m4:1898: AC_CACHE_VAL is expanded from...
+../../lib/m4sugar/m4sh.m4:516: AS_IF is expanded from...
+../../lib/autoconf/types.m4:232: AC_CHECK_TYPE is expanded from...
+configure.in:83: the top level])
+m4trace:configure.in:83: -1- AC_DEFINE_TRACE_LITERAL([socklen_t])
+m4trace:configure.in:83: -1- m4_pattern_allow([^socklen_t$])
+m4trace:configure.in:83: -1- AH_OUTPUT([socklen_t], [/* type to use in place of socklen_t if not defined */
+#undef socklen_t])
+m4trace:configure.in:107: -1- AH_OUTPUT([HAVE_KQUEUE], [/* Define to 1 if you have the `kqueue\' function. */
+#undef HAVE_KQUEUE])
+m4trace:configure.in:107: -1- AH_OUTPUT([HAVE_SETRLIMIT], [/* Define to 1 if you have the `setrlimit\' function. */
+#undef HAVE_SETRLIMIT])
+m4trace:configure.in:107: -1- AH_OUTPUT([HAVE_GETRUSAGE], [/* Define to 1 if you have the `getrusage\' function. */
+#undef HAVE_GETRUSAGE])
+m4trace:configure.in:107: -1- AH_OUTPUT([HAVE_TIMES], [/* Define to 1 if you have the `times\' function. */
+#undef HAVE_TIMES])
+m4trace:configure.in:114: -1- AC_SUBST([AWK])
+m4trace:configure.in:114: -1- AC_SUBST_TRACE([AWK])
+m4trace:configure.in:114: -1- m4_pattern_allow([^AWK$])
+m4trace:configure.in:115: -1- AC_SUBST([SET_MAKE])
+m4trace:configure.in:115: -1- AC_SUBST_TRACE([SET_MAKE])
+m4trace:configure.in:115: -1- m4_pattern_allow([^SET_MAKE$])
+m4trace:configure.in:116: -1- AC_REQUIRE_AUX_FILE([install-sh])
+m4trace:configure.in:116: -1- AC_SUBST([INSTALL_PROGRAM])
+m4trace:configure.in:116: -1- AC_SUBST_TRACE([INSTALL_PROGRAM])
+m4trace:configure.in:116: -1- m4_pattern_allow([^INSTALL_PROGRAM$])
+m4trace:configure.in:116: -1- AC_SUBST([INSTALL_SCRIPT])
+m4trace:configure.in:116: -1- AC_SUBST_TRACE([INSTALL_SCRIPT])
+m4trace:configure.in:116: -1- m4_pattern_allow([^INSTALL_SCRIPT$])
+m4trace:configure.in:116: -1- AC_SUBST([INSTALL_DATA])
+m4trace:configure.in:116: -1- AC_SUBST_TRACE([INSTALL_DATA])
+m4trace:configure.in:116: -1- m4_pattern_allow([^INSTALL_DATA$])
+m4trace:configure.in:117: -1- AC_SUBST([LN_S], [$as_ln_s])
+m4trace:configure.in:117: -1- AC_SUBST_TRACE([LN_S])
+m4trace:configure.in:117: -1- m4_pattern_allow([^LN_S$])
+m4trace:configure.in:118: -1- AC_SUBST([RMPROG])
+m4trace:configure.in:118: -1- AC_SUBST_TRACE([RMPROG])
+m4trace:configure.in:118: -1- m4_pattern_allow([^RMPROG$])
+m4trace:configure.in:119: -1- AC_SUBST([SHPROG])
+m4trace:configure.in:119: -1- AC_SUBST_TRACE([SHPROG])
+m4trace:configure.in:119: -1- m4_pattern_allow([^SHPROG$])
+m4trace:configure.in:122: -1- AC_SUBST([LEX])
+m4trace:configure.in:122: -1- AC_SUBST_TRACE([LEX])
+m4trace:configure.in:122: -1- m4_pattern_allow([^LEX$])
+m4trace:configure.in:122: -1- AC_SUBST([LEX_OUTPUT_ROOT], [$ac_cv_prog_lex_root])
+m4trace:configure.in:122: -1- AC_SUBST_TRACE([LEX_OUTPUT_ROOT])
+m4trace:configure.in:122: -1- m4_pattern_allow([^LEX_OUTPUT_ROOT$])
+m4trace:configure.in:122: -1- AC_SUBST([LEXLIB])
+m4trace:configure.in:122: -1- AC_SUBST_TRACE([LEXLIB])
+m4trace:configure.in:122: -1- m4_pattern_allow([^LEXLIB$])
+m4trace:configure.in:122: -1- AC_DEFINE_TRACE_LITERAL([YYTEXT_POINTER])
+m4trace:configure.in:122: -1- m4_pattern_allow([^YYTEXT_POINTER$])
+m4trace:configure.in:122: -1- AH_OUTPUT([YYTEXT_POINTER], [/* Define to 1 if `lex\' declares `yytext\' as a `char *\' by default, not a
+   `char[]\'. */
+#undef YYTEXT_POINTER])
+m4trace:configure.in:133: -1- AC_SUBST([YACC])
+m4trace:configure.in:133: -1- AC_SUBST_TRACE([YACC])
+m4trace:configure.in:133: -1- m4_pattern_allow([^YACC$])
+m4trace:configure.in:133: -1- AC_SUBST([YACC])
+m4trace:configure.in:133: -1- AC_SUBST_TRACE([YACC])
+m4trace:configure.in:133: -1- m4_pattern_allow([^YACC$])
+m4trace:configure.in:133: -1- AC_SUBST([YFLAGS])
+m4trace:configure.in:133: -1- AC_SUBST_TRACE([YFLAGS])
+m4trace:configure.in:133: -1- m4_pattern_allow([^YFLAGS$])
+m4trace:configure.in:145: -1- _m4_warn([obsolete], [The macro `AC_TRY_RUN' is obsolete.
+You should run autoupdate.], [../../lib/autoconf/general.m4:2478: AC_TRY_RUN is expanded from...
+../../lib/m4sugar/m4sh.m4:516: AS_IF is expanded from...
+../../lib/autoconf/general.m4:1898: AC_CACHE_VAL is expanded from...
+../../lib/autoconf/general.m4:1911: AC_CACHE_CHECK is expanded from...
+acinclude.m4:7: unet_NONBLOCKING is expanded from...
+configure.in:145: the top level])
+m4trace:configure.in:145: -1- _m4_warn([cross], [AC_RUN_IFELSE called without default to allow cross compiling], [../../lib/autoconf/general.m4:2462: AC_RUN_IFELSE is expanded from...
+../../lib/autoconf/general.m4:2478: AC_TRY_RUN is expanded from...
+../../lib/m4sugar/m4sh.m4:516: AS_IF is expanded from...
+../../lib/autoconf/general.m4:1898: AC_CACHE_VAL is expanded from...
+../../lib/autoconf/general.m4:1911: AC_CACHE_CHECK is expanded from...
+acinclude.m4:7: unet_NONBLOCKING is expanded from...
+configure.in:145: the top level])
+m4trace:configure.in:145: -1- AC_DEFINE_TRACE_LITERAL([NBLOCK_POSIX])
+m4trace:configure.in:145: -1- m4_pattern_allow([^NBLOCK_POSIX$])
+m4trace:configure.in:145: -1- AH_OUTPUT([NBLOCK_POSIX], [/* Define if you have POSIX non-blocking sockets. */
+#undef NBLOCK_POSIX])
+m4trace:configure.in:145: -1- _m4_warn([obsolete], [The macro `AC_TRY_RUN' is obsolete.
+You should run autoupdate.], [../../lib/autoconf/general.m4:2478: AC_TRY_RUN is expanded from...
+../../lib/m4sugar/m4sh.m4:516: AS_IF is expanded from...
+../../lib/autoconf/general.m4:1898: AC_CACHE_VAL is expanded from...
+../../lib/autoconf/general.m4:1911: AC_CACHE_CHECK is expanded from...
+acinclude.m4:7: unet_NONBLOCKING is expanded from...
+configure.in:145: the top level])
+m4trace:configure.in:145: -1- _m4_warn([cross], [AC_RUN_IFELSE called without default to allow cross compiling], [../../lib/autoconf/general.m4:2462: AC_RUN_IFELSE is expanded from...
+../../lib/autoconf/general.m4:2478: AC_TRY_RUN is expanded from...
+../../lib/m4sugar/m4sh.m4:516: AS_IF is expanded from...
+../../lib/autoconf/general.m4:1898: AC_CACHE_VAL is expanded from...
+../../lib/autoconf/general.m4:1911: AC_CACHE_CHECK is expanded from...
+acinclude.m4:7: unet_NONBLOCKING is expanded from...
+configure.in:145: the top level])
+m4trace:configure.in:145: -1- AC_DEFINE_TRACE_LITERAL([NBLOCK_BSD])
+m4trace:configure.in:145: -1- m4_pattern_allow([^NBLOCK_BSD$])
+m4trace:configure.in:145: -1- AH_OUTPUT([NBLOCK_BSD], [/* Define if you have BSD non-blocking sockets. */
+#undef NBLOCK_BSD])
+m4trace:configure.in:145: -1- AC_DEFINE_TRACE_LITERAL([NBLOCK_SYSV])
+m4trace:configure.in:145: -1- m4_pattern_allow([^NBLOCK_SYSV$])
+m4trace:configure.in:145: -1- AH_OUTPUT([NBLOCK_SYSV], [/* Define if you have SysV non-blocking sockets. */
+#undef NBLOCK_SYSV])
+m4trace:configure.in:146: -1- _m4_warn([obsolete], [The macro `AC_TRY_COMPILE' is obsolete.
+You should run autoupdate.], [../../lib/autoconf/general.m4:2367: AC_TRY_COMPILE is expanded from...
+../../lib/m4sugar/m4sh.m4:516: AS_IF is expanded from...
+../../lib/autoconf/general.m4:1898: AC_CACHE_VAL is expanded from...
+../../lib/autoconf/general.m4:1911: AC_CACHE_CHECK is expanded from...
+acinclude.m4:74: unet_SIGNALS is expanded from...
+configure.in:146: the top level])
+m4trace:configure.in:146: -1- AC_DEFINE_TRACE_LITERAL([POSIX_SIGNALS])
+m4trace:configure.in:146: -1- m4_pattern_allow([^POSIX_SIGNALS$])
+m4trace:configure.in:146: -1- AH_OUTPUT([POSIX_SIGNALS], [/* Define if you have POSIX signals. */
+#undef POSIX_SIGNALS])
+m4trace:configure.in:146: -1- _m4_warn([obsolete], [The macro `AC_TRY_RUN' is obsolete.
+You should run autoupdate.], [../../lib/autoconf/general.m4:2478: AC_TRY_RUN is expanded from...
+../../lib/m4sugar/m4sh.m4:516: AS_IF is expanded from...
+../../lib/autoconf/general.m4:1898: AC_CACHE_VAL is expanded from...
+../../lib/autoconf/general.m4:1911: AC_CACHE_CHECK is expanded from...
+acinclude.m4:74: unet_SIGNALS is expanded from...
+configure.in:146: the top level])
+m4trace:configure.in:146: -1- _m4_warn([cross], [AC_RUN_IFELSE called without default to allow cross compiling], [../../lib/autoconf/general.m4:2462: AC_RUN_IFELSE is expanded from...
+../../lib/autoconf/general.m4:2478: AC_TRY_RUN is expanded from...
+../../lib/m4sugar/m4sh.m4:516: AS_IF is expanded from...
+../../lib/autoconf/general.m4:1898: AC_CACHE_VAL is expanded from...
+../../lib/autoconf/general.m4:1911: AC_CACHE_CHECK is expanded from...
+acinclude.m4:74: unet_SIGNALS is expanded from...
+configure.in:146: the top level])
+m4trace:configure.in:146: -1- AC_DEFINE_TRACE_LITERAL([BSD_RELIABLE_SIGNALS])
+m4trace:configure.in:146: -1- m4_pattern_allow([^BSD_RELIABLE_SIGNALS$])
+m4trace:configure.in:146: -1- AH_OUTPUT([BSD_RELIABLE_SIGNALS], [/* Define if you have (reliable) BSD signals. */
+#undef BSD_RELIABLE_SIGNALS])
+m4trace:configure.in:146: -1- AC_DEFINE_TRACE_LITERAL([SYSV_UNRELIABLE_SIGNALS])
+m4trace:configure.in:146: -1- m4_pattern_allow([^SYSV_UNRELIABLE_SIGNALS$])
+m4trace:configure.in:146: -1- AH_OUTPUT([SYSV_UNRELIABLE_SIGNALS], [/* Define if you have (unreliable) SysV signals. */
+#undef SYSV_UNRELIABLE_SIGNALS])
+m4trace:configure.in:163: -1- AC_DEFINE_TRACE_LITERAL([IRCU_SOLARIS])
+m4trace:configure.in:163: -1- m4_pattern_allow([^IRCU_SOLARIS$])
+m4trace:configure.in:163: -1- AH_OUTPUT([IRCU_SOLARIS], [/* Define if building on Solaris */
+#undef IRCU_SOLARIS])
+m4trace:configure.in:192: -1- AC_DEFINE_TRACE_LITERAL([_DARWIN_C_SOURCE])
+m4trace:configure.in:192: -1- m4_pattern_allow([^_DARWIN_C_SOURCE$])
+m4trace:configure.in:192: -1- AH_OUTPUT([_DARWIN_C_SOURCE], [/* Define to enable POSIX compatibility on Darwin. */
+#undef _DARWIN_C_SOURCE])
+m4trace:configure.in:220: -1- AC_DEFINE_TRACE_LITERAL([USE_POLL])
+m4trace:configure.in:220: -1- m4_pattern_allow([^USE_POLL$])
+m4trace:configure.in:220: -1- AH_OUTPUT([USE_POLL], [/* Specify whether or not to use poll() */
+#undef USE_POLL])
+m4trace:configure.in:225: -1- AC_SUBST([ENGINE_C])
+m4trace:configure.in:225: -1- AC_SUBST_TRACE([ENGINE_C])
+m4trace:configure.in:225: -1- m4_pattern_allow([^ENGINE_C$])
+m4trace:configure.in:237: -1- AC_DEFINE_TRACE_LITERAL([DEBUGMODE])
+m4trace:configure.in:237: -1- m4_pattern_allow([^DEBUGMODE$])
+m4trace:configure.in:237: -1- AH_OUTPUT([DEBUGMODE], [/* Enable debugging code */
+#undef DEBUGMODE])
+m4trace:configure.in:264: -1- AC_DEFINE_TRACE_LITERAL([IPV6])
+m4trace:configure.in:264: -1- m4_pattern_allow([^IPV6$])
+m4trace:configure.in:264: -1- AH_OUTPUT([IPV6], [/* Enable IPv6 support */
+#undef IPV6])
+m4trace:configure.in:277: -1- AC_DEFINE_TRACE_LITERAL([NDEBUG])
+m4trace:configure.in:277: -1- m4_pattern_allow([^NDEBUG$])
+m4trace:configure.in:277: -1- AH_OUTPUT([NDEBUG], [/* Disable assertions */
+#undef NDEBUG])
+m4trace:configure.in:330: -1- AC_DEFINE_TRACE_LITERAL([FORCEINLINE])
+m4trace:configure.in:330: -1- m4_pattern_allow([^FORCEINLINE$])
+m4trace:configure.in:330: -1- AH_OUTPUT([FORCEINLINE], [/* Force inlining for a few critical functions */
+#undef FORCEINLINE])
+m4trace:configure.in:348: -1- AC_DEFINE_TRACE_LITERAL([USE_DEVPOLL])
+m4trace:configure.in:348: -1- m4_pattern_allow([^USE_DEVPOLL$])
+m4trace:configure.in:348: -1- AH_OUTPUT([USE_DEVPOLL], [/* Define to enable the /dev/poll engine */
+#undef USE_DEVPOLL])
+m4trace:configure.in:367: -1- AC_DEFINE_TRACE_LITERAL([USE_KQUEUE])
+m4trace:configure.in:367: -1- m4_pattern_allow([^USE_KQUEUE$])
+m4trace:configure.in:367: -1- AH_OUTPUT([USE_KQUEUE], [/* Define to enable the kqueue engine */
+#undef USE_KQUEUE])
+m4trace:configure.in:389: -1- AC_DEFINE_TRACE_LITERAL([EPOLL_NEED_BODY])
+m4trace:configure.in:389: -1- m4_pattern_allow([^EPOLL_NEED_BODY$])
+m4trace:configure.in:389: -1- AH_OUTPUT([EPOLL_NEED_BODY], [/* Define to implement epoll system calls */
+#undef EPOLL_NEED_BODY])
+m4trace:configure.in:393: -1- AC_DEFINE_TRACE_LITERAL([USE_EPOLL])
+m4trace:configure.in:393: -1- m4_pattern_allow([^USE_EPOLL$])
+m4trace:configure.in:393: -1- AH_OUTPUT([USE_EPOLL], [/* Define to enable the epoll engine */
+#undef USE_EPOLL])
+m4trace:configure.in:404: -1- AC_DEFINE_TRACE_LITERAL([HAVE_VA_COPY])
+m4trace:configure.in:404: -1- m4_pattern_allow([^HAVE_VA_COPY$])
+m4trace:configure.in:404: -1- AH_OUTPUT([HAVE_VA_COPY], [/* Define if we have va_copy */
+#undef HAVE_VA_COPY])
+m4trace:configure.in:413: -1- AC_DEFINE_TRACE_LITERAL([HAVE___VA_COPY])
+m4trace:configure.in:413: -1- m4_pattern_allow([^HAVE___VA_COPY$])
+m4trace:configure.in:413: -1- AH_OUTPUT([HAVE___VA_COPY], [/* Define if we have __va_copy */
+#undef HAVE___VA_COPY])
+m4trace:configure.in:438: -1- AC_SUBST([INSTALL_RULE])
+m4trace:configure.in:438: -1- AC_SUBST_TRACE([INSTALL_RULE])
+m4trace:configure.in:438: -1- m4_pattern_allow([^INSTALL_RULE$])
+m4trace:configure.in:439: -1- AC_SUBST([SYMLINK])
+m4trace:configure.in:439: -1- AC_SUBST_TRACE([SYMLINK])
+m4trace:configure.in:439: -1- m4_pattern_allow([^SYMLINK$])
+m4trace:configure.in:456: -1- AC_SUBST([IRCDMODE])
+m4trace:configure.in:456: -1- AC_SUBST_TRACE([IRCDMODE])
+m4trace:configure.in:456: -1- m4_pattern_allow([^IRCDMODE$])
+m4trace:configure.in:476: -1- AC_SUBST([IRCDOWN])
+m4trace:configure.in:476: -1- AC_SUBST_TRACE([IRCDOWN])
+m4trace:configure.in:476: -1- m4_pattern_allow([^IRCDOWN$])
+m4trace:configure.in:496: -1- AC_SUBST([IRCDGRP])
+m4trace:configure.in:496: -1- AC_SUBST_TRACE([IRCDGRP])
+m4trace:configure.in:496: -1- m4_pattern_allow([^IRCDGRP$])
+m4trace:configure.in:522: -1- AC_DEFINE_TRACE_LITERAL([DOMAINNAME])
+m4trace:configure.in:522: -1- m4_pattern_allow([^DOMAINNAME$])
+m4trace:configure.in:522: -1- AH_OUTPUT([DOMAINNAME], [/* Domain name to be used for some statistics gathering */
+#undef DOMAINNAME])
+m4trace:configure.in:592: -1- AC_DEFINE_TRACE_LITERAL([SPATH])
+m4trace:configure.in:592: -1- m4_pattern_allow([^SPATH$])
+m4trace:configure.in:592: -1- AH_OUTPUT([SPATH], [/* Path to executable for restarts */
+#undef SPATH])
+m4trace:configure.in:621: -1- AC_DEFINE_TRACE_LITERAL([DPATH])
+m4trace:configure.in:621: -1- m4_pattern_allow([^DPATH$])
+m4trace:configure.in:621: -1- AH_OUTPUT([DPATH], [/* Path to data directory */
+#undef DPATH])
+m4trace:configure.in:624: -1- AC_SUBST([DPATH])
+m4trace:configure.in:624: -1- AC_SUBST_TRACE([DPATH])
+m4trace:configure.in:624: -1- m4_pattern_allow([^DPATH$])
+m4trace:configure.in:655: -1- AC_DEFINE_TRACE_LITERAL([CPATH])
+m4trace:configure.in:655: -1- m4_pattern_allow([^CPATH$])
+m4trace:configure.in:655: -1- AH_OUTPUT([CPATH], [/* Configuration file name */
+#undef CPATH])
+m4trace:configure.in:688: -1- AC_DEFINE_TRACE_LITERAL([LPATH])
+m4trace:configure.in:688: -1- m4_pattern_allow([^LPATH$])
+m4trace:configure.in:688: -1- AH_OUTPUT([LPATH], [/* Path to debugging log file */
+#undef LPATH])
+m4trace:configure.in:714: -1- AC_DEFINE_TRACE_LITERAL([MAXCONNECTIONS])
+m4trace:configure.in:714: -1- m4_pattern_allow([^MAXCONNECTIONS$])
+m4trace:configure.in:714: -1- AH_OUTPUT([MAXCONNECTIONS], [/* Maximum number of network connections */
+#undef MAXCONNECTIONS])
+m4trace:configure.in:730: -1- AC_DEFINE_TRACE_LITERAL([OLD_OGN_IRCU_COMPAT])
+m4trace:configure.in:730: -1- m4_pattern_allow([^OLD_OGN_IRCU_COMPAT$])
+m4trace:configure.in:730: -1- AH_OUTPUT([OLD_OGN_IRCU_COMPAT], [/* Enable compatibility mode. */
+#undef OLD_OGN_IRCU_COMPAT])
+m4trace:configure.in:743: -1- AC_DEFINE_TRACE_LITERAL([WITH_UNSTABLE_FEAT])
+m4trace:configure.in:743: -1- m4_pattern_allow([^WITH_UNSTABLE_FEAT$])
+m4trace:configure.in:743: -1- AH_OUTPUT([WITH_UNSTABLE_FEAT], [/* Enable unstable features. */
+#undef WITH_UNSTABLE_FEAT])
+m4trace:configure.in:766: -1- AH_OUTPUT([HAVE_GNUTLS_GNUTLS_H], [/* Define to 1 if you have the <gnutls/gnutls.h> header file. */
+#undef HAVE_GNUTLS_GNUTLS_H])
+m4trace:configure.in:775: -1- AH_OUTPUT([HAVE_OPENSSL_SSL_H], [/* Define to 1 if you have the <openssl/ssl.h> header file. */
+#undef HAVE_OPENSSL_SSL_H])
+m4trace:configure.in:775: -1- AH_OUTPUT([HAVE_OPENSSL_ERR_H], [/* Define to 1 if you have the <openssl/err.h> header file. */
+#undef HAVE_OPENSSL_ERR_H])
+m4trace:configure.in:786: -1- AC_DEFINE_TRACE_LITERAL([HAVE_GNUTLS])
+m4trace:configure.in:786: -1- m4_pattern_allow([^HAVE_GNUTLS$])
+m4trace:configure.in:786: -1- AH_OUTPUT([HAVE_GNUTLS], [/* Define if you are using GnuTLS */
+#undef HAVE_GNUTLS])
+m4trace:configure.in:791: -1- AC_DEFINE_TRACE_LITERAL([HAVE_OPENSSL])
+m4trace:configure.in:791: -1- m4_pattern_allow([^HAVE_OPENSSL$])
+m4trace:configure.in:791: -1- AH_OUTPUT([HAVE_OPENSSL], [/* Define if you are using OpenSSL */
+#undef HAVE_OPENSSL])
+m4trace:configure.in:795: -1- AC_CONFIG_FILES([Makefile ircd/Makefile doc/Makefile])
+m4trace:configure.in:795: -1- _m4_warn([obsolete], [AC_OUTPUT should be used without arguments.
+You should run autoupdate.], [])
+m4trace:configure.in:795: -1- AC_SUBST([LIB@&t@OBJS], [$ac_libobjs])
+m4trace:configure.in:795: -1- AC_SUBST_TRACE([LIB@&t@OBJS])
+m4trace:configure.in:795: -1- m4_pattern_allow([^LIB@&t@OBJS$])
+m4trace:configure.in:795: -1- AC_SUBST([LTLIBOBJS], [$ac_ltlibobjs])
+m4trace:configure.in:795: -1- AC_SUBST_TRACE([LTLIBOBJS])
+m4trace:configure.in:795: -1- m4_pattern_allow([^LTLIBOBJS$])
+m4trace:configure.in:795: -1- AC_SUBST_TRACE([top_builddir])
+m4trace:configure.in:795: -1- AC_SUBST_TRACE([srcdir])
+m4trace:configure.in:795: -1- AC_SUBST_TRACE([abs_srcdir])
+m4trace:configure.in:795: -1- AC_SUBST_TRACE([top_srcdir])
+m4trace:configure.in:795: -1- AC_SUBST_TRACE([abs_top_srcdir])
+m4trace:configure.in:795: -1- AC_SUBST_TRACE([builddir])
+m4trace:configure.in:795: -1- AC_SUBST_TRACE([abs_builddir])
+m4trace:configure.in:795: -1- AC_SUBST_TRACE([abs_top_builddir])
+m4trace:configure.in:795: -1- AC_SUBST_TRACE([INSTALL])
diff --git a/clean b/clean
new file mode 100644 (file)
index 0000000..04c184d
--- /dev/null
+++ b/clean
@@ -0,0 +1,12 @@
+#!/bin/sh
+
+if [ -f "LICENSE" ] ; then
+  HASH=`md5sum LICENSE | awk '{print $1}'`
+  if [ "x$HASH" = "xda10ed7cf8038981c580e11c1d3e8fb6" ] ; then
+    rm -vf ircd/*.o
+    rm "-vfR" "configure" "Makefile" "doc/Makefile" "ircd/Makefile" "ircd/version.c" "config.log" "config.status" "config.h" "config.h.in" "autom4te.cache" "stamp-h" "aclocal.m4" "ircd/umkpasswd" "ircd/table_gen" "ircd/ircd" "ircd/chattr.tab.c" "ircd/lex.yy.c" "ircd/y.tab.h" "ircd/y.tab.c" ircd/*.orig
+  else
+    echo "You need to be in the ircu-core directory where the configure.in file lies."
+  fi
+fi
+
diff --git a/config.guess b/config.guess
new file mode 100644 (file)
index 0000000..10a8260
--- /dev/null
@@ -0,0 +1,1476 @@
+#! /bin/sh
+# Attempt to guess a canonical system name.
+#   Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
+#   2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
+
+timestamp='2005-12-23'
+
+# This file is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
+# 02110-1301, USA.
+#
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+
+# Originally written by Per Bothner <per@bothner.com>.
+# Please send patches to <config-patches@gnu.org>.  Submit a context
+# diff and a properly formatted ChangeLog entry.
+#
+# This script attempts to guess a canonical system name similar to
+# config.sub.  If it succeeds, it prints the system name on stdout, and
+# exits with 0.  Otherwise, it exits with 1.
+#
+# The plan is that this can be called by configure scripts if you
+# don't specify an explicit build system type.
+
+me=`echo "$0" | sed -e 's,.*/,,'`
+
+usage="\
+Usage: $0 [OPTION]
+
+Output the configuration name of the system \`$me' is run on.
+
+Operation modes:
+  -h, --help         print this help, then exit
+  -t, --time-stamp   print date of last modification, then exit
+  -v, --version      print version number, then exit
+
+Report bugs and patches to <config-patches@gnu.org>."
+
+version="\
+GNU config.guess ($timestamp)
+
+Originally written by Per Bothner.
+Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005
+Free Software Foundation, Inc.
+
+This is free software; see the source for copying conditions.  There is NO
+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
+
+help="
+Try \`$me --help' for more information."
+
+# Parse command line
+while test $# -gt 0 ; do
+  case $1 in
+    --time-stamp | --time* | -t )
+       echo "$timestamp" ; exit ;;
+    --version | -v )
+       echo "$version" ; exit ;;
+    --help | --h* | -h )
+       echo "$usage"; exit ;;
+    -- )     # Stop option processing
+       shift; break ;;
+    - )        # Use stdin as input.
+       break ;;
+    -* )
+       echo "$me: invalid option $1$help" >&2
+       exit 1 ;;
+    * )
+       break ;;
+  esac
+done
+
+if test $# != 0; then
+  echo "$me: too many arguments$help" >&2
+  exit 1
+fi
+
+trap 'exit 1' 1 2 15
+
+# CC_FOR_BUILD -- compiler used by this script. Note that the use of a
+# compiler to aid in system detection is discouraged as it requires
+# temporary files to be created and, as you can see below, it is a
+# headache to deal with in a portable fashion.
+
+# Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still
+# use `HOST_CC' if defined, but it is deprecated.
+
+# Portable tmp directory creation inspired by the Autoconf team.
+
+set_cc_for_build='
+trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ;
+trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ;
+: ${TMPDIR=/tmp} ;
+ { tmp=`(umask 077 && mktemp -d -q "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } ||
+ { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } ||
+ { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } ||
+ { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ;
+dummy=$tmp/dummy ;
+tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ;
+case $CC_FOR_BUILD,$HOST_CC,$CC in
+ ,,)    echo "int x;" > $dummy.c ;
+       for c in cc gcc c89 c99 ; do
+         if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then
+            CC_FOR_BUILD="$c"; break ;
+         fi ;
+       done ;
+       if test x"$CC_FOR_BUILD" = x ; then
+         CC_FOR_BUILD=no_compiler_found ;
+       fi
+       ;;
+ ,,*)   CC_FOR_BUILD=$CC ;;
+ ,*,*)  CC_FOR_BUILD=$HOST_CC ;;
+esac ; set_cc_for_build= ;'
+
+# This is needed to find uname on a Pyramid OSx when run in the BSD universe.
+# (ghazi@noc.rutgers.edu 1994-08-24)
+if (test -f /.attbin/uname) >/dev/null 2>&1 ; then
+       PATH=$PATH:/.attbin ; export PATH
+fi
+
+UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown
+UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown
+UNAME_SYSTEM=`(uname -s) 2>/dev/null`  || UNAME_SYSTEM=unknown
+UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown
+
+# Note: order is significant - the case branches are not exclusive.
+
+case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
+    *:NetBSD:*:*)
+       # NetBSD (nbsd) targets should (where applicable) match one or
+       # more of the tupples: *-*-netbsdelf*, *-*-netbsdaout*,
+       # *-*-netbsdecoff* and *-*-netbsd*.  For targets that recently
+       # switched to ELF, *-*-netbsd* would select the old
+       # object file format.  This provides both forward
+       # compatibility and a consistent mechanism for selecting the
+       # object file format.
+       #
+       # Note: NetBSD doesn't particularly care about the vendor
+       # portion of the name.  We always set it to "unknown".
+       sysctl="sysctl -n hw.machine_arch"
+       UNAME_MACHINE_ARCH=`(/sbin/$sysctl 2>/dev/null || \
+           /usr/sbin/$sysctl 2>/dev/null || echo unknown)`
+       case "${UNAME_MACHINE_ARCH}" in
+           armeb) machine=armeb-unknown ;;
+           arm*) machine=arm-unknown ;;
+           sh3el) machine=shl-unknown ;;
+           sh3eb) machine=sh-unknown ;;
+           *) machine=${UNAME_MACHINE_ARCH}-unknown ;;
+       esac
+       # The Operating System including object format, if it has switched
+       # to ELF recently, or will in the future.
+       case "${UNAME_MACHINE_ARCH}" in
+           arm*|i386|m68k|ns32k|sh3*|sparc|vax)
+               eval $set_cc_for_build
+               if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \
+                       | grep __ELF__ >/dev/null
+               then
+                   # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout).
+                   # Return netbsd for either.  FIX?
+                   os=netbsd
+               else
+                   os=netbsdelf
+               fi
+               ;;
+           *)
+               os=netbsd
+               ;;
+       esac
+       # The OS release
+       # Debian GNU/NetBSD machines have a different userland, and
+       # thus, need a distinct triplet. However, they do not need
+       # kernel version information, so it can be replaced with a
+       # suitable tag, in the style of linux-gnu.
+       case "${UNAME_VERSION}" in
+           Debian*)
+               release='-gnu'
+               ;;
+           *)
+               release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'`
+               ;;
+       esac
+       # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM:
+       # contains redundant information, the shorter form:
+       # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used.
+       echo "${machine}-${os}${release}"
+       exit ;;
+    *:OpenBSD:*:*)
+       UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'`
+       echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE}
+       exit ;;
+    *:ekkoBSD:*:*)
+       echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE}
+       exit ;;
+    macppc:MirBSD:*:*)
+       echo powerppc-unknown-mirbsd${UNAME_RELEASE}
+       exit ;;
+    *:MirBSD:*:*)
+       echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE}
+       exit ;;
+    alpha:OSF1:*:*)
+       case $UNAME_RELEASE in
+       *4.0)
+               UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'`
+               ;;
+       *5.*)
+               UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'`
+               ;;
+       esac
+       # According to Compaq, /usr/sbin/psrinfo has been available on
+       # OSF/1 and Tru64 systems produced since 1995.  I hope that
+       # covers most systems running today.  This code pipes the CPU
+       # types through head -n 1, so we only detect the type of CPU 0.
+       ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^  The alpha \(.*\) processor.*$/\1/p' | head -n 1`
+       case "$ALPHA_CPU_TYPE" in
+           "EV4 (21064)")
+               UNAME_MACHINE="alpha" ;;
+           "EV4.5 (21064)")
+               UNAME_MACHINE="alpha" ;;
+           "LCA4 (21066/21068)")
+               UNAME_MACHINE="alpha" ;;
+           "EV5 (21164)")
+               UNAME_MACHINE="alphaev5" ;;
+           "EV5.6 (21164A)")
+               UNAME_MACHINE="alphaev56" ;;
+           "EV5.6 (21164PC)")
+               UNAME_MACHINE="alphapca56" ;;
+           "EV5.7 (21164PC)")
+               UNAME_MACHINE="alphapca57" ;;
+           "EV6 (21264)")
+               UNAME_MACHINE="alphaev6" ;;
+           "EV6.7 (21264A)")
+               UNAME_MACHINE="alphaev67" ;;
+           "EV6.8CB (21264C)")
+               UNAME_MACHINE="alphaev68" ;;
+           "EV6.8AL (21264B)")
+               UNAME_MACHINE="alphaev68" ;;
+           "EV6.8CX (21264D)")
+               UNAME_MACHINE="alphaev68" ;;
+           "EV6.9A (21264/EV69A)")
+               UNAME_MACHINE="alphaev69" ;;
+           "EV7 (21364)")
+               UNAME_MACHINE="alphaev7" ;;
+           "EV7.9 (21364A)")
+               UNAME_MACHINE="alphaev79" ;;
+       esac
+       # A Pn.n version is a patched version.
+       # A Vn.n version is a released version.
+       # A Tn.n version is a released field test version.
+       # A Xn.n version is an unreleased experimental baselevel.
+       # 1.2 uses "1.2" for uname -r.
+       echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
+       exit ;;
+    Alpha\ *:Windows_NT*:*)
+       # How do we know it's Interix rather than the generic POSIX subsystem?
+       # Should we change UNAME_MACHINE based on the output of uname instead
+       # of the specific Alpha model?
+       echo alpha-pc-interix
+       exit ;;
+    21064:Windows_NT:50:3)
+       echo alpha-dec-winnt3.5
+       exit ;;
+    Amiga*:UNIX_System_V:4.0:*)
+       echo m68k-unknown-sysv4
+       exit ;;
+    *:[Aa]miga[Oo][Ss]:*:*)
+       echo ${UNAME_MACHINE}-unknown-amigaos
+       exit ;;
+    *:[Mm]orph[Oo][Ss]:*:*)
+       echo ${UNAME_MACHINE}-unknown-morphos
+       exit ;;
+    *:OS/390:*:*)
+       echo i370-ibm-openedition
+       exit ;;
+    *:z/VM:*:*)
+       echo s390-ibm-zvmoe
+       exit ;;
+    *:OS400:*:*)
+        echo powerpc-ibm-os400
+       exit ;;
+    arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*)
+       echo arm-acorn-riscix${UNAME_RELEASE}
+       exit ;;
+    arm:riscos:*:*|arm:RISCOS:*:*)
+       echo arm-unknown-riscos
+       exit ;;
+    SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*)
+       echo hppa1.1-hitachi-hiuxmpp
+       exit ;;
+    Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*)
+       # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE.
+       if test "`(/bin/universe) 2>/dev/null`" = att ; then
+               echo pyramid-pyramid-sysv3
+       else
+               echo pyramid-pyramid-bsd
+       fi
+       exit ;;
+    NILE*:*:*:dcosx)
+       echo pyramid-pyramid-svr4
+       exit ;;
+    DRS?6000:unix:4.0:6*)
+       echo sparc-icl-nx6
+       exit ;;
+    DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*)
+       case `/usr/bin/uname -p` in
+           sparc) echo sparc-icl-nx7; exit ;;
+       esac ;;
+    sun4H:SunOS:5.*:*)
+       echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+       exit ;;
+    sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*)
+       echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+       exit ;;
+    i86pc:SunOS:5.*:*)
+       echo i386-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+       exit ;;
+    sun4*:SunOS:6*:*)
+       # According to config.sub, this is the proper way to canonicalize
+       # SunOS6.  Hard to guess exactly what SunOS6 will be like, but
+       # it's likely to be more like Solaris than SunOS4.
+       echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+       exit ;;
+    sun4*:SunOS:*:*)
+       case "`/usr/bin/arch -k`" in
+           Series*|S4*)
+               UNAME_RELEASE=`uname -v`
+               ;;
+       esac
+       # Japanese Language versions have a version number like `4.1.3-JL'.
+       echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'`
+       exit ;;
+    sun3*:SunOS:*:*)
+       echo m68k-sun-sunos${UNAME_RELEASE}
+       exit ;;
+    sun*:*:4.2BSD:*)
+       UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null`
+       test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3
+       case "`/bin/arch`" in
+           sun3)
+               echo m68k-sun-sunos${UNAME_RELEASE}
+               ;;
+           sun4)
+               echo sparc-sun-sunos${UNAME_RELEASE}
+               ;;
+       esac
+       exit ;;
+    aushp:SunOS:*:*)
+       echo sparc-auspex-sunos${UNAME_RELEASE}
+       exit ;;
+    # The situation for MiNT is a little confusing.  The machine name
+    # can be virtually everything (everything which is not
+    # "atarist" or "atariste" at least should have a processor
+    # > m68000).  The system name ranges from "MiNT" over "FreeMiNT"
+    # to the lowercase version "mint" (or "freemint").  Finally
+    # the system name "TOS" denotes a system which is actually not
+    # MiNT.  But MiNT is downward compatible to TOS, so this should
+    # be no problem.
+    atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*)
+        echo m68k-atari-mint${UNAME_RELEASE}
+       exit ;;
+    atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*)
+       echo m68k-atari-mint${UNAME_RELEASE}
+        exit ;;
+    *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*)
+        echo m68k-atari-mint${UNAME_RELEASE}
+       exit ;;
+    milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*)
+        echo m68k-milan-mint${UNAME_RELEASE}
+        exit ;;
+    hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*)
+        echo m68k-hades-mint${UNAME_RELEASE}
+        exit ;;
+    *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*)
+        echo m68k-unknown-mint${UNAME_RELEASE}
+        exit ;;
+    m68k:machten:*:*)
+       echo m68k-apple-machten${UNAME_RELEASE}
+       exit ;;
+    powerpc:machten:*:*)
+       echo powerpc-apple-machten${UNAME_RELEASE}
+       exit ;;
+    RISC*:Mach:*:*)
+       echo mips-dec-mach_bsd4.3
+       exit ;;
+    RISC*:ULTRIX:*:*)
+       echo mips-dec-ultrix${UNAME_RELEASE}
+       exit ;;
+    VAX*:ULTRIX*:*:*)
+       echo vax-dec-ultrix${UNAME_RELEASE}
+       exit ;;
+    2020:CLIX:*:* | 2430:CLIX:*:*)
+       echo clipper-intergraph-clix${UNAME_RELEASE}
+       exit ;;
+    mips:*:*:UMIPS | mips:*:*:RISCos)
+       eval $set_cc_for_build
+       sed 's/^        //' << EOF >$dummy.c
+#ifdef __cplusplus
+#include <stdio.h>  /* for printf() prototype */
+       int main (int argc, char *argv[]) {
+#else
+       int main (argc, argv) int argc; char *argv[]; {
+#endif
+       #if defined (host_mips) && defined (MIPSEB)
+       #if defined (SYSTYPE_SYSV)
+         printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0);
+       #endif
+       #if defined (SYSTYPE_SVR4)
+         printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0);
+       #endif
+       #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD)
+         printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0);
+       #endif
+       #endif
+         exit (-1);
+       }
+EOF
+       $CC_FOR_BUILD -o $dummy $dummy.c &&
+         dummyarg=`echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` &&
+         SYSTEM_NAME=`$dummy $dummyarg` &&
+           { echo "$SYSTEM_NAME"; exit; }
+       echo mips-mips-riscos${UNAME_RELEASE}
+       exit ;;
+    Motorola:PowerMAX_OS:*:*)
+       echo powerpc-motorola-powermax
+       exit ;;
+    Motorola:*:4.3:PL8-*)
+       echo powerpc-harris-powermax
+       exit ;;
+    Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*)
+       echo powerpc-harris-powermax
+       exit ;;
+    Night_Hawk:Power_UNIX:*:*)
+       echo powerpc-harris-powerunix
+       exit ;;
+    m88k:CX/UX:7*:*)
+       echo m88k-harris-cxux7
+       exit ;;
+    m88k:*:4*:R4*)
+       echo m88k-motorola-sysv4
+       exit ;;
+    m88k:*:3*:R3*)
+       echo m88k-motorola-sysv3
+       exit ;;
+    AViiON:dgux:*:*)
+        # DG/UX returns AViiON for all architectures
+        UNAME_PROCESSOR=`/usr/bin/uname -p`
+       if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ]
+       then
+           if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \
+              [ ${TARGET_BINARY_INTERFACE}x = x ]
+           then
+               echo m88k-dg-dgux${UNAME_RELEASE}
+           else
+               echo m88k-dg-dguxbcs${UNAME_RELEASE}
+           fi
+       else
+           echo i586-dg-dgux${UNAME_RELEASE}
+       fi
+       exit ;;
+    M88*:DolphinOS:*:*)        # DolphinOS (SVR3)
+       echo m88k-dolphin-sysv3
+       exit ;;
+    M88*:*:R3*:*)
+       # Delta 88k system running SVR3
+       echo m88k-motorola-sysv3
+       exit ;;
+    XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3)
+       echo m88k-tektronix-sysv3
+       exit ;;
+    Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD)
+       echo m68k-tektronix-bsd
+       exit ;;
+    *:IRIX*:*:*)
+       echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'`
+       exit ;;
+    ????????:AIX?:[12].1:2)   # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX.
+       echo romp-ibm-aix     # uname -m gives an 8 hex-code CPU id
+       exit ;;               # Note that: echo "'`uname -s`'" gives 'AIX '
+    i*86:AIX:*:*)
+       echo i386-ibm-aix
+       exit ;;
+    ia64:AIX:*:*)
+       if [ -x /usr/bin/oslevel ] ; then
+               IBM_REV=`/usr/bin/oslevel`
+       else
+               IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE}
+       fi
+       echo ${UNAME_MACHINE}-ibm-aix${IBM_REV}
+       exit ;;
+    *:AIX:2:3)
+       if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then
+               eval $set_cc_for_build
+               sed 's/^                //' << EOF >$dummy.c
+               #include <sys/systemcfg.h>
+
+               main()
+                       {
+                       if (!__power_pc())
+                               exit(1);
+                       puts("powerpc-ibm-aix3.2.5");
+                       exit(0);
+                       }
+EOF
+               if $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy`
+               then
+                       echo "$SYSTEM_NAME"
+               else
+                       echo rs6000-ibm-aix3.2.5
+               fi
+       elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then
+               echo rs6000-ibm-aix3.2.4
+       else
+               echo rs6000-ibm-aix3.2
+       fi
+       exit ;;
+    *:AIX:*:[45])
+       IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'`
+       if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then
+               IBM_ARCH=rs6000
+       else
+               IBM_ARCH=powerpc
+       fi
+       if [ -x /usr/bin/oslevel ] ; then
+               IBM_REV=`/usr/bin/oslevel`
+       else
+               IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE}
+       fi
+       echo ${IBM_ARCH}-ibm-aix${IBM_REV}
+       exit ;;
+    *:AIX:*:*)
+       echo rs6000-ibm-aix
+       exit ;;
+    ibmrt:4.4BSD:*|romp-ibm:BSD:*)
+       echo romp-ibm-bsd4.4
+       exit ;;
+    ibmrt:*BSD:*|romp-ibm:BSD:*)            # covers RT/PC BSD and
+       echo romp-ibm-bsd${UNAME_RELEASE}   # 4.3 with uname added to
+       exit ;;                             # report: romp-ibm BSD 4.3
+    *:BOSX:*:*)
+       echo rs6000-bull-bosx
+       exit ;;
+    DPX/2?00:B.O.S.:*:*)
+       echo m68k-bull-sysv3
+       exit ;;
+    9000/[34]??:4.3bsd:1.*:*)
+       echo m68k-hp-bsd
+       exit ;;
+    hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*)
+       echo m68k-hp-bsd4.4
+       exit ;;
+    9000/[34678]??:HP-UX:*:*)
+       HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`
+       case "${UNAME_MACHINE}" in
+           9000/31? )            HP_ARCH=m68000 ;;
+           9000/[34]?? )         HP_ARCH=m68k ;;
+           9000/[678][0-9][0-9])
+               if [ -x /usr/bin/getconf ]; then
+                   sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null`
+                    sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null`
+                    case "${sc_cpu_version}" in
+                      523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0
+                      528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1
+                      532)                      # CPU_PA_RISC2_0
+                        case "${sc_kernel_bits}" in
+                          32) HP_ARCH="hppa2.0n" ;;
+                          64) HP_ARCH="hppa2.0w" ;;
+                         '') HP_ARCH="hppa2.0" ;;   # HP-UX 10.20
+                        esac ;;
+                    esac
+               fi
+               if [ "${HP_ARCH}" = "" ]; then
+                   eval $set_cc_for_build
+                   sed 's/^              //' << EOF >$dummy.c
+
+              #define _HPUX_SOURCE
+              #include <stdlib.h>
+              #include <unistd.h>
+
+              int main ()
+              {
+              #if defined(_SC_KERNEL_BITS)
+                  long bits = sysconf(_SC_KERNEL_BITS);
+              #endif
+                  long cpu  = sysconf (_SC_CPU_VERSION);
+
+                  switch (cpu)
+               {
+               case CPU_PA_RISC1_0: puts ("hppa1.0"); break;
+               case CPU_PA_RISC1_1: puts ("hppa1.1"); break;
+               case CPU_PA_RISC2_0:
+              #if defined(_SC_KERNEL_BITS)
+                   switch (bits)
+                       {
+                       case 64: puts ("hppa2.0w"); break;
+                       case 32: puts ("hppa2.0n"); break;
+                       default: puts ("hppa2.0"); break;
+                       } break;
+              #else  /* !defined(_SC_KERNEL_BITS) */
+                   puts ("hppa2.0"); break;
+              #endif
+               default: puts ("hppa1.0"); break;
+               }
+                  exit (0);
+              }
+EOF
+                   (CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy`
+                   test -z "$HP_ARCH" && HP_ARCH=hppa
+               fi ;;
+       esac
+       if [ ${HP_ARCH} = "hppa2.0w" ]
+       then
+           eval $set_cc_for_build
+
+           # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating
+           # 32-bit code.  hppa64-hp-hpux* has the same kernel and a compiler
+           # generating 64-bit code.  GNU and HP use different nomenclature:
+           #
+           # $ CC_FOR_BUILD=cc ./config.guess
+           # => hppa2.0w-hp-hpux11.23
+           # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess
+           # => hppa64-hp-hpux11.23
+
+           if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) |
+               grep __LP64__ >/dev/null
+           then
+               HP_ARCH="hppa2.0w"
+           else
+               HP_ARCH="hppa64"
+           fi
+       fi
+       echo ${HP_ARCH}-hp-hpux${HPUX_REV}
+       exit ;;
+    ia64:HP-UX:*:*)
+       HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`
+       echo ia64-hp-hpux${HPUX_REV}
+       exit ;;
+    3050*:HI-UX:*:*)
+       eval $set_cc_for_build
+       sed 's/^        //' << EOF >$dummy.c
+       #include <unistd.h>
+       int
+       main ()
+       {
+         long cpu = sysconf (_SC_CPU_VERSION);
+         /* The order matters, because CPU_IS_HP_MC68K erroneously returns
+            true for CPU_PA_RISC1_0.  CPU_IS_PA_RISC returns correct
+            results, however.  */
+         if (CPU_IS_PA_RISC (cpu))
+           {
+             switch (cpu)
+               {
+                 case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break;
+                 case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break;
+                 case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break;
+                 default: puts ("hppa-hitachi-hiuxwe2"); break;
+               }
+           }
+         else if (CPU_IS_HP_MC68K (cpu))
+           puts ("m68k-hitachi-hiuxwe2");
+         else puts ("unknown-hitachi-hiuxwe2");
+         exit (0);
+       }
+EOF
+       $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` &&
+               { echo "$SYSTEM_NAME"; exit; }
+       echo unknown-hitachi-hiuxwe2
+       exit ;;
+    9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* )
+       echo hppa1.1-hp-bsd
+       exit ;;
+    9000/8??:4.3bsd:*:*)
+       echo hppa1.0-hp-bsd
+       exit ;;
+    *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*)
+       echo hppa1.0-hp-mpeix
+       exit ;;
+    hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* )
+       echo hppa1.1-hp-osf
+       exit ;;
+    hp8??:OSF1:*:*)
+       echo hppa1.0-hp-osf
+       exit ;;
+    i*86:OSF1:*:*)
+       if [ -x /usr/sbin/sysversion ] ; then
+           echo ${UNAME_MACHINE}-unknown-osf1mk
+       else
+           echo ${UNAME_MACHINE}-unknown-osf1
+       fi
+       exit ;;
+    parisc*:Lites*:*:*)
+       echo hppa1.1-hp-lites
+       exit ;;
+    C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*)
+       echo c1-convex-bsd
+        exit ;;
+    C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*)
+       if getsysinfo -f scalar_acc
+       then echo c32-convex-bsd
+       else echo c2-convex-bsd
+       fi
+        exit ;;
+    C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*)
+       echo c34-convex-bsd
+        exit ;;
+    C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*)
+       echo c38-convex-bsd
+        exit ;;
+    C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*)
+       echo c4-convex-bsd
+        exit ;;
+    CRAY*Y-MP:*:*:*)
+       echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+       exit ;;
+    CRAY*[A-Z]90:*:*:*)
+       echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \
+       | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \
+             -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \
+             -e 's/\.[^.]*$/.X/'
+       exit ;;
+    CRAY*TS:*:*:*)
+       echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+       exit ;;
+    CRAY*T3E:*:*:*)
+       echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+       exit ;;
+    CRAY*SV1:*:*:*)
+       echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+       exit ;;
+    *:UNICOS/mp:*:*)
+       echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+       exit ;;
+    F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*)
+       FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
+        FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'`
+        FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'`
+        echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
+        exit ;;
+    5000:UNIX_System_V:4.*:*)
+        FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'`
+        FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'`
+        echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
+       exit ;;
+    i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*)
+       echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE}
+       exit ;;
+    sparc*:BSD/OS:*:*)
+       echo sparc-unknown-bsdi${UNAME_RELEASE}
+       exit ;;
+    *:BSD/OS:*:*)
+       echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE}
+       exit ;;
+    *:FreeBSD:*:*)
+       case ${UNAME_MACHINE} in
+           pc98)
+               echo i386-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;;
+           *)
+               echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;;
+       esac
+       exit ;;
+    i*:CYGWIN*:*)
+       echo ${UNAME_MACHINE}-pc-cygwin
+       exit ;;
+    i*:MINGW*:*)
+       echo ${UNAME_MACHINE}-pc-mingw32
+       exit ;;
+    i*:windows32*:*)
+       # uname -m includes "-pc" on this system.
+       echo ${UNAME_MACHINE}-mingw32
+       exit ;;
+    i*:PW*:*)
+       echo ${UNAME_MACHINE}-pc-pw32
+       exit ;;
+    x86:Interix*:[345]*)
+       echo i586-pc-interix${UNAME_RELEASE}|sed -e 's/\..*//'
+       exit ;;
+    [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*)
+       echo i${UNAME_MACHINE}-pc-mks
+       exit ;;
+    i*:Windows_NT*:* | Pentium*:Windows_NT*:*)
+       # How do we know it's Interix rather than the generic POSIX subsystem?
+       # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we
+       # UNAME_MACHINE based on the output of uname instead of i386?
+       echo i586-pc-interix
+       exit ;;
+    i*:UWIN*:*)
+       echo ${UNAME_MACHINE}-pc-uwin
+       exit ;;
+    amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*)
+       echo x86_64-unknown-cygwin
+       exit ;;
+    p*:CYGWIN*:*)
+       echo powerpcle-unknown-cygwin
+       exit ;;
+    prep*:SunOS:5.*:*)
+       echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+       exit ;;
+    *:GNU:*:*)
+       # the GNU system
+       echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'`
+       exit ;;
+    *:GNU/*:*:*)
+       # other systems with GNU libc and userland
+       echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-gnu
+       exit ;;
+    i*86:Minix:*:*)
+       echo ${UNAME_MACHINE}-pc-minix
+       exit ;;
+    arm*:Linux:*:*)
+       echo ${UNAME_MACHINE}-unknown-linux-gnu
+       exit ;;
+    cris:Linux:*:*)
+       echo cris-axis-linux-gnu
+       exit ;;
+    crisv32:Linux:*:*)
+       echo crisv32-axis-linux-gnu
+       exit ;;
+    frv:Linux:*:*)
+       echo frv-unknown-linux-gnu
+       exit ;;
+    ia64:Linux:*:*)
+       echo ${UNAME_MACHINE}-unknown-linux-gnu
+       exit ;;
+    m32r*:Linux:*:*)
+       echo ${UNAME_MACHINE}-unknown-linux-gnu
+       exit ;;
+    m68*:Linux:*:*)
+       echo ${UNAME_MACHINE}-unknown-linux-gnu
+       exit ;;
+    mips:Linux:*:*)
+       eval $set_cc_for_build
+       sed 's/^        //' << EOF >$dummy.c
+       #undef CPU
+       #undef mips
+       #undef mipsel
+       #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL)
+       CPU=mipsel
+       #else
+       #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB)
+       CPU=mips
+       #else
+       CPU=
+       #endif
+       #endif
+EOF
+       eval "`$CC_FOR_BUILD -E $dummy.c 2>/dev/null | sed -n '/^CPU/{s: ::g;p;}'`"
+       test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; }
+       ;;
+    mips64:Linux:*:*)
+       eval $set_cc_for_build
+       sed 's/^        //' << EOF >$dummy.c
+       #undef CPU
+       #undef mips64
+       #undef mips64el
+       #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL)
+       CPU=mips64el
+       #else
+       #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB)
+       CPU=mips64
+       #else
+       CPU=
+       #endif
+       #endif
+EOF
+       eval "`$CC_FOR_BUILD -E $dummy.c 2>/dev/null | sed -n '/^CPU/{s: ::g;p;}'`"
+       test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; }
+       ;;
+    or32:Linux:*:*)
+       echo or32-unknown-linux-gnu
+       exit ;;
+    ppc:Linux:*:*)
+       echo powerpc-unknown-linux-gnu
+       exit ;;
+    ppc64:Linux:*:*)
+       echo powerpc64-unknown-linux-gnu
+       exit ;;
+    alpha:Linux:*:*)
+       case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in
+         EV5)   UNAME_MACHINE=alphaev5 ;;
+         EV56)  UNAME_MACHINE=alphaev56 ;;
+         PCA56) UNAME_MACHINE=alphapca56 ;;
+         PCA57) UNAME_MACHINE=alphapca56 ;;
+         EV6)   UNAME_MACHINE=alphaev6 ;;
+         EV67)  UNAME_MACHINE=alphaev67 ;;
+         EV68*) UNAME_MACHINE=alphaev68 ;;
+        esac
+       objdump --private-headers /bin/sh | grep ld.so.1 >/dev/null
+       if test "$?" = 0 ; then LIBC="libc1" ; else LIBC="" ; fi
+       echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC}
+       exit ;;
+    parisc:Linux:*:* | hppa:Linux:*:*)
+       # Look for CPU level
+       case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in
+         PA7*) echo hppa1.1-unknown-linux-gnu ;;
+         PA8*) echo hppa2.0-unknown-linux-gnu ;;
+         *)    echo hppa-unknown-linux-gnu ;;
+       esac
+       exit ;;
+    parisc64:Linux:*:* | hppa64:Linux:*:*)
+       echo hppa64-unknown-linux-gnu
+       exit ;;
+    s390:Linux:*:* | s390x:Linux:*:*)
+       echo ${UNAME_MACHINE}-ibm-linux
+       exit ;;
+    sh64*:Linux:*:*)
+       echo ${UNAME_MACHINE}-unknown-linux-gnu
+       exit ;;
+    sh*:Linux:*:*)
+       echo ${UNAME_MACHINE}-unknown-linux-gnu
+       exit ;;
+    sparc:Linux:*:* | sparc64:Linux:*:*)
+       echo ${UNAME_MACHINE}-unknown-linux-gnu
+       exit ;;
+    vax:Linux:*:*)
+       echo ${UNAME_MACHINE}-dec-linux-gnu
+       exit ;;
+    x86_64:Linux:*:*)
+       echo x86_64-unknown-linux-gnu
+       exit ;;
+    i*86:Linux:*:*)
+       # The BFD linker knows what the default object file format is, so
+       # first see if it will tell us. cd to the root directory to prevent
+       # problems with other programs or directories called `ld' in the path.
+       # Set LC_ALL=C to ensure ld outputs messages in English.
+       ld_supported_targets=`cd /; LC_ALL=C ld --help 2>&1 \
+                        | sed -ne '/supported targets:/!d
+                                   s/[         ][      ]*/ /g
+                                   s/.*supported targets: *//
+                                   s/ .*//
+                                   p'`
+        case "$ld_supported_targets" in
+         elf32-i386)
+               TENTATIVE="${UNAME_MACHINE}-pc-linux-gnu"
+               ;;
+         a.out-i386-linux)
+               echo "${UNAME_MACHINE}-pc-linux-gnuaout"
+               exit ;;
+         coff-i386)
+               echo "${UNAME_MACHINE}-pc-linux-gnucoff"
+               exit ;;
+         "")
+               # Either a pre-BFD a.out linker (linux-gnuoldld) or
+               # one that does not give us useful --help.
+               echo "${UNAME_MACHINE}-pc-linux-gnuoldld"
+               exit ;;
+       esac
+       # Determine whether the default compiler is a.out or elf
+       eval $set_cc_for_build
+       sed 's/^        //' << EOF >$dummy.c
+       #include <features.h>
+       #ifdef __ELF__
+       # ifdef __GLIBC__
+       #  if __GLIBC__ >= 2
+       LIBC=gnu
+       #  else
+       LIBC=gnulibc1
+       #  endif
+       # else
+       LIBC=gnulibc1
+       # endif
+       #else
+       #if defined(__INTEL_COMPILER) || defined(__PGI)
+       LIBC=gnu
+       #else
+       LIBC=gnuaout
+       #endif
+       #endif
+       #ifdef __dietlibc__
+       LIBC=dietlibc
+       #endif
+EOF
+       eval "`$CC_FOR_BUILD -E $dummy.c 2>/dev/null | sed -n '/^LIBC/{s: ::g;p;}'`"
+       test x"${LIBC}" != x && {
+               echo "${UNAME_MACHINE}-pc-linux-${LIBC}"
+               exit
+       }
+       test x"${TENTATIVE}" != x && { echo "${TENTATIVE}"; exit; }
+       ;;
+    i*86:DYNIX/ptx:4*:*)
+       # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there.
+       # earlier versions are messed up and put the nodename in both
+       # sysname and nodename.
+       echo i386-sequent-sysv4
+       exit ;;
+    i*86:UNIX_SV:4.2MP:2.*)
+        # Unixware is an offshoot of SVR4, but it has its own version
+        # number series starting with 2...
+        # I am not positive that other SVR4 systems won't match this,
+       # I just have to hope.  -- rms.
+        # Use sysv4.2uw... so that sysv4* matches it.
+       echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION}
+       exit ;;
+    i*86:OS/2:*:*)
+       # If we were able to find `uname', then EMX Unix compatibility
+       # is probably installed.
+       echo ${UNAME_MACHINE}-pc-os2-emx
+       exit ;;
+    i*86:XTS-300:*:STOP)
+       echo ${UNAME_MACHINE}-unknown-stop
+       exit ;;
+    i*86:atheos:*:*)
+       echo ${UNAME_MACHINE}-unknown-atheos
+       exit ;;
+    i*86:syllable:*:*)
+       echo ${UNAME_MACHINE}-pc-syllable
+       exit ;;
+    i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.0*:*)
+       echo i386-unknown-lynxos${UNAME_RELEASE}
+       exit ;;
+    i*86:*DOS:*:*)
+       echo ${UNAME_MACHINE}-pc-msdosdjgpp
+       exit ;;
+    i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*)
+       UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'`
+       if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then
+               echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL}
+       else
+               echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL}
+       fi
+       exit ;;
+    i*86:*:5:[678]*)
+       # UnixWare 7.x, OpenUNIX and OpenServer 6.
+       case `/bin/uname -X | grep "^Machine"` in
+           *486*)           UNAME_MACHINE=i486 ;;
+           *Pentium)        UNAME_MACHINE=i586 ;;
+           *Pent*|*Celeron) UNAME_MACHINE=i686 ;;
+       esac
+       echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION}
+       exit ;;
+    i*86:*:3.2:*)
+       if test -f /usr/options/cb.name; then
+               UNAME_REL=`sed -n 's/.*Version //p' </usr/options/cb.name`
+               echo ${UNAME_MACHINE}-pc-isc$UNAME_REL
+       elif /bin/uname -X 2>/dev/null >/dev/null ; then
+               UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')`
+               (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486
+               (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \
+                       && UNAME_MACHINE=i586
+               (/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \
+                       && UNAME_MACHINE=i686
+               (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \
+                       && UNAME_MACHINE=i686
+               echo ${UNAME_MACHINE}-pc-sco$UNAME_REL
+       else
+               echo ${UNAME_MACHINE}-pc-sysv32
+       fi
+       exit ;;
+    pc:*:*:*)
+       # Left here for compatibility:
+        # uname -m prints for DJGPP always 'pc', but it prints nothing about
+        # the processor, so we play safe by assuming i386.
+       echo i386-pc-msdosdjgpp
+        exit ;;
+    Intel:Mach:3*:*)
+       echo i386-pc-mach3
+       exit ;;
+    paragon:*:*:*)
+       echo i860-intel-osf1
+       exit ;;
+    i860:*:4.*:*) # i860-SVR4
+       if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then
+         echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4
+       else # Add other i860-SVR4 vendors below as they are discovered.
+         echo i860-unknown-sysv${UNAME_RELEASE}  # Unknown i860-SVR4
+       fi
+       exit ;;
+    mini*:CTIX:SYS*5:*)
+       # "miniframe"
+       echo m68010-convergent-sysv
+       exit ;;
+    mc68k:UNIX:SYSTEM5:3.51m)
+       echo m68k-convergent-sysv
+       exit ;;
+    M680?0:D-NIX:5.3:*)
+       echo m68k-diab-dnix
+       exit ;;
+    M68*:*:R3V[5678]*:*)
+       test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;;
+    3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0)
+       OS_REL=''
+       test -r /etc/.relid \
+       && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid`
+       /bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+         && { echo i486-ncr-sysv4.3${OS_REL}; exit; }
+       /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \
+         && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;;
+    3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*)
+        /bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+          && { echo i486-ncr-sysv4; exit; } ;;
+    m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*)
+       echo m68k-unknown-lynxos${UNAME_RELEASE}
+       exit ;;
+    mc68030:UNIX_System_V:4.*:*)
+       echo m68k-atari-sysv4
+       exit ;;
+    TSUNAMI:LynxOS:2.*:*)
+       echo sparc-unknown-lynxos${UNAME_RELEASE}
+       exit ;;
+    rs6000:LynxOS:2.*:*)
+       echo rs6000-unknown-lynxos${UNAME_RELEASE}
+       exit ;;
+    PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.0*:*)
+       echo powerpc-unknown-lynxos${UNAME_RELEASE}
+       exit ;;
+    SM[BE]S:UNIX_SV:*:*)
+       echo mips-dde-sysv${UNAME_RELEASE}
+       exit ;;
+    RM*:ReliantUNIX-*:*:*)
+       echo mips-sni-sysv4
+       exit ;;
+    RM*:SINIX-*:*:*)
+       echo mips-sni-sysv4
+       exit ;;
+    *:SINIX-*:*:*)
+       if uname -p 2>/dev/null >/dev/null ; then
+               UNAME_MACHINE=`(uname -p) 2>/dev/null`
+               echo ${UNAME_MACHINE}-sni-sysv4
+       else
+               echo ns32k-sni-sysv
+       fi
+       exit ;;
+    PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort
+                      # says <Richard.M.Bartel@ccMail.Census.GOV>
+        echo i586-unisys-sysv4
+        exit ;;
+    *:UNIX_System_V:4*:FTX*)
+       # From Gerald Hewes <hewes@openmarket.com>.
+       # How about differentiating between stratus architectures? -djm
+       echo hppa1.1-stratus-sysv4
+       exit ;;
+    *:*:*:FTX*)
+       # From seanf@swdc.stratus.com.
+       echo i860-stratus-sysv4
+       exit ;;
+    i*86:VOS:*:*)
+       # From Paul.Green@stratus.com.
+       echo ${UNAME_MACHINE}-stratus-vos
+       exit ;;
+    *:VOS:*:*)
+       # From Paul.Green@stratus.com.
+       echo hppa1.1-stratus-vos
+       exit ;;
+    mc68*:A/UX:*:*)
+       echo m68k-apple-aux${UNAME_RELEASE}
+       exit ;;
+    news*:NEWS-OS:6*:*)
+       echo mips-sony-newsos6
+       exit ;;
+    R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*)
+       if [ -d /usr/nec ]; then
+               echo mips-nec-sysv${UNAME_RELEASE}
+       else
+               echo mips-unknown-sysv${UNAME_RELEASE}
+       fi
+        exit ;;
+    BeBox:BeOS:*:*)    # BeOS running on hardware made by Be, PPC only.
+       echo powerpc-be-beos
+       exit ;;
+    BeMac:BeOS:*:*)    # BeOS running on Mac or Mac clone, PPC only.
+       echo powerpc-apple-beos
+       exit ;;
+    BePC:BeOS:*:*)     # BeOS running on Intel PC compatible.
+       echo i586-pc-beos
+       exit ;;
+    SX-4:SUPER-UX:*:*)
+       echo sx4-nec-superux${UNAME_RELEASE}
+       exit ;;
+    SX-5:SUPER-UX:*:*)
+       echo sx5-nec-superux${UNAME_RELEASE}
+       exit ;;
+    SX-6:SUPER-UX:*:*)
+       echo sx6-nec-superux${UNAME_RELEASE}
+       exit ;;
+    Power*:Rhapsody:*:*)
+       echo powerpc-apple-rhapsody${UNAME_RELEASE}
+       exit ;;
+    *:Rhapsody:*:*)
+       echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE}
+       exit ;;
+    *:Darwin:*:*)
+       UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown
+       case $UNAME_PROCESSOR in
+           unknown) UNAME_PROCESSOR=powerpc ;;
+       esac
+       echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE}
+       exit ;;
+    *:procnto*:*:* | *:QNX:[0123456789]*:*)
+       UNAME_PROCESSOR=`uname -p`
+       if test "$UNAME_PROCESSOR" = "x86"; then
+               UNAME_PROCESSOR=i386
+               UNAME_MACHINE=pc
+       fi
+       echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE}
+       exit ;;
+    *:QNX:*:4*)
+       echo i386-pc-qnx
+       exit ;;
+    NSE-?:NONSTOP_KERNEL:*:*)
+       echo nse-tandem-nsk${UNAME_RELEASE}
+       exit ;;
+    NSR-?:NONSTOP_KERNEL:*:*)
+       echo nsr-tandem-nsk${UNAME_RELEASE}
+       exit ;;
+    *:NonStop-UX:*:*)
+       echo mips-compaq-nonstopux
+       exit ;;
+    BS2000:POSIX*:*:*)
+       echo bs2000-siemens-sysv
+       exit ;;
+    DS/*:UNIX_System_V:*:*)
+       echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE}
+       exit ;;
+    *:Plan9:*:*)
+       # "uname -m" is not consistent, so use $cputype instead. 386
+       # is converted to i386 for consistency with other x86
+       # operating systems.
+       if test "$cputype" = "386"; then
+           UNAME_MACHINE=i386
+       else
+           UNAME_MACHINE="$cputype"
+       fi
+       echo ${UNAME_MACHINE}-unknown-plan9
+       exit ;;
+    *:TOPS-10:*:*)
+       echo pdp10-unknown-tops10
+       exit ;;
+    *:TENEX:*:*)
+       echo pdp10-unknown-tenex
+       exit ;;
+    KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*)
+       echo pdp10-dec-tops20
+       exit ;;
+    XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*)
+       echo pdp10-xkl-tops20
+       exit ;;
+    *:TOPS-20:*:*)
+       echo pdp10-unknown-tops20
+       exit ;;
+    *:ITS:*:*)
+       echo pdp10-unknown-its
+       exit ;;
+    SEI:*:*:SEIUX)
+        echo mips-sei-seiux${UNAME_RELEASE}
+       exit ;;
+    *:DragonFly:*:*)
+       echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`
+       exit ;;
+    *:*VMS:*:*)
+       UNAME_MACHINE=`(uname -p) 2>/dev/null`
+       case "${UNAME_MACHINE}" in
+           A*) echo alpha-dec-vms ; exit ;;
+           I*) echo ia64-dec-vms ; exit ;;
+           V*) echo vax-dec-vms ; exit ;;
+       esac ;;
+    *:XENIX:*:SysV)
+       echo i386-pc-xenix
+       exit ;;
+    i*86:skyos:*:*)
+       echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE}` | sed -e 's/ .*$//'
+       exit ;;
+    i*86:rdos:*:*)
+       echo ${UNAME_MACHINE}-pc-rdos
+       exit ;;
+esac
+
+#echo '(No uname command or uname output not recognized.)' 1>&2
+#echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2
+
+eval $set_cc_for_build
+cat >$dummy.c <<EOF
+#ifdef _SEQUENT_
+# include <sys/types.h>
+# include <sys/utsname.h>
+#endif
+main ()
+{
+#if defined (sony)
+#if defined (MIPSEB)
+  /* BFD wants "bsd" instead of "newsos".  Perhaps BFD should be changed,
+     I don't know....  */
+  printf ("mips-sony-bsd\n"); exit (0);
+#else
+#include <sys/param.h>
+  printf ("m68k-sony-newsos%s\n",
+#ifdef NEWSOS4
+          "4"
+#else
+         ""
+#endif
+         ); exit (0);
+#endif
+#endif
+
+#if defined (__arm) && defined (__acorn) && defined (__unix)
+  printf ("arm-acorn-riscix\n"); exit (0);
+#endif
+
+#if defined (hp300) && !defined (hpux)
+  printf ("m68k-hp-bsd\n"); exit (0);
+#endif
+
+#if defined (NeXT)
+#if !defined (__ARCHITECTURE__)
+#define __ARCHITECTURE__ "m68k"
+#endif
+  int version;
+  version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`;
+  if (version < 4)
+    printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version);
+  else
+    printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version);
+  exit (0);
+#endif
+
+#if defined (MULTIMAX) || defined (n16)
+#if defined (UMAXV)
+  printf ("ns32k-encore-sysv\n"); exit (0);
+#else
+#if defined (CMU)
+  printf ("ns32k-encore-mach\n"); exit (0);
+#else
+  printf ("ns32k-encore-bsd\n"); exit (0);
+#endif
+#endif
+#endif
+
+#if defined (__386BSD__)
+  printf ("i386-pc-bsd\n"); exit (0);
+#endif
+
+#if defined (sequent)
+#if defined (i386)
+  printf ("i386-sequent-dynix\n"); exit (0);
+#endif
+#if defined (ns32000)
+  printf ("ns32k-sequent-dynix\n"); exit (0);
+#endif
+#endif
+
+#if defined (_SEQUENT_)
+    struct utsname un;
+
+    uname(&un);
+
+    if (strncmp(un.version, "V2", 2) == 0) {
+       printf ("i386-sequent-ptx2\n"); exit (0);
+    }
+    if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */
+       printf ("i386-sequent-ptx1\n"); exit (0);
+    }
+    printf ("i386-sequent-ptx\n"); exit (0);
+
+#endif
+
+#if defined (vax)
+# if !defined (ultrix)
+#  include <sys/param.h>
+#  if defined (BSD)
+#   if BSD == 43
+      printf ("vax-dec-bsd4.3\n"); exit (0);
+#   else
+#    if BSD == 199006
+      printf ("vax-dec-bsd4.3reno\n"); exit (0);
+#    else
+      printf ("vax-dec-bsd\n"); exit (0);
+#    endif
+#   endif
+#  else
+    printf ("vax-dec-bsd\n"); exit (0);
+#  endif
+# else
+    printf ("vax-dec-ultrix\n"); exit (0);
+# endif
+#endif
+
+#if defined (alliant) && defined (i860)
+  printf ("i860-alliant-bsd\n"); exit (0);
+#endif
+
+  exit (1);
+}
+EOF
+
+$CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null && SYSTEM_NAME=`$dummy` &&
+       { echo "$SYSTEM_NAME"; exit; }
+
+# Apollos put the system type in the environment.
+
+test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit; }
+
+# Convex versions that predate uname can use getsysinfo(1)
+
+if [ -x /usr/convex/getsysinfo ]
+then
+    case `getsysinfo -f cpu_type` in
+    c1*)
+       echo c1-convex-bsd
+       exit ;;
+    c2*)
+       if getsysinfo -f scalar_acc
+       then echo c32-convex-bsd
+       else echo c2-convex-bsd
+       fi
+       exit ;;
+    c34*)
+       echo c34-convex-bsd
+       exit ;;
+    c38*)
+       echo c38-convex-bsd
+       exit ;;
+    c4*)
+       echo c4-convex-bsd
+       exit ;;
+    esac
+fi
+
+cat >&2 <<EOF
+$0: unable to guess system type
+
+This script, last modified $timestamp, has failed to recognize
+the operating system you are using. It is advised that you
+download the most up to date version of the config scripts from
+
+  http://savannah.gnu.org/cgi-bin/viewcvs/*checkout*/config/config/config.guess
+and
+  http://savannah.gnu.org/cgi-bin/viewcvs/*checkout*/config/config/config.sub
+
+If the version you run ($0) is already up to date, please
+send the following data and any information you think might be
+pertinent to <config-patches@gnu.org> in order to provide the needed
+information to handle your system.
+
+config.guess timestamp = $timestamp
+
+uname -m = `(uname -m) 2>/dev/null || echo unknown`
+uname -r = `(uname -r) 2>/dev/null || echo unknown`
+uname -s = `(uname -s) 2>/dev/null || echo unknown`
+uname -v = `(uname -v) 2>/dev/null || echo unknown`
+
+/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null`
+/bin/uname -X     = `(/bin/uname -X) 2>/dev/null`
+
+hostinfo               = `(hostinfo) 2>/dev/null`
+/bin/universe          = `(/bin/universe) 2>/dev/null`
+/usr/bin/arch -k       = `(/usr/bin/arch -k) 2>/dev/null`
+/bin/arch              = `(/bin/arch) 2>/dev/null`
+/usr/bin/oslevel       = `(/usr/bin/oslevel) 2>/dev/null`
+/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null`
+
+UNAME_MACHINE = ${UNAME_MACHINE}
+UNAME_RELEASE = ${UNAME_RELEASE}
+UNAME_SYSTEM  = ${UNAME_SYSTEM}
+UNAME_VERSION = ${UNAME_VERSION}
+EOF
+
+exit 1
+
+# Local variables:
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "timestamp='"
+# time-stamp-format: "%:y-%02m-%02d"
+# time-stamp-end: "'"
+# End:
diff --git a/config.h.in b/config.h.in
new file mode 100644 (file)
index 0000000..7c2c789
--- /dev/null
@@ -0,0 +1,232 @@
+/* config.h.in.  Generated from configure.in by autoheader.  */
+
+/* Define if you have (reliable) BSD signals. */
+#undef BSD_RELIABLE_SIGNALS
+
+/* Configuration file name */
+#undef CPATH
+
+/* Enable debugging code */
+#undef DEBUGMODE
+
+/* Domain name to be used for some statistics gathering */
+#undef DOMAINNAME
+
+/* Path to data directory */
+#undef DPATH
+
+/* Define to implement epoll system calls */
+#undef EPOLL_NEED_BODY
+
+/* Force inlining for a few critical functions */
+#undef FORCEINLINE
+
+/* Define to 1 if you have the <crypt.h> header file. */
+#undef HAVE_CRYPT_H
+
+/* Define to 1 if you have the `getrusage' function. */
+#undef HAVE_GETRUSAGE
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#undef HAVE_INTTYPES_H
+
+/* Define to 1 if you have the `kqueue' function. */
+#undef HAVE_KQUEUE
+
+/* Define to 1 if you have the `nsl' library (-lnsl). */
+#undef HAVE_LIBNSL
+
+/* Define to 1 if you have the `resolv' library (-lresolv). */
+#undef HAVE_LIBRESOLV
+
+/* Define to 1 if you have the `socket' library (-lsocket). */
+#undef HAVE_LIBSOCKET
+
+/* Define to 1 if you have the <memory.h> header file. */
+#undef HAVE_MEMORY_H
+
+/* Define to 1 if you have the <poll.h> header file. */
+#undef HAVE_POLL_H
+
+/* Define to 1 if system calls automatically restart after interruption by a
+   signal. */
+#undef HAVE_RESTARTABLE_SYSCALLS
+
+/* Define to 1 if you have the `setrlimit' function. */
+#undef HAVE_SETRLIMIT
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#undef HAVE_STDINT_H
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#undef HAVE_STDLIB_H
+
+/* Define to 1 if you have the <strings.h> header file. */
+#undef HAVE_STRINGS_H
+
+/* Define to 1 if you have the <string.h> header file. */
+#undef HAVE_STRING_H
+
+/* Define to 1 if you have the <sys/devpoll.h> header file. */
+#undef HAVE_SYS_DEVPOLL_H
+
+/* Define to 1 if you have the <sys/epoll.h> header file. */
+#undef HAVE_SYS_EPOLL_H
+
+/* Define to 1 if you have the <sys/event.h> header file. */
+#undef HAVE_SYS_EVENT_H
+
+/* Define to 1 if you have the <sys/param.h> header file. */
+#undef HAVE_SYS_PARAM_H
+
+/* Define to 1 if you have the <sys/resource.h> header file. */
+#undef HAVE_SYS_RESOURCE_H
+
+/* Define to 1 if you have the <sys/socket.h> header file. */
+#undef HAVE_SYS_SOCKET_H
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#undef HAVE_SYS_STAT_H
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#undef HAVE_SYS_TYPES_H
+
+/* Define to 1 if you have <sys/wait.h> that is POSIX.1 compatible. */
+#undef HAVE_SYS_WAIT_H
+
+/* Define to 1 if you have the `times' function. */
+#undef HAVE_TIMES
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#undef HAVE_UNISTD_H
+
+/* Define if we have va_copy */
+#undef HAVE_VA_COPY
+
+/* Define if we have __va_copy */
+#undef HAVE___VA_COPY
+
+/* Enable IPv6 support */
+#undef IPV6
+
+/* Define if building on Solaris */
+#undef IRCU_SOLARIS
+
+/* Path to debugging log file */
+#undef LPATH
+
+/* Maximum number of network connections */
+#undef MAXCONNECTIONS
+
+/* Define if you have BSD non-blocking sockets. */
+#undef NBLOCK_BSD
+
+/* Define if you have POSIX non-blocking sockets. */
+#undef NBLOCK_POSIX
+
+/* Define if you have SysV non-blocking sockets. */
+#undef NBLOCK_SYSV
+
+/* Disable assertions */
+#undef NDEBUG
+
+/* Define to the address where bug reports for this package should be sent. */
+#undef PACKAGE_BUGREPORT
+
+/* Define to the full name of this package. */
+#undef PACKAGE_NAME
+
+/* Define to the full name and version of this package. */
+#undef PACKAGE_STRING
+
+/* Define to the one symbol short name of this package. */
+#undef PACKAGE_TARNAME
+
+/* Define to the version of this package. */
+#undef PACKAGE_VERSION
+
+/* Define if you have POSIX signals. */
+#undef POSIX_SIGNALS
+
+/* The size of a `int', as computed by sizeof. */
+#undef SIZEOF_INT
+
+/* The size of a `int64_t', as computed by sizeof. */
+#undef SIZEOF_INT64_T
+
+/* The size of a `long', as computed by sizeof. */
+#undef SIZEOF_LONG
+
+/* The size of a `long long', as computed by sizeof. */
+#undef SIZEOF_LONG_LONG
+
+/* The size of a `short', as computed by sizeof. */
+#undef SIZEOF_SHORT
+
+/* The size of a `void *', as computed by sizeof. */
+#undef SIZEOF_VOID_P
+
+/* Path to executable for restarts */
+#undef SPATH
+
+/* Define to 1 if you have the ANSI C header files. */
+#undef STDC_HEADERS
+
+/* Define if you have (unreliable) SysV signals. */
+#undef SYSV_UNRELIABLE_SIGNALS
+
+/* Define to 1 if you can safely include both <sys/time.h> and <time.h>. */
+#undef TIME_WITH_SYS_TIME
+
+/* Define to 1 if your <sys/time.h> declares `struct tm'. */
+#undef TM_IN_SYS_TIME
+
+/* Define to enable the /dev/poll engine */
+#undef USE_DEVPOLL
+
+/* Define to enable the epoll engine */
+#undef USE_EPOLL
+
+/* Define to enable the kqueue engine */
+#undef USE_KQUEUE
+
+/* Specify whether or not to use poll() */
+#undef USE_POLL
+
+/* Define to 1 if your processor stores words with the most significant byte
+   first (like Motorola and SPARC, unlike Intel and VAX). */
+#undef WORDS_BIGENDIAN
+
+/* Define to 1 if `lex' declares `yytext' as a `char *' by default, not a
+   `char[]'. */
+#undef YYTEXT_POINTER
+
+/* Define to `int' if <sys/types.h> doesn't define. */
+#undef gid_t
+
+/* Define to `short' if <sys/types.h> does not define. */
+#undef int16_t
+
+/* Define to `long' if <sys/types.h> does not define. */
+#undef int32_t
+
+/* Define to `long long' if <sys/types.h> does not define. */
+#undef int64_t
+
+/* Define to `unsigned' if <sys/types.h> does not define. */
+#undef size_t
+
+/* type to use in place of socklen_t if not defined */
+#undef socklen_t
+
+/* Define to `int' if <sys/types.h> doesn't define. */
+#undef uid_t
+
+/* Define to `unsigned short' if <sys/types.h> does not define. */
+#undef uint16_t
+
+/* Define to `unsigned long' if <sys/types.h> does not define. */
+#undef uint32_t
+
+/* Define to `unsigned long long' if <sys/types.h> does not define. */
+#undef uint64_t
diff --git a/config.sub b/config.sub
new file mode 100644 (file)
index 0000000..8f7b738
--- /dev/null
@@ -0,0 +1,1605 @@
+#! /bin/sh
+# Configuration validation subroutine script.
+#   Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
+#   2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
+
+timestamp='2005-12-23'
+
+# This file is (in principle) common to ALL GNU software.
+# The presence of a machine in this file suggests that SOME GNU software
+# can handle that machine.  It does not imply ALL GNU software can.
+#
+# This file is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
+# 02110-1301, USA.
+#
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+
+# Please send patches to <config-patches@gnu.org>.  Submit a context
+# diff and a properly formatted ChangeLog entry.
+#
+# Configuration subroutine to validate and canonicalize a configuration type.
+# Supply the specified configuration type as an argument.
+# If it is invalid, we print an error message on stderr and exit with code 1.
+# Otherwise, we print the canonical config type on stdout and succeed.
+
+# This file is supposed to be the same for all GNU packages
+# and recognize all the CPU types, system types and aliases
+# that are meaningful with *any* GNU software.
+# Each package is responsible for reporting which valid configurations
+# it does not support.  The user should be able to distinguish
+# a failure to support a valid configuration from a meaningless
+# configuration.
+
+# The goal of this file is to map all the various variations of a given
+# machine specification into a single specification in the form:
+#      CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM
+# or in some cases, the newer four-part form:
+#      CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM
+# It is wrong to echo any other type of specification.
+
+me=`echo "$0" | sed -e 's,.*/,,'`
+
+usage="\
+Usage: $0 [OPTION] CPU-MFR-OPSYS
+       $0 [OPTION] ALIAS
+
+Canonicalize a configuration name.
+
+Operation modes:
+  -h, --help         print this help, then exit
+  -t, --time-stamp   print date of last modification, then exit
+  -v, --version      print version number, then exit
+
+Report bugs and patches to <config-patches@gnu.org>."
+
+version="\
+GNU config.sub ($timestamp)
+
+Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005
+Free Software Foundation, Inc.
+
+This is free software; see the source for copying conditions.  There is NO
+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
+
+help="
+Try \`$me --help' for more information."
+
+# Parse command line
+while test $# -gt 0 ; do
+  case $1 in
+    --time-stamp | --time* | -t )
+       echo "$timestamp" ; exit ;;
+    --version | -v )
+       echo "$version" ; exit ;;
+    --help | --h* | -h )
+       echo "$usage"; exit ;;
+    -- )     # Stop option processing
+       shift; break ;;
+    - )        # Use stdin as input.
+       break ;;
+    -* )
+       echo "$me: invalid option $1$help"
+       exit 1 ;;
+
+    *local*)
+       # First pass through any local machine types.
+       echo $1
+       exit ;;
+
+    * )
+       break ;;
+  esac
+done
+
+case $# in
+ 0) echo "$me: missing argument$help" >&2
+    exit 1;;
+ 1) ;;
+ *) echo "$me: too many arguments$help" >&2
+    exit 1;;
+esac
+
+# Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any).
+# Here we must recognize all the valid KERNEL-OS combinations.
+maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'`
+case $maybe_os in
+  nto-qnx* | linux-gnu* | linux-dietlibc | linux-newlib* | linux-uclibc* | \
+  uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | knetbsd*-gnu* | netbsd*-gnu* | \
+  storm-chaos* | os2-emx* | rtmk-nova*)
+    os=-$maybe_os
+    basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`
+    ;;
+  *)
+    basic_machine=`echo $1 | sed 's/-[^-]*$//'`
+    if [ $basic_machine != $1 ]
+    then os=`echo $1 | sed 's/.*-/-/'`
+    else os=; fi
+    ;;
+esac
+
+### Let's recognize common machines as not being operating systems so
+### that things like config.sub decstation-3100 work.  We also
+### recognize some manufacturers as not being operating systems, so we
+### can provide default operating systems below.
+case $os in
+       -sun*os*)
+               # Prevent following clause from handling this invalid input.
+               ;;
+       -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \
+       -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \
+       -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \
+       -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\
+       -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \
+       -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \
+       -apple | -axis | -knuth | -cray)
+               os=
+               basic_machine=$1
+               ;;
+       -sim | -cisco | -oki | -wec | -winbond)
+               os=
+               basic_machine=$1
+               ;;
+       -scout)
+               ;;
+       -wrs)
+               os=-vxworks
+               basic_machine=$1
+               ;;
+       -chorusos*)
+               os=-chorusos
+               basic_machine=$1
+               ;;
+       -chorusrdb)
+               os=-chorusrdb
+               basic_machine=$1
+               ;;
+       -hiux*)
+               os=-hiuxwe2
+               ;;
+       -sco6)
+               os=-sco5v6
+               basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+               ;;
+       -sco5)
+               os=-sco3.2v5
+               basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+               ;;
+       -sco4)
+               os=-sco3.2v4
+               basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+               ;;
+       -sco3.2.[4-9]*)
+               os=`echo $os | sed -e 's/sco3.2./sco3.2v/'`
+               basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+               ;;
+       -sco3.2v[4-9]*)
+               # Don't forget version if it is 3.2v4 or newer.
+               basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+               ;;
+       -sco5v6*)
+               # Don't forget version if it is 3.2v4 or newer.
+               basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+               ;;
+       -sco*)
+               os=-sco3.2v2
+               basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+               ;;
+       -udk*)
+               basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+               ;;
+       -isc)
+               os=-isc2.2
+               basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+               ;;
+       -clix*)
+               basic_machine=clipper-intergraph
+               ;;
+       -isc*)
+               basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+               ;;
+       -lynx*)
+               os=-lynxos
+               ;;
+       -ptx*)
+               basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'`
+               ;;
+       -windowsnt*)
+               os=`echo $os | sed -e 's/windowsnt/winnt/'`
+               ;;
+       -psos*)
+               os=-psos
+               ;;
+       -mint | -mint[0-9]*)
+               basic_machine=m68k-atari
+               os=-mint
+               ;;
+esac
+
+# Decode aliases for certain CPU-COMPANY combinations.
+case $basic_machine in
+       # Recognize the basic CPU types without company name.
+       # Some are omitted here because they have special meanings below.
+       1750a | 580 \
+       | a29k \
+       | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \
+       | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \
+       | am33_2.0 \
+       | arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr \
+       | bfin \
+       | c4x | clipper \
+       | d10v | d30v | dlx | dsp16xx \
+       | fr30 | frv \
+       | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \
+       | i370 | i860 | i960 | ia64 \
+       | ip2k | iq2000 \
+       | m32r | m32rle | m68000 | m68k | m88k | maxq | mb | microblaze | mcore \
+       | mips | mipsbe | mipseb | mipsel | mipsle \
+       | mips16 \
+       | mips64 | mips64el \
+       | mips64vr | mips64vrel \
+       | mips64orion | mips64orionel \
+       | mips64vr4100 | mips64vr4100el \
+       | mips64vr4300 | mips64vr4300el \
+       | mips64vr5000 | mips64vr5000el \
+       | mips64vr5900 | mips64vr5900el \
+       | mipsisa32 | mipsisa32el \
+       | mipsisa32r2 | mipsisa32r2el \
+       | mipsisa64 | mipsisa64el \
+       | mipsisa64r2 | mipsisa64r2el \
+       | mipsisa64sb1 | mipsisa64sb1el \
+       | mipsisa64sr71k | mipsisa64sr71kel \
+       | mipstx39 | mipstx39el \
+       | mn10200 | mn10300 \
+       | mt \
+       | msp430 \
+       | ns16k | ns32k \
+       | or32 \
+       | pdp10 | pdp11 | pj | pjl \
+       | powerpc | powerpc64 | powerpc64le | powerpcle | ppcbe \
+       | pyramid \
+       | sh | sh[1234] | sh[24]a | sh[23]e | sh[34]eb | shbe | shle | sh[1234]le | sh3ele \
+       | sh64 | sh64le \
+       | sparc | sparc64 | sparc64b | sparc86x | sparclet | sparclite \
+       | sparcv8 | sparcv9 | sparcv9b \
+       | strongarm \
+       | tahoe | thumb | tic4x | tic80 | tron \
+       | v850 | v850e \
+       | we32k \
+       | x86 | xscale | xscalee[bl] | xstormy16 | xtensa \
+       | z8k)
+               basic_machine=$basic_machine-unknown
+               ;;
+       m32c)
+               basic_machine=$basic_machine-unknown
+               ;;
+       m6811 | m68hc11 | m6812 | m68hc12)
+               # Motorola 68HC11/12.
+               basic_machine=$basic_machine-unknown
+               os=-none
+               ;;
+       m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k)
+               ;;
+       ms1)
+               basic_machine=mt-unknown
+               ;;
+
+       # We use `pc' rather than `unknown'
+       # because (1) that's what they normally are, and
+       # (2) the word "unknown" tends to confuse beginning users.
+       i*86 | x86_64)
+         basic_machine=$basic_machine-pc
+         ;;
+       # Object if more than one company name word.
+       *-*-*)
+               echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
+               exit 1
+               ;;
+       # Recognize the basic CPU types with company name.
+       580-* \
+       | a29k-* \
+       | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \
+       | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \
+       | alphapca5[67]-* | alpha64pca5[67]-* | arc-* \
+       | arm-*  | armbe-* | armle-* | armeb-* | armv*-* \
+       | avr-* \
+       | bfin-* | bs2000-* \
+       | c[123]* | c30-* | [cjt]90-* | c4x-* | c54x-* | c55x-* | c6x-* \
+       | clipper-* | craynv-* | cydra-* \
+       | d10v-* | d30v-* | dlx-* \
+       | elxsi-* \
+       | f30[01]-* | f700-* | fr30-* | frv-* | fx80-* \
+       | h8300-* | h8500-* \
+       | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \
+       | i*86-* | i860-* | i960-* | ia64-* \
+       | ip2k-* | iq2000-* \
+       | m32r-* | m32rle-* \
+       | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \
+       | m88110-* | m88k-* | maxq-* | mcore-* \
+       | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \
+       | mips16-* \
+       | mips64-* | mips64el-* \
+       | mips64vr-* | mips64vrel-* \
+       | mips64orion-* | mips64orionel-* \
+       | mips64vr4100-* | mips64vr4100el-* \
+       | mips64vr4300-* | mips64vr4300el-* \
+       | mips64vr5000-* | mips64vr5000el-* \
+       | mips64vr5900-* | mips64vr5900el-* \
+       | mipsisa32-* | mipsisa32el-* \
+       | mipsisa32r2-* | mipsisa32r2el-* \
+       | mipsisa64-* | mipsisa64el-* \
+       | mipsisa64r2-* | mipsisa64r2el-* \
+       | mipsisa64sb1-* | mipsisa64sb1el-* \
+       | mipsisa64sr71k-* | mipsisa64sr71kel-* \
+       | mipstx39-* | mipstx39el-* \
+       | mmix-* \
+       | mt-* \
+       | msp430-* \
+       | none-* | np1-* | ns16k-* | ns32k-* \
+       | orion-* \
+       | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \
+       | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* | ppcbe-* \
+       | pyramid-* \
+       | romp-* | rs6000-* \
+       | sh-* | sh[1234]-* | sh[24]a-* | sh[23]e-* | sh[34]eb-* | shbe-* \
+       | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \
+       | sparc-* | sparc64-* | sparc64b-* | sparc86x-* | sparclet-* \
+       | sparclite-* \
+       | sparcv8-* | sparcv9-* | sparcv9b-* | strongarm-* | sv1-* | sx?-* \
+       | tahoe-* | thumb-* \
+       | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \
+       | tron-* \
+       | v850-* | v850e-* | vax-* \
+       | we32k-* \
+       | x86-* | x86_64-* | xps100-* | xscale-* | xscalee[bl]-* \
+       | xstormy16-* | xtensa-* \
+       | ymp-* \
+       | z8k-*)
+               ;;
+       m32c-*)
+               ;;
+       # Recognize the various machine names and aliases which stand
+       # for a CPU type and a company and sometimes even an OS.
+       386bsd)
+               basic_machine=i386-unknown
+               os=-bsd
+               ;;
+       3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc)
+               basic_machine=m68000-att
+               ;;
+       3b*)
+               basic_machine=we32k-att
+               ;;
+       a29khif)
+               basic_machine=a29k-amd
+               os=-udi
+               ;;
+       abacus)
+               basic_machine=abacus-unknown
+               ;;
+       adobe68k)
+               basic_machine=m68010-adobe
+               os=-scout
+               ;;
+       alliant | fx80)
+               basic_machine=fx80-alliant
+               ;;
+       altos | altos3068)
+               basic_machine=m68k-altos
+               ;;
+       am29k)
+               basic_machine=a29k-none
+               os=-bsd
+               ;;
+       amd64)
+               basic_machine=x86_64-pc
+               ;;
+       amd64-*)
+               basic_machine=x86_64-`echo $basic_machine | sed 's/^[^-]*-//'`
+               ;;
+       amdahl)
+               basic_machine=580-amdahl
+               os=-sysv
+               ;;
+       amiga | amiga-*)
+               basic_machine=m68k-unknown
+               ;;
+       amigaos | amigados)
+               basic_machine=m68k-unknown
+               os=-amigaos
+               ;;
+       amigaunix | amix)
+               basic_machine=m68k-unknown
+               os=-sysv4
+               ;;
+       apollo68)
+               basic_machine=m68k-apollo
+               os=-sysv
+               ;;
+       apollo68bsd)
+               basic_machine=m68k-apollo
+               os=-bsd
+               ;;
+       aux)
+               basic_machine=m68k-apple
+               os=-aux
+               ;;
+       balance)
+               basic_machine=ns32k-sequent
+               os=-dynix
+               ;;
+       c90)
+               basic_machine=c90-cray
+               os=-unicos
+               ;;
+       convex-c1)
+               basic_machine=c1-convex
+               os=-bsd
+               ;;
+       convex-c2)
+               basic_machine=c2-convex
+               os=-bsd
+               ;;
+       convex-c32)
+               basic_machine=c32-convex
+               os=-bsd
+               ;;
+       convex-c34)
+               basic_machine=c34-convex
+               os=-bsd
+               ;;
+       convex-c38)
+               basic_machine=c38-convex
+               os=-bsd
+               ;;
+       cray | j90)
+               basic_machine=j90-cray
+               os=-unicos
+               ;;
+       craynv)
+               basic_machine=craynv-cray
+               os=-unicosmp
+               ;;
+       cr16c)
+               basic_machine=cr16c-unknown
+               os=-elf
+               ;;
+       crds | unos)
+               basic_machine=m68k-crds
+               ;;
+       crisv32 | crisv32-* | etraxfs*)
+               basic_machine=crisv32-axis
+               ;;
+       cris | cris-* | etrax*)
+               basic_machine=cris-axis
+               ;;
+       crx)
+               basic_machine=crx-unknown
+               os=-elf
+               ;;
+       da30 | da30-*)
+               basic_machine=m68k-da30
+               ;;
+       decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn)
+               basic_machine=mips-dec
+               ;;
+       decsystem10* | dec10*)
+               basic_machine=pdp10-dec
+               os=-tops10
+               ;;
+       decsystem20* | dec20*)
+               basic_machine=pdp10-dec
+               os=-tops20
+               ;;
+       delta | 3300 | motorola-3300 | motorola-delta \
+             | 3300-motorola | delta-motorola)
+               basic_machine=m68k-motorola
+               ;;
+       delta88)
+               basic_machine=m88k-motorola
+               os=-sysv3
+               ;;
+       djgpp)
+               basic_machine=i586-pc
+               os=-msdosdjgpp
+               ;;
+       dpx20 | dpx20-*)
+               basic_machine=rs6000-bull
+               os=-bosx
+               ;;
+       dpx2* | dpx2*-bull)
+               basic_machine=m68k-bull
+               os=-sysv3
+               ;;
+       ebmon29k)
+               basic_machine=a29k-amd
+               os=-ebmon
+               ;;
+       elxsi)
+               basic_machine=elxsi-elxsi
+               os=-bsd
+               ;;
+       encore | umax | mmax)
+               basic_machine=ns32k-encore
+               ;;
+       es1800 | OSE68k | ose68k | ose | OSE)
+               basic_machine=m68k-ericsson
+               os=-ose
+               ;;
+       fx2800)
+               basic_machine=i860-alliant
+               ;;
+       genix)
+               basic_machine=ns32k-ns
+               ;;
+       gmicro)
+               basic_machine=tron-gmicro
+               os=-sysv
+               ;;
+       go32)
+               basic_machine=i386-pc
+               os=-go32
+               ;;
+       h3050r* | hiux*)
+               basic_machine=hppa1.1-hitachi
+               os=-hiuxwe2
+               ;;
+       h8300hms)
+               basic_machine=h8300-hitachi
+               os=-hms
+               ;;
+       h8300xray)
+               basic_machine=h8300-hitachi
+               os=-xray
+               ;;
+       h8500hms)
+               basic_machine=h8500-hitachi
+               os=-hms
+               ;;
+       harris)
+               basic_machine=m88k-harris
+               os=-sysv3
+               ;;
+       hp300-*)
+               basic_machine=m68k-hp
+               ;;
+       hp300bsd)
+               basic_machine=m68k-hp
+               os=-bsd
+               ;;
+       hp300hpux)
+               basic_machine=m68k-hp
+               os=-hpux
+               ;;
+       hp3k9[0-9][0-9] | hp9[0-9][0-9])
+               basic_machine=hppa1.0-hp
+               ;;
+       hp9k2[0-9][0-9] | hp9k31[0-9])
+               basic_machine=m68000-hp
+               ;;
+       hp9k3[2-9][0-9])
+               basic_machine=m68k-hp
+               ;;
+       hp9k6[0-9][0-9] | hp6[0-9][0-9])
+               basic_machine=hppa1.0-hp
+               ;;
+       hp9k7[0-79][0-9] | hp7[0-79][0-9])
+               basic_machine=hppa1.1-hp
+               ;;
+       hp9k78[0-9] | hp78[0-9])
+               # FIXME: really hppa2.0-hp
+               basic_machine=hppa1.1-hp
+               ;;
+       hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893)
+               # FIXME: really hppa2.0-hp
+               basic_machine=hppa1.1-hp
+               ;;
+       hp9k8[0-9][13679] | hp8[0-9][13679])
+               basic_machine=hppa1.1-hp
+               ;;
+       hp9k8[0-9][0-9] | hp8[0-9][0-9])
+               basic_machine=hppa1.0-hp
+               ;;
+       hppa-next)
+               os=-nextstep3
+               ;;
+       hppaosf)
+               basic_machine=hppa1.1-hp
+               os=-osf
+               ;;
+       hppro)
+               basic_machine=hppa1.1-hp
+               os=-proelf
+               ;;
+       i370-ibm* | ibm*)
+               basic_machine=i370-ibm
+               ;;
+# I'm not sure what "Sysv32" means.  Should this be sysv3.2?
+       i*86v32)
+               basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+               os=-sysv32
+               ;;
+       i*86v4*)
+               basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+               os=-sysv4
+               ;;
+       i*86v)
+               basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+               os=-sysv
+               ;;
+       i*86sol2)
+               basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+               os=-solaris2
+               ;;
+       i386mach)
+               basic_machine=i386-mach
+               os=-mach
+               ;;
+       i386-vsta | vsta)
+               basic_machine=i386-unknown
+               os=-vsta
+               ;;
+       iris | iris4d)
+               basic_machine=mips-sgi
+               case $os in
+                   -irix*)
+                       ;;
+                   *)
+                       os=-irix4
+                       ;;
+               esac
+               ;;
+       isi68 | isi)
+               basic_machine=m68k-isi
+               os=-sysv
+               ;;
+       m88k-omron*)
+               basic_machine=m88k-omron
+               ;;
+       magnum | m3230)
+               basic_machine=mips-mips
+               os=-sysv
+               ;;
+       merlin)
+               basic_machine=ns32k-utek
+               os=-sysv
+               ;;
+       mingw32)
+               basic_machine=i386-pc
+               os=-mingw32
+               ;;
+       miniframe)
+               basic_machine=m68000-convergent
+               ;;
+       *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*)
+               basic_machine=m68k-atari
+               os=-mint
+               ;;
+       mips3*-*)
+               basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`
+               ;;
+       mips3*)
+               basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown
+               ;;
+       monitor)
+               basic_machine=m68k-rom68k
+               os=-coff
+               ;;
+       morphos)
+               basic_machine=powerpc-unknown
+               os=-morphos
+               ;;
+       msdos)
+               basic_machine=i386-pc
+               os=-msdos
+               ;;
+       ms1-*)
+               basic_machine=`echo $basic_machine | sed -e 's/ms1-/mt-/'`
+               ;;
+       mvs)
+               basic_machine=i370-ibm
+               os=-mvs
+               ;;
+       ncr3000)
+               basic_machine=i486-ncr
+               os=-sysv4
+               ;;
+       netbsd386)
+               basic_machine=i386-unknown
+               os=-netbsd
+               ;;
+       netwinder)
+               basic_machine=armv4l-rebel
+               os=-linux
+               ;;
+       news | news700 | news800 | news900)
+               basic_machine=m68k-sony
+               os=-newsos
+               ;;
+       news1000)
+               basic_machine=m68030-sony
+               os=-newsos
+               ;;
+       news-3600 | risc-news)
+               basic_machine=mips-sony
+               os=-newsos
+               ;;
+       necv70)
+               basic_machine=v70-nec
+               os=-sysv
+               ;;
+       next | m*-next )
+               basic_machine=m68k-next
+               case $os in
+                   -nextstep* )
+                       ;;
+                   -ns2*)
+                     os=-nextstep2
+                       ;;
+                   *)
+                     os=-nextstep3
+                       ;;
+               esac
+               ;;
+       nh3000)
+               basic_machine=m68k-harris
+               os=-cxux
+               ;;
+       nh[45]000)
+               basic_machine=m88k-harris
+               os=-cxux
+               ;;
+       nindy960)
+               basic_machine=i960-intel
+               os=-nindy
+               ;;
+       mon960)
+               basic_machine=i960-intel
+               os=-mon960
+               ;;
+       nonstopux)
+               basic_machine=mips-compaq
+               os=-nonstopux
+               ;;
+       np1)
+               basic_machine=np1-gould
+               ;;
+       nsr-tandem)
+               basic_machine=nsr-tandem
+               ;;
+       op50n-* | op60c-*)
+               basic_machine=hppa1.1-oki
+               os=-proelf
+               ;;
+       openrisc | openrisc-*)
+               basic_machine=or32-unknown
+               ;;
+       os400)
+               basic_machine=powerpc-ibm
+               os=-os400
+               ;;
+       OSE68000 | ose68000)
+               basic_machine=m68000-ericsson
+               os=-ose
+               ;;
+       os68k)
+               basic_machine=m68k-none
+               os=-os68k
+               ;;
+       pa-hitachi)
+               basic_machine=hppa1.1-hitachi
+               os=-hiuxwe2
+               ;;
+       paragon)
+               basic_machine=i860-intel
+               os=-osf
+               ;;
+       pbd)
+               basic_machine=sparc-tti
+               ;;
+       pbb)
+               basic_machine=m68k-tti
+               ;;
+       pc532 | pc532-*)
+               basic_machine=ns32k-pc532
+               ;;
+       pc98)
+               basic_machine=i386-pc
+               ;;
+       pc98-*)
+               basic_machine=i386-`echo $basic_machine | sed 's/^[^-]*-//'`
+               ;;
+       pentium | p5 | k5 | k6 | nexgen | viac3)
+               basic_machine=i586-pc
+               ;;
+       pentiumpro | p6 | 6x86 | athlon | athlon_*)
+               basic_machine=i686-pc
+               ;;
+       pentiumii | pentium2 | pentiumiii | pentium3)
+               basic_machine=i686-pc
+               ;;
+       pentium4)
+               basic_machine=i786-pc
+               ;;
+       pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*)
+               basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'`
+               ;;
+       pentiumpro-* | p6-* | 6x86-* | athlon-*)
+               basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
+               ;;
+       pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*)
+               basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
+               ;;
+       pentium4-*)
+               basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'`
+               ;;
+       pn)
+               basic_machine=pn-gould
+               ;;
+       power)  basic_machine=power-ibm
+               ;;
+       ppc)    basic_machine=powerpc-unknown
+               ;;
+       ppc-*)  basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'`
+               ;;
+       ppcle | powerpclittle | ppc-le | powerpc-little)
+               basic_machine=powerpcle-unknown
+               ;;
+       ppcle-* | powerpclittle-*)
+               basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'`
+               ;;
+       ppc64)  basic_machine=powerpc64-unknown
+               ;;
+       ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'`
+               ;;
+       ppc64le | powerpc64little | ppc64-le | powerpc64-little)
+               basic_machine=powerpc64le-unknown
+               ;;
+       ppc64le-* | powerpc64little-*)
+               basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'`
+               ;;
+       ps2)
+               basic_machine=i386-ibm
+               ;;
+       pw32)
+               basic_machine=i586-unknown
+               os=-pw32
+               ;;
+       rdos)
+               basic_machine=i386-pc
+               os=-rdos
+               ;;
+       rom68k)
+               basic_machine=m68k-rom68k
+               os=-coff
+               ;;
+       rm[46]00)
+               basic_machine=mips-siemens
+               ;;
+       rtpc | rtpc-*)
+               basic_machine=romp-ibm
+               ;;
+       s390 | s390-*)
+               basic_machine=s390-ibm
+               ;;
+       s390x | s390x-*)
+               basic_machine=s390x-ibm
+               ;;
+       sa29200)
+               basic_machine=a29k-amd
+               os=-udi
+               ;;
+       sb1)
+               basic_machine=mipsisa64sb1-unknown
+               ;;
+       sb1el)
+               basic_machine=mipsisa64sb1el-unknown
+               ;;
+       sei)
+               basic_machine=mips-sei
+               os=-seiux
+               ;;
+       sequent)
+               basic_machine=i386-sequent
+               ;;
+       sh)
+               basic_machine=sh-hitachi
+               os=-hms
+               ;;
+       sh64)
+               basic_machine=sh64-unknown
+               ;;
+       sparclite-wrs | simso-wrs)
+               basic_machine=sparclite-wrs
+               os=-vxworks
+               ;;
+       sps7)
+               basic_machine=m68k-bull
+               os=-sysv2
+               ;;
+       spur)
+               basic_machine=spur-unknown
+               ;;
+       st2000)
+               basic_machine=m68k-tandem
+               ;;
+       stratus)
+               basic_machine=i860-stratus
+               os=-sysv4
+               ;;
+       sun2)
+               basic_machine=m68000-sun
+               ;;
+       sun2os3)
+               basic_machine=m68000-sun
+               os=-sunos3
+               ;;
+       sun2os4)
+               basic_machine=m68000-sun
+               os=-sunos4
+               ;;
+       sun3os3)
+               basic_machine=m68k-sun
+               os=-sunos3
+               ;;
+       sun3os4)
+               basic_machine=m68k-sun
+               os=-sunos4
+               ;;
+       sun4os3)
+               basic_machine=sparc-sun
+               os=-sunos3
+               ;;
+       sun4os4)
+               basic_machine=sparc-sun
+               os=-sunos4
+               ;;
+       sun4sol2)
+               basic_machine=sparc-sun
+               os=-solaris2
+               ;;
+       sun3 | sun3-*)
+               basic_machine=m68k-sun
+               ;;
+       sun4)
+               basic_machine=sparc-sun
+               ;;
+       sun386 | sun386i | roadrunner)
+               basic_machine=i386-sun
+               ;;
+       sv1)
+               basic_machine=sv1-cray
+               os=-unicos
+               ;;
+       symmetry)
+               basic_machine=i386-sequent
+               os=-dynix
+               ;;
+       t3e)
+               basic_machine=alphaev5-cray
+               os=-unicos
+               ;;
+       t90)
+               basic_machine=t90-cray
+               os=-unicos
+               ;;
+       tic54x | c54x*)
+               basic_machine=tic54x-unknown
+               os=-coff
+               ;;
+       tic55x | c55x*)
+               basic_machine=tic55x-unknown
+               os=-coff
+               ;;
+       tic6x | c6x*)
+               basic_machine=tic6x-unknown
+               os=-coff
+               ;;
+       tx39)
+               basic_machine=mipstx39-unknown
+               ;;
+       tx39el)
+               basic_machine=mipstx39el-unknown
+               ;;
+       toad1)
+               basic_machine=pdp10-xkl
+               os=-tops20
+               ;;
+       tower | tower-32)
+               basic_machine=m68k-ncr
+               ;;
+       tpf)
+               basic_machine=s390x-ibm
+               os=-tpf
+               ;;
+       udi29k)
+               basic_machine=a29k-amd
+               os=-udi
+               ;;
+       ultra3)
+               basic_machine=a29k-nyu
+               os=-sym1
+               ;;
+       v810 | necv810)
+               basic_machine=v810-nec
+               os=-none
+               ;;
+       vaxv)
+               basic_machine=vax-dec
+               os=-sysv
+               ;;
+       vms)
+               basic_machine=vax-dec
+               os=-vms
+               ;;
+       vpp*|vx|vx-*)
+               basic_machine=f301-fujitsu
+               ;;
+       vxworks960)
+               basic_machine=i960-wrs
+               os=-vxworks
+               ;;
+       vxworks68)
+               basic_machine=m68k-wrs
+               os=-vxworks
+               ;;
+       vxworks29k)
+               basic_machine=a29k-wrs
+               os=-vxworks
+               ;;
+       w65*)
+               basic_machine=w65-wdc
+               os=-none
+               ;;
+       w89k-*)
+               basic_machine=hppa1.1-winbond
+               os=-proelf
+               ;;
+       xbox)
+               basic_machine=i686-pc
+               os=-mingw32
+               ;;
+       xps | xps100)
+               basic_machine=xps100-honeywell
+               ;;
+       ymp)
+               basic_machine=ymp-cray
+               os=-unicos
+               ;;
+       z8k-*-coff)
+               basic_machine=z8k-unknown
+               os=-sim
+               ;;
+       none)
+               basic_machine=none-none
+               os=-none
+               ;;
+
+# Here we handle the default manufacturer of certain CPU types.  It is in
+# some cases the only manufacturer, in others, it is the most popular.
+       w89k)
+               basic_machine=hppa1.1-winbond
+               ;;
+       op50n)
+               basic_machine=hppa1.1-oki
+               ;;
+       op60c)
+               basic_machine=hppa1.1-oki
+               ;;
+       romp)
+               basic_machine=romp-ibm
+               ;;
+       mmix)
+               basic_machine=mmix-knuth
+               ;;
+       rs6000)
+               basic_machine=rs6000-ibm
+               ;;
+       vax)
+               basic_machine=vax-dec
+               ;;
+       pdp10)
+               # there are many clones, so DEC is not a safe bet
+               basic_machine=pdp10-unknown
+               ;;
+       pdp11)
+               basic_machine=pdp11-dec
+               ;;
+       we32k)
+               basic_machine=we32k-att
+               ;;
+       sh[1234] | sh[24]a | sh[34]eb | sh[1234]le | sh[23]ele)
+               basic_machine=sh-unknown
+               ;;
+       sparc | sparcv8 | sparcv9 | sparcv9b)
+               basic_machine=sparc-sun
+               ;;
+       cydra)
+               basic_machine=cydra-cydrome
+               ;;
+       orion)
+               basic_machine=orion-highlevel
+               ;;
+       orion105)
+               basic_machine=clipper-highlevel
+               ;;
+       mac | mpw | mac-mpw)
+               basic_machine=m68k-apple
+               ;;
+       pmac | pmac-mpw)
+               basic_machine=powerpc-apple
+               ;;
+       *-unknown)
+               # Make sure to match an already-canonicalized machine name.
+               ;;
+       *)
+               echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
+               exit 1
+               ;;
+esac
+
+# Here we canonicalize certain aliases for manufacturers.
+case $basic_machine in
+       *-digital*)
+               basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'`
+               ;;
+       *-commodore*)
+               basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'`
+               ;;
+       *)
+               ;;
+esac
+
+# Decode manufacturer-specific aliases for certain operating systems.
+
+if [ x"$os" != x"" ]
+then
+case $os in
+        # First match some system type aliases
+        # that might get confused with valid system types.
+       # -solaris* is a basic system type, with this one exception.
+       -solaris1 | -solaris1.*)
+               os=`echo $os | sed -e 's|solaris1|sunos4|'`
+               ;;
+       -solaris)
+               os=-solaris2
+               ;;
+       -svr4*)
+               os=-sysv4
+               ;;
+       -unixware*)
+               os=-sysv4.2uw
+               ;;
+       -gnu/linux*)
+               os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'`
+               ;;
+       # First accept the basic system types.
+       # The portable systems comes first.
+       # Each alternative MUST END IN A *, to match a version number.
+       # -sysv* is not here because it comes later, after sysvr4.
+       -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \
+             | -*vms* | -sco* | -esix* | -isc* | -aix* | -sunos | -sunos[34]*\
+             | -hpux* | -unos* | -osf* | -luna* | -dgux* | -solaris* | -sym* \
+             | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \
+             | -aos* \
+             | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \
+             | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \
+             | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* | -openbsd* \
+             | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \
+             | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \
+             | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \
+             | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \
+             | -chorusos* | -chorusrdb* \
+             | -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \
+             | -mingw32* | -linux-gnu* | -linux-newlib* | -linux-uclibc* \
+             | -uxpv* | -beos* | -mpeix* | -udk* \
+             | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \
+             | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \
+             | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \
+             | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \
+             | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \
+             | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \
+             | -skyos* | -haiku* | -rdos*)
+       # Remember, each alternative MUST END IN *, to match a version number.
+               ;;
+       -qnx*)
+               case $basic_machine in
+                   x86-* | i*86-*)
+                       ;;
+                   *)
+                       os=-nto$os
+                       ;;
+               esac
+               ;;
+       -nto-qnx*)
+               ;;
+       -nto*)
+               os=`echo $os | sed -e 's|nto|nto-qnx|'`
+               ;;
+       -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \
+             | -windows* | -osx | -abug | -netware* | -os9* | -beos* | -haiku* \
+             | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*)
+               ;;
+       -mac*)
+               os=`echo $os | sed -e 's|mac|macos|'`
+               ;;
+       -linux-dietlibc)
+               os=-linux-dietlibc
+               ;;
+       -linux*)
+               os=`echo $os | sed -e 's|linux|linux-gnu|'`
+               ;;
+       -sunos5*)
+               os=`echo $os | sed -e 's|sunos5|solaris2|'`
+               ;;
+       -sunos6*)
+               os=`echo $os | sed -e 's|sunos6|solaris3|'`
+               ;;
+       -opened*)
+               os=-openedition
+               ;;
+        -os400*)
+               os=-os400
+               ;;
+       -wince*)
+               os=-wince
+               ;;
+       -osfrose*)
+               os=-osfrose
+               ;;
+       -osf*)
+               os=-osf
+               ;;
+       -utek*)
+               os=-bsd
+               ;;
+       -dynix*)
+               os=-bsd
+               ;;
+       -acis*)
+               os=-aos
+               ;;
+       -atheos*)
+               os=-atheos
+               ;;
+       -syllable*)
+               os=-syllable
+               ;;
+       -386bsd)
+               os=-bsd
+               ;;
+       -ctix* | -uts*)
+               os=-sysv
+               ;;
+       -nova*)
+               os=-rtmk-nova
+               ;;
+       -ns2 )
+               os=-nextstep2
+               ;;
+       -nsk*)
+               os=-nsk
+               ;;
+       # Preserve the version number of sinix5.
+       -sinix5.*)
+               os=`echo $os | sed -e 's|sinix|sysv|'`
+               ;;
+       -sinix*)
+               os=-sysv4
+               ;;
+        -tpf*)
+               os=-tpf
+               ;;
+       -triton*)
+               os=-sysv3
+               ;;
+       -oss*)
+               os=-sysv3
+               ;;
+       -svr4)
+               os=-sysv4
+               ;;
+       -svr3)
+               os=-sysv3
+               ;;
+       -sysvr4)
+               os=-sysv4
+               ;;
+       # This must come after -sysvr4.
+       -sysv*)
+               ;;
+       -ose*)
+               os=-ose
+               ;;
+       -es1800*)
+               os=-ose
+               ;;
+       -xenix)
+               os=-xenix
+               ;;
+       -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*)
+               os=-mint
+               ;;
+       -aros*)
+               os=-aros
+               ;;
+       -kaos*)
+               os=-kaos
+               ;;
+       -zvmoe)
+               os=-zvmoe
+               ;;
+       -none)
+               ;;
+       *)
+               # Get rid of the `-' at the beginning of $os.
+               os=`echo $os | sed 's/[^-]*-//'`
+               echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2
+               exit 1
+               ;;
+esac
+else
+
+# Here we handle the default operating systems that come with various machines.
+# The value should be what the vendor currently ships out the door with their
+# machine or put another way, the most popular os provided with the machine.
+
+# Note that if you're going to try to match "-MANUFACTURER" here (say,
+# "-sun"), then you have to tell the case statement up towards the top
+# that MANUFACTURER isn't an operating system.  Otherwise, code above
+# will signal an error saying that MANUFACTURER isn't an operating
+# system, and we'll never get to this point.
+
+case $basic_machine in
+       *-acorn)
+               os=-riscix1.2
+               ;;
+       arm*-rebel)
+               os=-linux
+               ;;
+       arm*-semi)
+               os=-aout
+               ;;
+    c4x-* | tic4x-*)
+        os=-coff
+        ;;
+       # This must come before the *-dec entry.
+       pdp10-*)
+               os=-tops20
+               ;;
+       pdp11-*)
+               os=-none
+               ;;
+       *-dec | vax-*)
+               os=-ultrix4.2
+               ;;
+       m68*-apollo)
+               os=-domain
+               ;;
+       i386-sun)
+               os=-sunos4.0.2
+               ;;
+       m68000-sun)
+               os=-sunos3
+               # This also exists in the configure program, but was not the
+               # default.
+               # os=-sunos4
+               ;;
+       m68*-cisco)
+               os=-aout
+               ;;
+       mips*-cisco)
+               os=-elf
+               ;;
+       mips*-*)
+               os=-elf
+               ;;
+       or32-*)
+               os=-coff
+               ;;
+       *-tti)  # must be before sparc entry or we get the wrong os.
+               os=-sysv3
+               ;;
+       sparc-* | *-sun)
+               os=-sunos4.1.1
+               ;;
+       *-be)
+               os=-beos
+               ;;
+       *-haiku)
+               os=-haiku
+               ;;
+       *-ibm)
+               os=-aix
+               ;;
+       *-knuth)
+               os=-mmixware
+               ;;
+       *-wec)
+               os=-proelf
+               ;;
+       *-winbond)
+               os=-proelf
+               ;;
+       *-oki)
+               os=-proelf
+               ;;
+       *-hp)
+               os=-hpux
+               ;;
+       *-hitachi)
+               os=-hiux
+               ;;
+       i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent)
+               os=-sysv
+               ;;
+       *-cbm)
+               os=-amigaos
+               ;;
+       *-dg)
+               os=-dgux
+               ;;
+       *-dolphin)
+               os=-sysv3
+               ;;
+       m68k-ccur)
+               os=-rtu
+               ;;
+       m88k-omron*)
+               os=-luna
+               ;;
+       *-next )
+               os=-nextstep
+               ;;
+       *-sequent)
+               os=-ptx
+               ;;
+       *-crds)
+               os=-unos
+               ;;
+       *-ns)
+               os=-genix
+               ;;
+       i370-*)
+               os=-mvs
+               ;;
+       *-next)
+               os=-nextstep3
+               ;;
+       *-gould)
+               os=-sysv
+               ;;
+       *-highlevel)
+               os=-bsd
+               ;;
+       *-encore)
+               os=-bsd
+               ;;
+       *-sgi)
+               os=-irix
+               ;;
+       *-siemens)
+               os=-sysv4
+               ;;
+       *-masscomp)
+               os=-rtu
+               ;;
+       f30[01]-fujitsu | f700-fujitsu)
+               os=-uxpv
+               ;;
+       *-rom68k)
+               os=-coff
+               ;;
+       *-*bug)
+               os=-coff
+               ;;
+       *-apple)
+               os=-macos
+               ;;
+       *-atari*)
+               os=-mint
+               ;;
+       *)
+               os=-none
+               ;;
+esac
+fi
+
+# Here we handle the case where we know the os, and the CPU type, but not the
+# manufacturer.  We pick the logical manufacturer.
+vendor=unknown
+case $basic_machine in
+       *-unknown)
+               case $os in
+                       -riscix*)
+                               vendor=acorn
+                               ;;
+                       -sunos*)
+                               vendor=sun
+                               ;;
+                       -aix*)
+                               vendor=ibm
+                               ;;
+                       -beos*)
+                               vendor=be
+                               ;;
+                       -hpux*)
+                               vendor=hp
+                               ;;
+                       -mpeix*)
+                               vendor=hp
+                               ;;
+                       -hiux*)
+                               vendor=hitachi
+                               ;;
+                       -unos*)
+                               vendor=crds
+                               ;;
+                       -dgux*)
+                               vendor=dg
+                               ;;
+                       -luna*)
+                               vendor=omron
+                               ;;
+                       -genix*)
+                               vendor=ns
+                               ;;
+                       -mvs* | -opened*)
+                               vendor=ibm
+                               ;;
+                       -os400*)
+                               vendor=ibm
+                               ;;
+                       -ptx*)
+                               vendor=sequent
+                               ;;
+                       -tpf*)
+                               vendor=ibm
+                               ;;
+                       -vxsim* | -vxworks* | -windiss*)
+                               vendor=wrs
+                               ;;
+                       -aux*)
+                               vendor=apple
+                               ;;
+                       -hms*)
+                               vendor=hitachi
+                               ;;
+                       -mpw* | -macos*)
+                               vendor=apple
+                               ;;
+                       -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*)
+                               vendor=atari
+                               ;;
+                       -vos*)
+                               vendor=stratus
+                               ;;
+               esac
+               basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"`
+               ;;
+esac
+
+echo $basic_machine$os
+exit
+
+# Local variables:
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "timestamp='"
+# time-stamp-format: "%:y-%02m-%02d"
+# time-stamp-end: "'"
+# End:
diff --git a/configure b/configure
new file mode 100644 (file)
index 0000000..3c9c151
--- /dev/null
+++ b/configure
@@ -0,0 +1,12623 @@
+#! /bin/sh
+# Guess values for system-dependent variables and create Makefiles.
+# Generated by GNU Autoconf 2.61.
+#
+# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001,
+# 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
+# This configure script is free software; the Free Software Foundation
+# gives unlimited permission to copy, distribute and modify it.
+## --------------------- ##
+## M4sh Initialization.  ##
+## --------------------- ##
+
+# Be more Bourne compatible
+DUALCASE=1; export DUALCASE # for MKS sh
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then
+  emulate sh
+  NULLCMD=:
+  # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which
+  # is contrary to our usage.  Disable this feature.
+  alias -g '${1+"$@"}'='"$@"'
+  setopt NO_GLOB_SUBST
+else
+  case `(set -o) 2>/dev/null` in
+  *posix*) set -o posix ;;
+esac
+
+fi
+
+
+
+
+# PATH needs CR
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+  echo "#! /bin/sh" >conf$$.sh
+  echo  "exit 0"   >>conf$$.sh
+  chmod +x conf$$.sh
+  if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then
+    PATH_SEPARATOR=';'
+  else
+    PATH_SEPARATOR=:
+  fi
+  rm -f conf$$.sh
+fi
+
+# Support unset when possible.
+if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then
+  as_unset=unset
+else
+  as_unset=false
+fi
+
+
+# IFS
+# We need space, tab and new line, in precisely that order.  Quoting is
+# there to prevent editors from complaining about space-tab.
+# (If _AS_PATH_WALK were called with IFS unset, it would disable word
+# splitting by setting IFS to empty value.)
+as_nl='
+'
+IFS=" ""       $as_nl"
+
+# Find who we are.  Look in the path if we contain no directory separator.
+case $0 in
+  *[\\/]* ) as_myself=$0 ;;
+  *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+done
+IFS=$as_save_IFS
+
+     ;;
+esac
+# We did not find ourselves, most probably we were run as `sh COMMAND'
+# in which case we are not to be found in the path.
+if test "x$as_myself" = x; then
+  as_myself=$0
+fi
+if test ! -f "$as_myself"; then
+  echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
+  { (exit 1); exit 1; }
+fi
+
+# Work around bugs in pre-3.0 UWIN ksh.
+for as_var in ENV MAIL MAILPATH
+do ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var
+done
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+for as_var in \
+  LANG LANGUAGE LC_ADDRESS LC_ALL LC_COLLATE LC_CTYPE LC_IDENTIFICATION \
+  LC_MEASUREMENT LC_MESSAGES LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER \
+  LC_TELEPHONE LC_TIME
+do
+  if (set +x; test -z "`(eval $as_var=C; export $as_var) 2>&1`"); then
+    eval $as_var=C; export $as_var
+  else
+    ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var
+  fi
+done
+
+# Required to use basename.
+if expr a : '\(a\)' >/dev/null 2>&1 &&
+   test "X`expr 00001 : '.*\(...\)'`" = X001; then
+  as_expr=expr
+else
+  as_expr=false
+fi
+
+if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then
+  as_basename=basename
+else
+  as_basename=false
+fi
+
+
+# Name of the executable.
+as_me=`$as_basename -- "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+        X"$0" : 'X\(//\)$' \| \
+        X"$0" : 'X\(/\)' \| . 2>/dev/null ||
+echo X/"$0" |
+    sed '/^.*\/\([^/][^/]*\)\/*$/{
+           s//\1/
+           q
+         }
+         /^X\/\(\/\/\)$/{
+           s//\1/
+           q
+         }
+         /^X\/\(\/\).*/{
+           s//\1/
+           q
+         }
+         s/.*/./; q'`
+
+# CDPATH.
+$as_unset CDPATH
+
+
+if test "x$CONFIG_SHELL" = x; then
+  if (eval ":") 2>/dev/null; then
+  as_have_required=yes
+else
+  as_have_required=no
+fi
+
+  if test $as_have_required = yes &&    (eval ":
+(as_func_return () {
+  (exit \$1)
+}
+as_func_success () {
+  as_func_return 0
+}
+as_func_failure () {
+  as_func_return 1
+}
+as_func_ret_success () {
+  return 0
+}
+as_func_ret_failure () {
+  return 1
+}
+
+exitcode=0
+if as_func_success; then
+  :
+else
+  exitcode=1
+  echo as_func_success failed.
+fi
+
+if as_func_failure; then
+  exitcode=1
+  echo as_func_failure succeeded.
+fi
+
+if as_func_ret_success; then
+  :
+else
+  exitcode=1
+  echo as_func_ret_success failed.
+fi
+
+if as_func_ret_failure; then
+  exitcode=1
+  echo as_func_ret_failure succeeded.
+fi
+
+if ( set x; as_func_ret_success y && test x = \"\$1\" ); then
+  :
+else
+  exitcode=1
+  echo positional parameters were not saved.
+fi
+
+test \$exitcode = 0) || { (exit 1); exit 1; }
+
+(
+  as_lineno_1=\$LINENO
+  as_lineno_2=\$LINENO
+  test \"x\$as_lineno_1\" != \"x\$as_lineno_2\" &&
+  test \"x\`expr \$as_lineno_1 + 1\`\" = \"x\$as_lineno_2\") || { (exit 1); exit 1; }
+") 2> /dev/null; then
+  :
+else
+  as_candidate_shells=
+    as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  case $as_dir in
+        /*)
+          for as_base in sh bash ksh sh5; do
+            as_candidate_shells="$as_candidate_shells $as_dir/$as_base"
+          done;;
+       esac
+done
+IFS=$as_save_IFS
+
+
+      for as_shell in $as_candidate_shells $SHELL; do
+        # Try only shells that exist, to save several forks.
+        if { test -f "$as_shell" || test -f "$as_shell.exe"; } &&
+               { ("$as_shell") 2> /dev/null <<\_ASEOF
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then
+  emulate sh
+  NULLCMD=:
+  # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which
+  # is contrary to our usage.  Disable this feature.
+  alias -g '${1+"$@"}'='"$@"'
+  setopt NO_GLOB_SUBST
+else
+  case `(set -o) 2>/dev/null` in
+  *posix*) set -o posix ;;
+esac
+
+fi
+
+
+:
+_ASEOF
+}; then
+  CONFIG_SHELL=$as_shell
+              as_have_required=yes
+              if { "$as_shell" 2> /dev/null <<\_ASEOF
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then
+  emulate sh
+  NULLCMD=:
+  # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which
+  # is contrary to our usage.  Disable this feature.
+  alias -g '${1+"$@"}'='"$@"'
+  setopt NO_GLOB_SUBST
+else
+  case `(set -o) 2>/dev/null` in
+  *posix*) set -o posix ;;
+esac
+
+fi
+
+
+:
+(as_func_return () {
+  (exit $1)
+}
+as_func_success () {
+  as_func_return 0
+}
+as_func_failure () {
+  as_func_return 1
+}
+as_func_ret_success () {
+  return 0
+}
+as_func_ret_failure () {
+  return 1
+}
+
+exitcode=0
+if as_func_success; then
+  :
+else
+  exitcode=1
+  echo as_func_success failed.
+fi
+
+if as_func_failure; then
+  exitcode=1
+  echo as_func_failure succeeded.
+fi
+
+if as_func_ret_success; then
+  :
+else
+  exitcode=1
+  echo as_func_ret_success failed.
+fi
+
+if as_func_ret_failure; then
+  exitcode=1
+  echo as_func_ret_failure succeeded.
+fi
+
+if ( set x; as_func_ret_success y && test x = "$1" ); then
+  :
+else
+  exitcode=1
+  echo positional parameters were not saved.
+fi
+
+test $exitcode = 0) || { (exit 1); exit 1; }
+
+(
+  as_lineno_1=$LINENO
+  as_lineno_2=$LINENO
+  test "x$as_lineno_1" != "x$as_lineno_2" &&
+  test "x`expr $as_lineno_1 + 1`" = "x$as_lineno_2") || { (exit 1); exit 1; }
+
+_ASEOF
+}; then
+  break
+fi
+
+fi
+
+      done
+
+      if test "x$CONFIG_SHELL" != x; then
+  for as_var in BASH_ENV ENV
+        do ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var
+        done
+        export CONFIG_SHELL
+        exec "$CONFIG_SHELL" "$as_myself" ${1+"$@"}
+fi
+
+
+    if test $as_have_required = no; then
+  echo This script requires a shell more modern than all the
+      echo shells that I found on your system.  Please install a
+      echo modern shell, or manually run the script under such a
+      echo shell if you do have one.
+      { (exit 1); exit 1; }
+fi
+
+
+fi
+
+fi
+
+
+
+(eval "as_func_return () {
+  (exit \$1)
+}
+as_func_success () {
+  as_func_return 0
+}
+as_func_failure () {
+  as_func_return 1
+}
+as_func_ret_success () {
+  return 0
+}
+as_func_ret_failure () {
+  return 1
+}
+
+exitcode=0
+if as_func_success; then
+  :
+else
+  exitcode=1
+  echo as_func_success failed.
+fi
+
+if as_func_failure; then
+  exitcode=1
+  echo as_func_failure succeeded.
+fi
+
+if as_func_ret_success; then
+  :
+else
+  exitcode=1
+  echo as_func_ret_success failed.
+fi
+
+if as_func_ret_failure; then
+  exitcode=1
+  echo as_func_ret_failure succeeded.
+fi
+
+if ( set x; as_func_ret_success y && test x = \"\$1\" ); then
+  :
+else
+  exitcode=1
+  echo positional parameters were not saved.
+fi
+
+test \$exitcode = 0") || {
+  echo No shell found that supports shell functions.
+  echo Please tell autoconf@gnu.org about your system,
+  echo including any error possibly output before this
+  echo message
+}
+
+
+
+  as_lineno_1=$LINENO
+  as_lineno_2=$LINENO
+  test "x$as_lineno_1" != "x$as_lineno_2" &&
+  test "x`expr $as_lineno_1 + 1`" = "x$as_lineno_2" || {
+
+  # Create $as_me.lineno as a copy of $as_myself, but with $LINENO
+  # uniformly replaced by the line number.  The first 'sed' inserts a
+  # line-number line after each line using $LINENO; the second 'sed'
+  # does the real work.  The second script uses 'N' to pair each
+  # line-number line with the line containing $LINENO, and appends
+  # trailing '-' during substitution so that $LINENO is not a special
+  # case at line end.
+  # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the
+  # scripts with optimization help from Paolo Bonzini.  Blame Lee
+  # E. McMahon (1931-1989) for sed's syntax.  :-)
+  sed -n '
+    p
+    /[$]LINENO/=
+  ' <$as_myself |
+    sed '
+      s/[$]LINENO.*/&-/
+      t lineno
+      b
+      :lineno
+      N
+      :loop
+      s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/
+      t loop
+      s/-\n.*//
+    ' >$as_me.lineno &&
+  chmod +x "$as_me.lineno" ||
+    { echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2
+   { (exit 1); exit 1; }; }
+
+  # Don't try to exec as it changes $[0], causing all sort of problems
+  # (the dirname of $[0] is not the place where we might find the
+  # original and so on.  Autoconf is especially sensitive to this).
+  . "./$as_me.lineno"
+  # Exit status is that of the last command.
+  exit
+}
+
+
+if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
+  as_dirname=dirname
+else
+  as_dirname=false
+fi
+
+ECHO_C= ECHO_N= ECHO_T=
+case `echo -n x` in
+-n*)
+  case `echo 'x\c'` in
+  *c*) ECHO_T='        ';;     # ECHO_T is single tab character.
+  *)   ECHO_C='\c';;
+  esac;;
+*)
+  ECHO_N='-n';;
+esac
+
+if expr a : '\(a\)' >/dev/null 2>&1 &&
+   test "X`expr 00001 : '.*\(...\)'`" = X001; then
+  as_expr=expr
+else
+  as_expr=false
+fi
+
+rm -f conf$$ conf$$.exe conf$$.file
+if test -d conf$$.dir; then
+  rm -f conf$$.dir/conf$$.file
+else
+  rm -f conf$$.dir
+  mkdir conf$$.dir
+fi
+echo >conf$$.file
+if ln -s conf$$.file conf$$ 2>/dev/null; then
+  as_ln_s='ln -s'
+  # ... but there are two gotchas:
+  # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
+  # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
+  # In both cases, we have to default to `cp -p'.
+  ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
+    as_ln_s='cp -p'
+elif ln conf$$.file conf$$ 2>/dev/null; then
+  as_ln_s=ln
+else
+  as_ln_s='cp -p'
+fi
+rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
+rmdir conf$$.dir 2>/dev/null
+
+if mkdir -p . 2>/dev/null; then
+  as_mkdir_p=:
+else
+  test -d ./-p && rmdir ./-p
+  as_mkdir_p=false
+fi
+
+if test -x / >/dev/null 2>&1; then
+  as_test_x='test -x'
+else
+  if ls -dL / >/dev/null 2>&1; then
+    as_ls_L_option=L
+  else
+    as_ls_L_option=
+  fi
+  as_test_x='
+    eval sh -c '\''
+      if test -d "$1"; then
+        test -d "$1/.";
+      else
+       case $1 in
+        -*)set "./$1";;
+       esac;
+       case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in
+       ???[sx]*):;;*)false;;esac;fi
+    '\'' sh
+  '
+fi
+as_executable_p=$as_test_x
+
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
+
+# Sed expression to map a string onto a valid variable name.
+as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
+
+
+
+exec 7<&0 </dev/null 6>&1
+
+# Name of the host.
+# hostname on some systems (SVR3.2, Linux) returns a bogus exit status,
+# so uname gets run too.
+ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q`
+
+#
+# Initializations.
+#
+ac_default_prefix=/usr/local
+ac_clean_files=
+ac_config_libobj_dir=.
+LIBOBJS=
+cross_compiling=no
+subdirs=
+MFLAGS=
+MAKEFLAGS=
+SHELL=${CONFIG_SHELL-/bin/sh}
+
+# Identity of this package.
+PACKAGE_NAME=
+PACKAGE_TARNAME=
+PACKAGE_VERSION=
+PACKAGE_STRING=
+PACKAGE_BUGREPORT=
+
+ac_unique_file="ircd/ircd.c"
+ac_default_prefix=$HOME
+# Factoring default headers for most tests.
+ac_includes_default="\
+#include <stdio.h>
+#ifdef HAVE_SYS_TYPES_H
+# include <sys/types.h>
+#endif
+#ifdef HAVE_SYS_STAT_H
+# include <sys/stat.h>
+#endif
+#ifdef STDC_HEADERS
+# include <stdlib.h>
+# include <stddef.h>
+#else
+# ifdef HAVE_STDLIB_H
+#  include <stdlib.h>
+# endif
+#endif
+#ifdef HAVE_STRING_H
+# if !defined STDC_HEADERS && defined HAVE_MEMORY_H
+#  include <memory.h>
+# endif
+# include <string.h>
+#endif
+#ifdef HAVE_STRINGS_H
+# include <strings.h>
+#endif
+#ifdef HAVE_INTTYPES_H
+# include <inttypes.h>
+#endif
+#ifdef HAVE_STDINT_H
+# include <stdint.h>
+#endif
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif"
+
+ac_subst_vars='SHELL
+PATH_SEPARATOR
+PACKAGE_NAME
+PACKAGE_TARNAME
+PACKAGE_VERSION
+PACKAGE_STRING
+PACKAGE_BUGREPORT
+exec_prefix
+prefix
+program_transform_name
+bindir
+sbindir
+libexecdir
+datarootdir
+datadir
+sysconfdir
+sharedstatedir
+localstatedir
+includedir
+oldincludedir
+docdir
+infodir
+htmldir
+dvidir
+pdfdir
+psdir
+libdir
+localedir
+mandir
+DEFS
+ECHO_C
+ECHO_N
+ECHO_T
+LIBS
+build_alias
+host_alias
+target_alias
+build
+build_cpu
+build_vendor
+build_os
+host
+host_cpu
+host_vendor
+host_os
+CC
+CFLAGS
+LDFLAGS
+CPPFLAGS
+ac_ct_CC
+EXEEXT
+OBJEXT
+CPP
+GREP
+EGREP
+AWK
+SET_MAKE
+INSTALL_PROGRAM
+INSTALL_SCRIPT
+INSTALL_DATA
+LN_S
+RMPROG
+SHPROG
+LEX
+LEX_OUTPUT_ROOT
+LEXLIB
+YACC
+YFLAGS
+ENGINE_C
+INSTALL_RULE
+SYMLINK
+IRCDMODE
+IRCDOWN
+IRCDGRP
+DPATH
+LIBOBJS
+LTLIBOBJS'
+ac_subst_files=''
+      ac_precious_vars='build_alias
+host_alias
+target_alias
+CC
+CFLAGS
+LDFLAGS
+LIBS
+CPPFLAGS
+CPP
+YACC
+YFLAGS'
+
+
+# Initialize some variables set by options.
+ac_init_help=
+ac_init_version=false
+# The variables have the same names as the options, with
+# dashes changed to underlines.
+cache_file=/dev/null
+exec_prefix=NONE
+no_create=
+no_recursion=
+prefix=NONE
+program_prefix=NONE
+program_suffix=NONE
+program_transform_name=s,x,x,
+silent=
+site=
+srcdir=
+verbose=
+x_includes=NONE
+x_libraries=NONE
+
+# Installation directory options.
+# These are left unexpanded so users can "make install exec_prefix=/foo"
+# and all the variables that are supposed to be based on exec_prefix
+# by default will actually change.
+# Use braces instead of parens because sh, perl, etc. also accept them.
+# (The list follows the same order as the GNU Coding Standards.)
+bindir='${exec_prefix}/bin'
+sbindir='${exec_prefix}/sbin'
+libexecdir='${exec_prefix}/libexec'
+datarootdir='${prefix}/share'
+datadir='${datarootdir}'
+sysconfdir='${prefix}/etc'
+sharedstatedir='${prefix}/com'
+localstatedir='${prefix}/var'
+includedir='${prefix}/include'
+oldincludedir='/usr/include'
+docdir='${datarootdir}/doc/${PACKAGE}'
+infodir='${datarootdir}/info'
+htmldir='${docdir}'
+dvidir='${docdir}'
+pdfdir='${docdir}'
+psdir='${docdir}'
+libdir='${exec_prefix}/lib'
+localedir='${datarootdir}/locale'
+mandir='${datarootdir}/man'
+
+ac_prev=
+ac_dashdash=
+for ac_option
+do
+  # If the previous option needs an argument, assign it.
+  if test -n "$ac_prev"; then
+    eval $ac_prev=\$ac_option
+    ac_prev=
+    continue
+  fi
+
+  case $ac_option in
+  *=*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;;
+  *)   ac_optarg=yes ;;
+  esac
+
+  # Accept the important Cygnus configure options, so we can diagnose typos.
+
+  case $ac_dashdash$ac_option in
+  --)
+    ac_dashdash=yes ;;
+
+  -bindir | --bindir | --bindi | --bind | --bin | --bi)
+    ac_prev=bindir ;;
+  -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*)
+    bindir=$ac_optarg ;;
+
+  -build | --build | --buil | --bui | --bu)
+    ac_prev=build_alias ;;
+  -build=* | --build=* | --buil=* | --bui=* | --bu=*)
+    build_alias=$ac_optarg ;;
+
+  -cache-file | --cache-file | --cache-fil | --cache-fi \
+  | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c)
+    ac_prev=cache_file ;;
+  -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \
+  | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*)
+    cache_file=$ac_optarg ;;
+
+  --config-cache | -C)
+    cache_file=config.cache ;;
+
+  -datadir | --datadir | --datadi | --datad)
+    ac_prev=datadir ;;
+  -datadir=* | --datadir=* | --datadi=* | --datad=*)
+    datadir=$ac_optarg ;;
+
+  -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \
+  | --dataroo | --dataro | --datar)
+    ac_prev=datarootdir ;;
+  -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \
+  | --dataroot=* | --dataroo=* | --dataro=* | --datar=*)
+    datarootdir=$ac_optarg ;;
+
+  -disable-* | --disable-*)
+    ac_feature=`expr "x$ac_option" : 'x-*disable-\(.*\)'`
+    # Reject names that are not valid shell variable names.
+    expr "x$ac_feature" : ".*[^-._$as_cr_alnum]" >/dev/null &&
+      { echo "$as_me: error: invalid feature name: $ac_feature" >&2
+   { (exit 1); exit 1; }; }
+    ac_feature=`echo $ac_feature | sed 's/[-.]/_/g'`
+    eval enable_$ac_feature=no ;;
+
+  -docdir | --docdir | --docdi | --doc | --do)
+    ac_prev=docdir ;;
+  -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*)
+    docdir=$ac_optarg ;;
+
+  -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv)
+    ac_prev=dvidir ;;
+  -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*)
+    dvidir=$ac_optarg ;;
+
+  -enable-* | --enable-*)
+    ac_feature=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'`
+    # Reject names that are not valid shell variable names.
+    expr "x$ac_feature" : ".*[^-._$as_cr_alnum]" >/dev/null &&
+      { echo "$as_me: error: invalid feature name: $ac_feature" >&2
+   { (exit 1); exit 1; }; }
+    ac_feature=`echo $ac_feature | sed 's/[-.]/_/g'`
+    eval enable_$ac_feature=\$ac_optarg ;;
+
+  -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \
+  | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \
+  | --exec | --exe | --ex)
+    ac_prev=exec_prefix ;;
+  -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \
+  | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \
+  | --exec=* | --exe=* | --ex=*)
+    exec_prefix=$ac_optarg ;;
+
+  -gas | --gas | --ga | --g)
+    # Obsolete; use --with-gas.
+    with_gas=yes ;;
+
+  -help | --help | --hel | --he | -h)
+    ac_init_help=long ;;
+  -help=r* | --help=r* | --hel=r* | --he=r* | -hr*)
+    ac_init_help=recursive ;;
+  -help=s* | --help=s* | --hel=s* | --he=s* | -hs*)
+    ac_init_help=short ;;
+
+  -host | --host | --hos | --ho)
+    ac_prev=host_alias ;;
+  -host=* | --host=* | --hos=* | --ho=*)
+    host_alias=$ac_optarg ;;
+
+  -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht)
+    ac_prev=htmldir ;;
+  -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \
+  | --ht=*)
+    htmldir=$ac_optarg ;;
+
+  -includedir | --includedir | --includedi | --included | --include \
+  | --includ | --inclu | --incl | --inc)
+    ac_prev=includedir ;;
+  -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \
+  | --includ=* | --inclu=* | --incl=* | --inc=*)
+    includedir=$ac_optarg ;;
+
+  -infodir | --infodir | --infodi | --infod | --info | --inf)
+    ac_prev=infodir ;;
+  -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*)
+    infodir=$ac_optarg ;;
+
+  -libdir | --libdir | --libdi | --libd)
+    ac_prev=libdir ;;
+  -libdir=* | --libdir=* | --libdi=* | --libd=*)
+    libdir=$ac_optarg ;;
+
+  -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \
+  | --libexe | --libex | --libe)
+    ac_prev=libexecdir ;;
+  -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \
+  | --libexe=* | --libex=* | --libe=*)
+    libexecdir=$ac_optarg ;;
+
+  -localedir | --localedir | --localedi | --localed | --locale)
+    ac_prev=localedir ;;
+  -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*)
+    localedir=$ac_optarg ;;
+
+  -localstatedir | --localstatedir | --localstatedi | --localstated \
+  | --localstate | --localstat | --localsta | --localst | --locals)
+    ac_prev=localstatedir ;;
+  -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \
+  | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*)
+    localstatedir=$ac_optarg ;;
+
+  -mandir | --mandir | --mandi | --mand | --man | --ma | --m)
+    ac_prev=mandir ;;
+  -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*)
+    mandir=$ac_optarg ;;
+
+  -nfp | --nfp | --nf)
+    # Obsolete; use --without-fp.
+    with_fp=no ;;
+
+  -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+  | --no-cr | --no-c | -n)
+    no_create=yes ;;
+
+  -no-recursion | --no-recursion | --no-recursio | --no-recursi \
+  | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r)
+    no_recursion=yes ;;
+
+  -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \
+  | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \
+  | --oldin | --oldi | --old | --ol | --o)
+    ac_prev=oldincludedir ;;
+  -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \
+  | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \
+  | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*)
+    oldincludedir=$ac_optarg ;;
+
+  -prefix | --prefix | --prefi | --pref | --pre | --pr | --p)
+    ac_prev=prefix ;;
+  -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*)
+    prefix=$ac_optarg ;;
+
+  -program-prefix | --program-prefix | --program-prefi | --program-pref \
+  | --program-pre | --program-pr | --program-p)
+    ac_prev=program_prefix ;;
+  -program-prefix=* | --program-prefix=* | --program-prefi=* \
+  | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*)
+    program_prefix=$ac_optarg ;;
+
+  -program-suffix | --program-suffix | --program-suffi | --program-suff \
+  | --program-suf | --program-su | --program-s)
+    ac_prev=program_suffix ;;
+  -program-suffix=* | --program-suffix=* | --program-suffi=* \
+  | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*)
+    program_suffix=$ac_optarg ;;
+
+  -program-transform-name | --program-transform-name \
+  | --program-transform-nam | --program-transform-na \
+  | --program-transform-n | --program-transform- \
+  | --program-transform | --program-transfor \
+  | --program-transfo | --program-transf \
+  | --program-trans | --program-tran \
+  | --progr-tra | --program-tr | --program-t)
+    ac_prev=program_transform_name ;;
+  -program-transform-name=* | --program-transform-name=* \
+  | --program-transform-nam=* | --program-transform-na=* \
+  | --program-transform-n=* | --program-transform-=* \
+  | --program-transform=* | --program-transfor=* \
+  | --program-transfo=* | --program-transf=* \
+  | --program-trans=* | --program-tran=* \
+  | --progr-tra=* | --program-tr=* | --program-t=*)
+    program_transform_name=$ac_optarg ;;
+
+  -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd)
+    ac_prev=pdfdir ;;
+  -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*)
+    pdfdir=$ac_optarg ;;
+
+  -psdir | --psdir | --psdi | --psd | --ps)
+    ac_prev=psdir ;;
+  -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*)
+    psdir=$ac_optarg ;;
+
+  -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+  | -silent | --silent | --silen | --sile | --sil)
+    silent=yes ;;
+
+  -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
+    ac_prev=sbindir ;;
+  -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
+  | --sbi=* | --sb=*)
+    sbindir=$ac_optarg ;;
+
+  -sharedstatedir | --sharedstatedir | --sharedstatedi \
+  | --sharedstated | --sharedstate | --sharedstat | --sharedsta \
+  | --sharedst | --shareds | --shared | --share | --shar \
+  | --sha | --sh)
+    ac_prev=sharedstatedir ;;
+  -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \
+  | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \
+  | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \
+  | --sha=* | --sh=*)
+    sharedstatedir=$ac_optarg ;;
+
+  -site | --site | --sit)
+    ac_prev=site ;;
+  -site=* | --site=* | --sit=*)
+    site=$ac_optarg ;;
+
+  -srcdir | --srcdir | --srcdi | --srcd | --src | --sr)
+    ac_prev=srcdir ;;
+  -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*)
+    srcdir=$ac_optarg ;;
+
+  -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \
+  | --syscon | --sysco | --sysc | --sys | --sy)
+    ac_prev=sysconfdir ;;
+  -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \
+  | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*)
+    sysconfdir=$ac_optarg ;;
+
+  -target | --target | --targe | --targ | --tar | --ta | --t)
+    ac_prev=target_alias ;;
+  -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*)
+    target_alias=$ac_optarg ;;
+
+  -v | -verbose | --verbose | --verbos | --verbo | --verb)
+    verbose=yes ;;
+
+  -version | --version | --versio | --versi | --vers | -V)
+    ac_init_version=: ;;
+
+  -with-* | --with-*)
+    ac_package=`expr "x$ac_option" : 'x-*with-\([^=]*\)'`
+    # Reject names that are not valid shell variable names.
+    expr "x$ac_package" : ".*[^-._$as_cr_alnum]" >/dev/null &&
+      { echo "$as_me: error: invalid package name: $ac_package" >&2
+   { (exit 1); exit 1; }; }
+    ac_package=`echo $ac_package | sed 's/[-.]/_/g'`
+    eval with_$ac_package=\$ac_optarg ;;
+
+  -without-* | --without-*)
+    ac_package=`expr "x$ac_option" : 'x-*without-\(.*\)'`
+    # Reject names that are not valid shell variable names.
+    expr "x$ac_package" : ".*[^-._$as_cr_alnum]" >/dev/null &&
+      { echo "$as_me: error: invalid package name: $ac_package" >&2
+   { (exit 1); exit 1; }; }
+    ac_package=`echo $ac_package | sed 's/[-.]/_/g'`
+    eval with_$ac_package=no ;;
+
+  --x)
+    # Obsolete; use --with-x.
+    with_x=yes ;;
+
+  -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \
+  | --x-incl | --x-inc | --x-in | --x-i)
+    ac_prev=x_includes ;;
+  -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \
+  | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*)
+    x_includes=$ac_optarg ;;
+
+  -x-libraries | --x-libraries | --x-librarie | --x-librari \
+  | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l)
+    ac_prev=x_libraries ;;
+  -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \
+  | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*)
+    x_libraries=$ac_optarg ;;
+
+  -*) { echo "$as_me: error: unrecognized option: $ac_option
+Try \`$0 --help' for more information." >&2
+   { (exit 1); exit 1; }; }
+    ;;
+
+  *=*)
+    ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='`
+    # Reject names that are not valid shell variable names.
+    expr "x$ac_envvar" : ".*[^_$as_cr_alnum]" >/dev/null &&
+      { echo "$as_me: error: invalid variable name: $ac_envvar" >&2
+   { (exit 1); exit 1; }; }
+    eval $ac_envvar=\$ac_optarg
+    export $ac_envvar ;;
+
+  *)
+    # FIXME: should be removed in autoconf 3.0.
+    echo "$as_me: WARNING: you should use --build, --host, --target" >&2
+    expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null &&
+      echo "$as_me: WARNING: invalid host type: $ac_option" >&2
+    : ${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}
+    ;;
+
+  esac
+done
+
+if test -n "$ac_prev"; then
+  ac_option=--`echo $ac_prev | sed 's/_/-/g'`
+  { echo "$as_me: error: missing argument to $ac_option" >&2
+   { (exit 1); exit 1; }; }
+fi
+
+# Be sure to have absolute directory names.
+for ac_var in  exec_prefix prefix bindir sbindir libexecdir datarootdir \
+               datadir sysconfdir sharedstatedir localstatedir includedir \
+               oldincludedir docdir infodir htmldir dvidir pdfdir psdir \
+               libdir localedir mandir
+do
+  eval ac_val=\$$ac_var
+  case $ac_val in
+    [\\/$]* | ?:[\\/]* )  continue;;
+    NONE | '' ) case $ac_var in *prefix ) continue;; esac;;
+  esac
+  { echo "$as_me: error: expected an absolute directory name for --$ac_var: $ac_val" >&2
+   { (exit 1); exit 1; }; }
+done
+
+# There might be people who depend on the old broken behavior: `$host'
+# used to hold the argument of --host etc.
+# FIXME: To remove some day.
+build=$build_alias
+host=$host_alias
+target=$target_alias
+
+# FIXME: To remove some day.
+if test "x$host_alias" != x; then
+  if test "x$build_alias" = x; then
+    cross_compiling=maybe
+    echo "$as_me: WARNING: If you wanted to set the --build type, don't use --host.
+    If a cross compiler is detected then cross compile mode will be used." >&2
+  elif test "x$build_alias" != "x$host_alias"; then
+    cross_compiling=yes
+  fi
+fi
+
+ac_tool_prefix=
+test -n "$host_alias" && ac_tool_prefix=$host_alias-
+
+test "$silent" = yes && exec 6>/dev/null
+
+
+ac_pwd=`pwd` && test -n "$ac_pwd" &&
+ac_ls_di=`ls -di .` &&
+ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` ||
+  { echo "$as_me: error: Working directory cannot be determined" >&2
+   { (exit 1); exit 1; }; }
+test "X$ac_ls_di" = "X$ac_pwd_ls_di" ||
+  { echo "$as_me: error: pwd does not report name of working directory" >&2
+   { (exit 1); exit 1; }; }
+
+
+# Find the source files, if location was not specified.
+if test -z "$srcdir"; then
+  ac_srcdir_defaulted=yes
+  # Try the directory containing this script, then the parent directory.
+  ac_confdir=`$as_dirname -- "$0" ||
+$as_expr X"$0" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+        X"$0" : 'X\(//\)[^/]' \| \
+        X"$0" : 'X\(//\)$' \| \
+        X"$0" : 'X\(/\)' \| . 2>/dev/null ||
+echo X"$0" |
+    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+           s//\1/
+           q
+         }
+         /^X\(\/\/\)[^/].*/{
+           s//\1/
+           q
+         }
+         /^X\(\/\/\)$/{
+           s//\1/
+           q
+         }
+         /^X\(\/\).*/{
+           s//\1/
+           q
+         }
+         s/.*/./; q'`
+  srcdir=$ac_confdir
+  if test ! -r "$srcdir/$ac_unique_file"; then
+    srcdir=..
+  fi
+else
+  ac_srcdir_defaulted=no
+fi
+if test ! -r "$srcdir/$ac_unique_file"; then
+  test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .."
+  { echo "$as_me: error: cannot find sources ($ac_unique_file) in $srcdir" >&2
+   { (exit 1); exit 1; }; }
+fi
+ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work"
+ac_abs_confdir=`(
+       cd "$srcdir" && test -r "./$ac_unique_file" || { echo "$as_me: error: $ac_msg" >&2
+   { (exit 1); exit 1; }; }
+       pwd)`
+# When building in place, set srcdir=.
+if test "$ac_abs_confdir" = "$ac_pwd"; then
+  srcdir=.
+fi
+# Remove unnecessary trailing slashes from srcdir.
+# Double slashes in file names in object file debugging info
+# mess up M-x gdb in Emacs.
+case $srcdir in
+*/) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;;
+esac
+for ac_var in $ac_precious_vars; do
+  eval ac_env_${ac_var}_set=\${${ac_var}+set}
+  eval ac_env_${ac_var}_value=\$${ac_var}
+  eval ac_cv_env_${ac_var}_set=\${${ac_var}+set}
+  eval ac_cv_env_${ac_var}_value=\$${ac_var}
+done
+
+#
+# Report the --help message.
+#
+if test "$ac_init_help" = "long"; then
+  # Omit some internal or obsolete options to make the list less imposing.
+  # This message is too long to be a string in the A/UX 3.1 sh.
+  cat <<_ACEOF
+\`configure' configures this package to adapt to many kinds of systems.
+
+Usage: $0 [OPTION]... [VAR=VALUE]...
+
+To assign environment variables (e.g., CC, CFLAGS...), specify them as
+VAR=VALUE.  See below for descriptions of some of the useful variables.
+
+Defaults for the options are specified in brackets.
+
+Configuration:
+  -h, --help              display this help and exit
+      --help=short        display options specific to this package
+      --help=recursive    display the short help of all the included packages
+  -V, --version           display version information and exit
+  -q, --quiet, --silent   do not print \`checking...' messages
+      --cache-file=FILE   cache test results in FILE [disabled]
+  -C, --config-cache      alias for \`--cache-file=config.cache'
+  -n, --no-create         do not create output files
+      --srcdir=DIR        find the sources in DIR [configure dir or \`..']
+
+Installation directories:
+  --prefix=PREFIX         install architecture-independent files in PREFIX
+                         [$ac_default_prefix]
+  --exec-prefix=EPREFIX   install architecture-dependent files in EPREFIX
+                         [PREFIX]
+
+By default, \`make install' will install all the files in
+\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc.  You can specify
+an installation prefix other than \`$ac_default_prefix' using \`--prefix',
+for instance \`--prefix=\$HOME'.
+
+For better control, use the options below.
+
+Fine tuning of the installation directories:
+  --bindir=DIR           user executables [EPREFIX/bin]
+  --sbindir=DIR          system admin executables [EPREFIX/sbin]
+  --libexecdir=DIR       program executables [EPREFIX/libexec]
+  --sysconfdir=DIR       read-only single-machine data [PREFIX/etc]
+  --sharedstatedir=DIR   modifiable architecture-independent data [PREFIX/com]
+  --localstatedir=DIR    modifiable single-machine data [PREFIX/var]
+  --libdir=DIR           object code libraries [EPREFIX/lib]
+  --includedir=DIR       C header files [PREFIX/include]
+  --oldincludedir=DIR    C header files for non-gcc [/usr/include]
+  --datarootdir=DIR      read-only arch.-independent data root [PREFIX/share]
+  --datadir=DIR          read-only architecture-independent data [DATAROOTDIR]
+  --infodir=DIR          info documentation [DATAROOTDIR/info]
+  --localedir=DIR        locale-dependent data [DATAROOTDIR/locale]
+  --mandir=DIR           man documentation [DATAROOTDIR/man]
+  --docdir=DIR           documentation root [DATAROOTDIR/doc/PACKAGE]
+  --htmldir=DIR          html documentation [DOCDIR]
+  --dvidir=DIR           dvi documentation [DOCDIR]
+  --pdfdir=DIR           pdf documentation [DOCDIR]
+  --psdir=DIR            ps documentation [DOCDIR]
+_ACEOF
+
+  cat <<\_ACEOF
+
+System types:
+  --build=BUILD     configure for building on BUILD [guessed]
+  --host=HOST       cross-compile to build programs to run on HOST [BUILD]
+_ACEOF
+fi
+
+if test -n "$ac_init_help"; then
+
+  cat <<\_ACEOF
+
+Optional Features:
+  --disable-FEATURE       do not include FEATURE (same as --enable-FEATURE=no)
+  --enable-FEATURE[=ARG]  include FEATURE [ARG=yes]
+  --enable-poll           Force poll to be used regardless of whether or not
+                          it is a system call
+  --enable-debug          Turn on debugging mode
+  --disable-asserts       Disable assertion checking
+  --enable-profile        Enable profiling support (add -pg to CFLAGS and LDFLAGS)
+  --enable-pedantic       Enable pedantic warnings (add -pedantic to CFLAGS)
+  --enable-warnings       Enable warnings (add -Wall to CFLAGS)
+  --disable-inlines       Disable inlining for a few critical functions
+  --disable-devpoll       Disable the /dev/poll-based engine
+  --disable-kqueue        Disable the kqueue-based engine
+  --disable-epoll         Disable the epoll-based engine
+  --enable-compat          Enables OGN-compat mode.
+  --enable-unstable          Enables unstable features.
+  --enable-gnutls          Enables GnuTLS ssl backend.
+  --enable-openssl          Enables OpenSSL ssl backend.
+
+Optional Packages:
+  --with-PACKAGE[=ARG]    use PACKAGE [ARG=yes]
+  --without-PACKAGE       do not use PACKAGE (same as --with-PACKAGE=no)
+  --with-leak-detect          Turn on the leak detector(requires patched boehm)
+  --without-ipv6          disable IPv6 support (default is autodetect)
+  --with-symlink=name     Name to give the symlink; if name is "no," no
+                          symlink will be created.
+  --with-mode=mode        Permissions (in octal) to give the binary
+  --with-owner=owner      Specify owner of the installed binary
+  --with-group=group      Specify group owner of the installed binary
+  --with-domain=domain    Domain name to use in local statistics gathering
+  --with-chroot=dir       Specify that the server will be operated under
+                          a different root directory given by dir.  See
+                          doc/readme.chroot for more information.
+  --with-dpath=dir        Directory for all server data files
+  --with-cpath=file       Set server configuration file
+  --with-lpath=file       Set the debugging log file
+  --with-maxcon=maxcon    Maximum number of connections server will accept
+
+Some influential environment variables:
+  CC          C compiler command
+  CFLAGS      C compiler flags
+  LDFLAGS     linker flags, e.g. -L<lib dir> if you have libraries in a
+              nonstandard directory <lib dir>
+  LIBS        libraries to pass to the linker, e.g. -l<library>
+  CPPFLAGS    C/C++/Objective C preprocessor flags, e.g. -I<include dir> if
+              you have headers in a nonstandard directory <include dir>
+  CPP         C preprocessor
+  YACC        The `Yet Another C Compiler' implementation to use. Defaults to
+              the first program found out of: `bison -y', `byacc', `yacc'.
+  YFLAGS      The list of arguments that will be passed by default to $YACC.
+              This script will default YFLAGS to the empty string to avoid a
+              default value of `-d' given by some make applications.
+
+Use these variables to override the choices made by `configure' or to help
+it to find libraries and programs with nonstandard names/locations.
+
+_ACEOF
+ac_status=$?
+fi
+
+if test "$ac_init_help" = "recursive"; then
+  # If there are subdirs, report their specific --help.
+  for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue
+    test -d "$ac_dir" || continue
+    ac_builddir=.
+
+case "$ac_dir" in
+.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
+*)
+  ac_dir_suffix=/`echo "$ac_dir" | sed 's,^\.[\\/],,'`
+  # A ".." for each directory in $ac_dir_suffix.
+  ac_top_builddir_sub=`echo "$ac_dir_suffix" | sed 's,/[^\\/]*,/..,g;s,/,,'`
+  case $ac_top_builddir_sub in
+  "") ac_top_builddir_sub=. ac_top_build_prefix= ;;
+  *)  ac_top_build_prefix=$ac_top_builddir_sub/ ;;
+  esac ;;
+esac
+ac_abs_top_builddir=$ac_pwd
+ac_abs_builddir=$ac_pwd$ac_dir_suffix
+# for backward compatibility:
+ac_top_builddir=$ac_top_build_prefix
+
+case $srcdir in
+  .)  # We are building in place.
+    ac_srcdir=.
+    ac_top_srcdir=$ac_top_builddir_sub
+    ac_abs_top_srcdir=$ac_pwd ;;
+  [\\/]* | ?:[\\/]* )  # Absolute name.
+    ac_srcdir=$srcdir$ac_dir_suffix;
+    ac_top_srcdir=$srcdir
+    ac_abs_top_srcdir=$srcdir ;;
+  *) # Relative name.
+    ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix
+    ac_top_srcdir=$ac_top_build_prefix$srcdir
+    ac_abs_top_srcdir=$ac_pwd/$srcdir ;;
+esac
+ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix
+
+    cd "$ac_dir" || { ac_status=$?; continue; }
+    # Check for guested configure.
+    if test -f "$ac_srcdir/configure.gnu"; then
+      echo &&
+      $SHELL "$ac_srcdir/configure.gnu" --help=recursive
+    elif test -f "$ac_srcdir/configure"; then
+      echo &&
+      $SHELL "$ac_srcdir/configure" --help=recursive
+    else
+      echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2
+    fi || ac_status=$?
+    cd "$ac_pwd" || { ac_status=$?; break; }
+  done
+fi
+
+test -n "$ac_init_help" && exit $ac_status
+if $ac_init_version; then
+  cat <<\_ACEOF
+configure
+generated by GNU Autoconf 2.61
+
+Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001,
+2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
+This configure script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it.
+_ACEOF
+  exit
+fi
+cat >config.log <<_ACEOF
+This file contains any messages produced by compilers while
+running configure, to aid debugging if configure makes a mistake.
+
+It was created by $as_me, which was
+generated by GNU Autoconf 2.61.  Invocation command line was
+
+  $ $0 $@
+
+_ACEOF
+exec 5>>config.log
+{
+cat <<_ASUNAME
+## --------- ##
+## Platform. ##
+## --------- ##
+
+hostname = `(hostname || uname -n) 2>/dev/null | sed 1q`
+uname -m = `(uname -m) 2>/dev/null || echo unknown`
+uname -r = `(uname -r) 2>/dev/null || echo unknown`
+uname -s = `(uname -s) 2>/dev/null || echo unknown`
+uname -v = `(uname -v) 2>/dev/null || echo unknown`
+
+/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown`
+/bin/uname -X     = `(/bin/uname -X) 2>/dev/null     || echo unknown`
+
+/bin/arch              = `(/bin/arch) 2>/dev/null              || echo unknown`
+/usr/bin/arch -k       = `(/usr/bin/arch -k) 2>/dev/null       || echo unknown`
+/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown`
+/usr/bin/hostinfo      = `(/usr/bin/hostinfo) 2>/dev/null      || echo unknown`
+/bin/machine           = `(/bin/machine) 2>/dev/null           || echo unknown`
+/usr/bin/oslevel       = `(/usr/bin/oslevel) 2>/dev/null       || echo unknown`
+/bin/universe          = `(/bin/universe) 2>/dev/null          || echo unknown`
+
+_ASUNAME
+
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  echo "PATH: $as_dir"
+done
+IFS=$as_save_IFS
+
+} >&5
+
+cat >&5 <<_ACEOF
+
+
+## ----------- ##
+## Core tests. ##
+## ----------- ##
+
+_ACEOF
+
+
+# Keep a trace of the command line.
+# Strip out --no-create and --no-recursion so they do not pile up.
+# Strip out --silent because we don't want to record it for future runs.
+# Also quote any args containing shell meta-characters.
+# Make two passes to allow for proper duplicate-argument suppression.
+ac_configure_args=
+ac_configure_args0=
+ac_configure_args1=
+ac_must_keep_next=false
+for ac_pass in 1 2
+do
+  for ac_arg
+  do
+    case $ac_arg in
+    -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;;
+    -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+    | -silent | --silent | --silen | --sile | --sil)
+      continue ;;
+    *\'*)
+      ac_arg=`echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;;
+    esac
+    case $ac_pass in
+    1) ac_configure_args0="$ac_configure_args0 '$ac_arg'" ;;
+    2)
+      ac_configure_args1="$ac_configure_args1 '$ac_arg'"
+      if test $ac_must_keep_next = true; then
+       ac_must_keep_next=false # Got value, back to normal.
+      else
+       case $ac_arg in
+         *=* | --config-cache | -C | -disable-* | --disable-* \
+         | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \
+         | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \
+         | -with-* | --with-* | -without-* | --without-* | --x)
+           case "$ac_configure_args0 " in
+             "$ac_configure_args1"*" '$ac_arg' "* ) continue ;;
+           esac
+           ;;
+         -* ) ac_must_keep_next=true ;;
+       esac
+      fi
+      ac_configure_args="$ac_configure_args '$ac_arg'"
+      ;;
+    esac
+  done
+done
+$as_unset ac_configure_args0 || test "${ac_configure_args0+set}" != set || { ac_configure_args0=; export ac_configure_args0; }
+$as_unset ac_configure_args1 || test "${ac_configure_args1+set}" != set || { ac_configure_args1=; export ac_configure_args1; }
+
+# When interrupted or exit'd, cleanup temporary files, and complete
+# config.log.  We remove comments because anyway the quotes in there
+# would cause problems or look ugly.
+# WARNING: Use '\'' to represent an apostrophe within the trap.
+# WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug.
+trap 'exit_status=$?
+  # Save into config.log some information that might help in debugging.
+  {
+    echo
+
+    cat <<\_ASBOX
+## ---------------- ##
+## Cache variables. ##
+## ---------------- ##
+_ASBOX
+    echo
+    # The following way of writing the cache mishandles newlines in values,
+(
+  for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do
+    eval ac_val=\$$ac_var
+    case $ac_val in #(
+    *${as_nl}*)
+      case $ac_var in #(
+      *_cv_*) { echo "$as_me:$LINENO: WARNING: Cache variable $ac_var contains a newline." >&5
+echo "$as_me: WARNING: Cache variable $ac_var contains a newline." >&2;} ;;
+      esac
+      case $ac_var in #(
+      _ | IFS | as_nl) ;; #(
+      *) $as_unset $ac_var ;;
+      esac ;;
+    esac
+  done
+  (set) 2>&1 |
+    case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #(
+    *${as_nl}ac_space=\ *)
+      sed -n \
+       "s/'\''/'\''\\\\'\'''\''/g;
+         s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p"
+      ;; #(
+    *)
+      sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p"
+      ;;
+    esac |
+    sort
+)
+    echo
+
+    cat <<\_ASBOX
+## ----------------- ##
+## Output variables. ##
+## ----------------- ##
+_ASBOX
+    echo
+    for ac_var in $ac_subst_vars
+    do
+      eval ac_val=\$$ac_var
+      case $ac_val in
+      *\'\''*) ac_val=`echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
+      esac
+      echo "$ac_var='\''$ac_val'\''"
+    done | sort
+    echo
+
+    if test -n "$ac_subst_files"; then
+      cat <<\_ASBOX
+## ------------------- ##
+## File substitutions. ##
+## ------------------- ##
+_ASBOX
+      echo
+      for ac_var in $ac_subst_files
+      do
+       eval ac_val=\$$ac_var
+       case $ac_val in
+       *\'\''*) ac_val=`echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
+       esac
+       echo "$ac_var='\''$ac_val'\''"
+      done | sort
+      echo
+    fi
+
+    if test -s confdefs.h; then
+      cat <<\_ASBOX
+## ----------- ##
+## confdefs.h. ##
+## ----------- ##
+_ASBOX
+      echo
+      cat confdefs.h
+      echo
+    fi
+    test "$ac_signal" != 0 &&
+      echo "$as_me: caught signal $ac_signal"
+    echo "$as_me: exit $exit_status"
+  } >&5
+  rm -f core *.core core.conftest.* &&
+    rm -f -r conftest* confdefs* conf$$* $ac_clean_files &&
+    exit $exit_status
+' 0
+for ac_signal in 1 2 13 15; do
+  trap 'ac_signal='$ac_signal'; { (exit 1); exit 1; }' $ac_signal
+done
+ac_signal=0
+
+# confdefs.h avoids OS command line length limits that DEFS can exceed.
+rm -f -r conftest* confdefs.h
+
+# Predefined preprocessor variables.
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_NAME "$PACKAGE_NAME"
+_ACEOF
+
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_TARNAME "$PACKAGE_TARNAME"
+_ACEOF
+
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_VERSION "$PACKAGE_VERSION"
+_ACEOF
+
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_STRING "$PACKAGE_STRING"
+_ACEOF
+
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT"
+_ACEOF
+
+
+# Let the site file select an alternate cache file if it wants to.
+# Prefer explicitly selected file to automatically selected ones.
+if test -n "$CONFIG_SITE"; then
+  set x "$CONFIG_SITE"
+elif test "x$prefix" != xNONE; then
+  set x "$prefix/share/config.site" "$prefix/etc/config.site"
+else
+  set x "$ac_default_prefix/share/config.site" \
+       "$ac_default_prefix/etc/config.site"
+fi
+shift
+for ac_site_file
+do
+  if test -r "$ac_site_file"; then
+    { echo "$as_me:$LINENO: loading site script $ac_site_file" >&5
+echo "$as_me: loading site script $ac_site_file" >&6;}
+    sed 's/^/| /' "$ac_site_file" >&5
+    . "$ac_site_file"
+  fi
+done
+
+if test -r "$cache_file"; then
+  # Some versions of bash will fail to source /dev/null (special
+  # files actually), so we avoid doing that.
+  if test -f "$cache_file"; then
+    { echo "$as_me:$LINENO: loading cache $cache_file" >&5
+echo "$as_me: loading cache $cache_file" >&6;}
+    case $cache_file in
+      [\\/]* | ?:[\\/]* ) . "$cache_file";;
+      *)                      . "./$cache_file";;
+    esac
+  fi
+else
+  { echo "$as_me:$LINENO: creating cache $cache_file" >&5
+echo "$as_me: creating cache $cache_file" >&6;}
+  >$cache_file
+fi
+
+# Check that the precious variables saved in the cache have kept the same
+# value.
+ac_cache_corrupted=false
+for ac_var in $ac_precious_vars; do
+  eval ac_old_set=\$ac_cv_env_${ac_var}_set
+  eval ac_new_set=\$ac_env_${ac_var}_set
+  eval ac_old_val=\$ac_cv_env_${ac_var}_value
+  eval ac_new_val=\$ac_env_${ac_var}_value
+  case $ac_old_set,$ac_new_set in
+    set,)
+      { echo "$as_me:$LINENO: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5
+echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;}
+      ac_cache_corrupted=: ;;
+    ,set)
+      { echo "$as_me:$LINENO: error: \`$ac_var' was not set in the previous run" >&5
+echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;}
+      ac_cache_corrupted=: ;;
+    ,);;
+    *)
+      if test "x$ac_old_val" != "x$ac_new_val"; then
+       { echo "$as_me:$LINENO: error: \`$ac_var' has changed since the previous run:" >&5
+echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;}
+       { echo "$as_me:$LINENO:   former value:  $ac_old_val" >&5
+echo "$as_me:   former value:  $ac_old_val" >&2;}
+       { echo "$as_me:$LINENO:   current value: $ac_new_val" >&5
+echo "$as_me:   current value: $ac_new_val" >&2;}
+       ac_cache_corrupted=:
+      fi;;
+  esac
+  # Pass precious variables to config.status.
+  if test "$ac_new_set" = set; then
+    case $ac_new_val in
+    *\'*) ac_arg=$ac_var=`echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;;
+    *) ac_arg=$ac_var=$ac_new_val ;;
+    esac
+    case " $ac_configure_args " in
+      *" '$ac_arg' "*) ;; # Avoid dups.  Use of quotes ensures accuracy.
+      *) ac_configure_args="$ac_configure_args '$ac_arg'" ;;
+    esac
+  fi
+done
+if $ac_cache_corrupted; then
+  { echo "$as_me:$LINENO: error: changes in the environment can compromise the build" >&5
+echo "$as_me: error: changes in the environment can compromise the build" >&2;}
+  { { echo "$as_me:$LINENO: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&5
+echo "$as_me: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&2;}
+   { (exit 1); exit 1; }; }
+fi
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+
+
+{ echo "$as_me:$LINENO: checking for installation prefix" >&5
+echo $ECHO_N "checking for installation prefix... $ECHO_C" >&6; }
+if test "${unet_cv_prefix+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  unet_cv_prefix=$HOME
+fi
+
+if test x"$prefix" != xNONE; then
+    unet_cv_prefix=$prefix
+fi
+{ echo "$as_me:$LINENO: result: $unet_cv_prefix" >&5
+echo "${ECHO_T}$unet_cv_prefix" >&6; }
+ac_default_prefix=$unet_cv_prefix
+
+ac_config_headers="$ac_config_headers config.h"
+
+
+
+
+ac_aux_dir=
+for ac_dir in "$srcdir" "$srcdir/.." "$srcdir/../.."; do
+  if test -f "$ac_dir/install-sh"; then
+    ac_aux_dir=$ac_dir
+    ac_install_sh="$ac_aux_dir/install-sh -c"
+    break
+  elif test -f "$ac_dir/install.sh"; then
+    ac_aux_dir=$ac_dir
+    ac_install_sh="$ac_aux_dir/install.sh -c"
+    break
+  elif test -f "$ac_dir/shtool"; then
+    ac_aux_dir=$ac_dir
+    ac_install_sh="$ac_aux_dir/shtool install -c"
+    break
+  fi
+done
+if test -z "$ac_aux_dir"; then
+  { { echo "$as_me:$LINENO: error: cannot find install-sh or install.sh in \"$srcdir\" \"$srcdir/..\" \"$srcdir/../..\"" >&5
+echo "$as_me: error: cannot find install-sh or install.sh in \"$srcdir\" \"$srcdir/..\" \"$srcdir/../..\"" >&2;}
+   { (exit 1); exit 1; }; }
+fi
+
+# These three variables are undocumented and unsupported,
+# and are intended to be withdrawn in a future Autoconf release.
+# They can cause serious problems if a builder's source tree is in a directory
+# whose full name contains unusual characters.
+ac_config_guess="$SHELL $ac_aux_dir/config.guess"  # Please don't use this var.
+ac_config_sub="$SHELL $ac_aux_dir/config.sub"  # Please don't use this var.
+ac_configure="$SHELL $ac_aux_dir/configure"  # Please don't use this var.
+
+
+# Make sure we can run config.sub.
+$SHELL "$ac_aux_dir/config.sub" sun4 >/dev/null 2>&1 ||
+  { { echo "$as_me:$LINENO: error: cannot run $SHELL $ac_aux_dir/config.sub" >&5
+echo "$as_me: error: cannot run $SHELL $ac_aux_dir/config.sub" >&2;}
+   { (exit 1); exit 1; }; }
+
+{ echo "$as_me:$LINENO: checking build system type" >&5
+echo $ECHO_N "checking build system type... $ECHO_C" >&6; }
+if test "${ac_cv_build+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_build_alias=$build_alias
+test "x$ac_build_alias" = x &&
+  ac_build_alias=`$SHELL "$ac_aux_dir/config.guess"`
+test "x$ac_build_alias" = x &&
+  { { echo "$as_me:$LINENO: error: cannot guess build type; you must specify one" >&5
+echo "$as_me: error: cannot guess build type; you must specify one" >&2;}
+   { (exit 1); exit 1; }; }
+ac_cv_build=`$SHELL "$ac_aux_dir/config.sub" $ac_build_alias` ||
+  { { echo "$as_me:$LINENO: error: $SHELL $ac_aux_dir/config.sub $ac_build_alias failed" >&5
+echo "$as_me: error: $SHELL $ac_aux_dir/config.sub $ac_build_alias failed" >&2;}
+   { (exit 1); exit 1; }; }
+
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_build" >&5
+echo "${ECHO_T}$ac_cv_build" >&6; }
+case $ac_cv_build in
+*-*-*) ;;
+*) { { echo "$as_me:$LINENO: error: invalid value of canonical build" >&5
+echo "$as_me: error: invalid value of canonical build" >&2;}
+   { (exit 1); exit 1; }; };;
+esac
+build=$ac_cv_build
+ac_save_IFS=$IFS; IFS='-'
+set x $ac_cv_build
+shift
+build_cpu=$1
+build_vendor=$2
+shift; shift
+# Remember, the first character of IFS is used to create $*,
+# except with old shells:
+build_os=$*
+IFS=$ac_save_IFS
+case $build_os in *\ *) build_os=`echo "$build_os" | sed 's/ /-/g'`;; esac
+
+
+{ echo "$as_me:$LINENO: checking host system type" >&5
+echo $ECHO_N "checking host system type... $ECHO_C" >&6; }
+if test "${ac_cv_host+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if test "x$host_alias" = x; then
+  ac_cv_host=$ac_cv_build
+else
+  ac_cv_host=`$SHELL "$ac_aux_dir/config.sub" $host_alias` ||
+    { { echo "$as_me:$LINENO: error: $SHELL $ac_aux_dir/config.sub $host_alias failed" >&5
+echo "$as_me: error: $SHELL $ac_aux_dir/config.sub $host_alias failed" >&2;}
+   { (exit 1); exit 1; }; }
+fi
+
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_host" >&5
+echo "${ECHO_T}$ac_cv_host" >&6; }
+case $ac_cv_host in
+*-*-*) ;;
+*) { { echo "$as_me:$LINENO: error: invalid value of canonical host" >&5
+echo "$as_me: error: invalid value of canonical host" >&2;}
+   { (exit 1); exit 1; }; };;
+esac
+host=$ac_cv_host
+ac_save_IFS=$IFS; IFS='-'
+set x $ac_cv_host
+shift
+host_cpu=$1
+host_vendor=$2
+shift; shift
+# Remember, the first character of IFS is used to create $*,
+# except with old shells:
+host_os=$*
+IFS=$ac_save_IFS
+case $host_os in *\ *) host_os=`echo "$host_os" | sed 's/ /-/g'`;; esac
+
+
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+if test -n "$ac_tool_prefix"; then
+  # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args.
+set dummy ${ac_tool_prefix}gcc; ac_word=$2
+{ echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
+if test "${ac_cv_prog_CC+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_CC="${ac_tool_prefix}gcc"
+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+  { echo "$as_me:$LINENO: result: $CC" >&5
+echo "${ECHO_T}$CC" >&6; }
+else
+  { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_CC"; then
+  ac_ct_CC=$CC
+  # Extract the first word of "gcc", so it can be a program name with args.
+set dummy gcc; ac_word=$2
+{ echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
+if test "${ac_cv_prog_ac_ct_CC+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if test -n "$ac_ct_CC"; then
+  ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_ac_ct_CC="gcc"
+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+  { echo "$as_me:$LINENO: result: $ac_ct_CC" >&5
+echo "${ECHO_T}$ac_ct_CC" >&6; }
+else
+  { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+fi
+
+  if test "x$ac_ct_CC" = x; then
+    CC=""
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ echo "$as_me:$LINENO: WARNING: In the future, Autoconf will not detect cross-tools
+whose name does not start with the host triplet.  If you think this
+configuration is useful to you, please write to autoconf@gnu.org." >&5
+echo "$as_me: WARNING: In the future, Autoconf will not detect cross-tools
+whose name does not start with the host triplet.  If you think this
+configuration is useful to you, please write to autoconf@gnu.org." >&2;}
+ac_tool_warned=yes ;;
+esac
+    CC=$ac_ct_CC
+  fi
+else
+  CC="$ac_cv_prog_CC"
+fi
+
+if test -z "$CC"; then
+          if test -n "$ac_tool_prefix"; then
+    # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args.
+set dummy ${ac_tool_prefix}cc; ac_word=$2
+{ echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
+if test "${ac_cv_prog_CC+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_CC="${ac_tool_prefix}cc"
+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+  { echo "$as_me:$LINENO: result: $CC" >&5
+echo "${ECHO_T}$CC" >&6; }
+else
+  { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+fi
+
+
+  fi
+fi
+if test -z "$CC"; then
+  # Extract the first word of "cc", so it can be a program name with args.
+set dummy cc; ac_word=$2
+{ echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
+if test "${ac_cv_prog_CC+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+  ac_prog_rejected=no
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then
+       ac_prog_rejected=yes
+       continue
+     fi
+    ac_cv_prog_CC="cc"
+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+IFS=$as_save_IFS
+
+if test $ac_prog_rejected = yes; then
+  # We found a bogon in the path, so make sure we never use it.
+  set dummy $ac_cv_prog_CC
+  shift
+  if test $# != 0; then
+    # We chose a different compiler from the bogus one.
+    # However, it has the same basename, so the bogon will be chosen
+    # first if we set CC to just the basename; use the full file name.
+    shift
+    ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@"
+  fi
+fi
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+  { echo "$as_me:$LINENO: result: $CC" >&5
+echo "${ECHO_T}$CC" >&6; }
+else
+  { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+fi
+
+
+fi
+if test -z "$CC"; then
+  if test -n "$ac_tool_prefix"; then
+  for ac_prog in cl.exe
+  do
+    # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
+set dummy $ac_tool_prefix$ac_prog; ac_word=$2
+{ echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
+if test "${ac_cv_prog_CC+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_CC="$ac_tool_prefix$ac_prog"
+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+  { echo "$as_me:$LINENO: result: $CC" >&5
+echo "${ECHO_T}$CC" >&6; }
+else
+  { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+fi
+
+
+    test -n "$CC" && break
+  done
+fi
+if test -z "$CC"; then
+  ac_ct_CC=$CC
+  for ac_prog in cl.exe
+do
+  # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
+if test "${ac_cv_prog_ac_ct_CC+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if test -n "$ac_ct_CC"; then
+  ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_ac_ct_CC="$ac_prog"
+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+  { echo "$as_me:$LINENO: result: $ac_ct_CC" >&5
+echo "${ECHO_T}$ac_ct_CC" >&6; }
+else
+  { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+fi
+
+
+  test -n "$ac_ct_CC" && break
+done
+
+  if test "x$ac_ct_CC" = x; then
+    CC=""
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ echo "$as_me:$LINENO: WARNING: In the future, Autoconf will not detect cross-tools
+whose name does not start with the host triplet.  If you think this
+configuration is useful to you, please write to autoconf@gnu.org." >&5
+echo "$as_me: WARNING: In the future, Autoconf will not detect cross-tools
+whose name does not start with the host triplet.  If you think this
+configuration is useful to you, please write to autoconf@gnu.org." >&2;}
+ac_tool_warned=yes ;;
+esac
+    CC=$ac_ct_CC
+  fi
+fi
+
+fi
+
+
+test -z "$CC" && { { echo "$as_me:$LINENO: error: no acceptable C compiler found in \$PATH
+See \`config.log' for more details." >&5
+echo "$as_me: error: no acceptable C compiler found in \$PATH
+See \`config.log' for more details." >&2;}
+   { (exit 1); exit 1; }; }
+
+# Provide some information about the compiler.
+echo "$as_me:$LINENO: checking for C compiler version" >&5
+ac_compiler=`set X $ac_compile; echo $2`
+{ (ac_try="$ac_compiler --version >&5"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compiler --version >&5") 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }
+{ (ac_try="$ac_compiler -v >&5"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compiler -v >&5") 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }
+{ (ac_try="$ac_compiler -V >&5"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compiler -V >&5") 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }
+
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files a.out a.exe b.out"
+# Try to create an executable without -o first, disregard a.out.
+# It will help us diagnose broken compilers, and finding out an intuition
+# of exeext.
+{ echo "$as_me:$LINENO: checking for C compiler default output file name" >&5
+echo $ECHO_N "checking for C compiler default output file name... $ECHO_C" >&6; }
+ac_link_default=`echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'`
+#
+# List of possible output files, starting from the most likely.
+# The algorithm is not robust to junk in `.', hence go to wildcards (a.*)
+# only as a last resort.  b.out is created by i960 compilers.
+ac_files='a_out.exe a.exe conftest.exe a.out conftest a.* conftest.* b.out'
+#
+# The IRIX 6 linker writes into existing files which may not be
+# executable, retaining their permissions.  Remove them first so a
+# subsequent execution test works.
+ac_rmfiles=
+for ac_file in $ac_files
+do
+  case $ac_file in
+    *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.o | *.obj ) ;;
+    * ) ac_rmfiles="$ac_rmfiles $ac_file";;
+  esac
+done
+rm -f $ac_rmfiles
+
+if { (ac_try="$ac_link_default"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link_default") 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; then
+  # Autoconf-2.13 could set the ac_cv_exeext variable to `no'.
+# So ignore a value of `no', otherwise this would lead to `EXEEXT = no'
+# in a Makefile.  We should not override ac_cv_exeext if it was cached,
+# so that the user can short-circuit this test for compilers unknown to
+# Autoconf.
+for ac_file in $ac_files ''
+do
+  test -f "$ac_file" || continue
+  case $ac_file in
+    *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.o | *.obj )
+       ;;
+    [ab].out )
+       # We found the default executable, but exeext='' is most
+       # certainly right.
+       break;;
+    *.* )
+        if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no;
+       then :; else
+          ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
+       fi
+       # We set ac_cv_exeext here because the later test for it is not
+       # safe: cross compilers may not add the suffix if given an `-o'
+       # argument, so we may need to know it at that point already.
+       # Even if this section looks crufty: it has the advantage of
+       # actually working.
+       break;;
+    * )
+       break;;
+  esac
+done
+test "$ac_cv_exeext" = no && ac_cv_exeext=
+
+else
+  ac_file=''
+fi
+
+{ echo "$as_me:$LINENO: result: $ac_file" >&5
+echo "${ECHO_T}$ac_file" >&6; }
+if test -z "$ac_file"; then
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+{ { echo "$as_me:$LINENO: error: C compiler cannot create executables
+See \`config.log' for more details." >&5
+echo "$as_me: error: C compiler cannot create executables
+See \`config.log' for more details." >&2;}
+   { (exit 77); exit 77; }; }
+fi
+
+ac_exeext=$ac_cv_exeext
+
+# Check that the compiler produces executables we can run.  If not, either
+# the compiler is broken, or we cross compile.
+{ echo "$as_me:$LINENO: checking whether the C compiler works" >&5
+echo $ECHO_N "checking whether the C compiler works... $ECHO_C" >&6; }
+# FIXME: These cross compiler hacks should be removed for Autoconf 3.0
+# If not cross compiling, check that we can run a simple program.
+if test "$cross_compiling" != yes; then
+  if { ac_try='./$ac_file'
+  { (case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_try") 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+    cross_compiling=no
+  else
+    if test "$cross_compiling" = maybe; then
+       cross_compiling=yes
+    else
+       { { echo "$as_me:$LINENO: error: cannot run C compiled programs.
+If you meant to cross compile, use \`--host'.
+See \`config.log' for more details." >&5
+echo "$as_me: error: cannot run C compiled programs.
+If you meant to cross compile, use \`--host'.
+See \`config.log' for more details." >&2;}
+   { (exit 1); exit 1; }; }
+    fi
+  fi
+fi
+{ echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6; }
+
+rm -f a.out a.exe conftest$ac_cv_exeext b.out
+ac_clean_files=$ac_clean_files_save
+# Check that the compiler produces executables we can run.  If not, either
+# the compiler is broken, or we cross compile.
+{ echo "$as_me:$LINENO: checking whether we are cross compiling" >&5
+echo $ECHO_N "checking whether we are cross compiling... $ECHO_C" >&6; }
+{ echo "$as_me:$LINENO: result: $cross_compiling" >&5
+echo "${ECHO_T}$cross_compiling" >&6; }
+
+{ echo "$as_me:$LINENO: checking for suffix of executables" >&5
+echo $ECHO_N "checking for suffix of executables... $ECHO_C" >&6; }
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; then
+  # If both `conftest.exe' and `conftest' are `present' (well, observable)
+# catch `conftest.exe'.  For instance with Cygwin, `ls conftest' will
+# work properly (i.e., refer to `conftest.exe'), while it won't with
+# `rm'.
+for ac_file in conftest.exe conftest conftest.*; do
+  test -f "$ac_file" || continue
+  case $ac_file in
+    *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.o | *.obj ) ;;
+    *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
+         break;;
+    * ) break;;
+  esac
+done
+else
+  { { echo "$as_me:$LINENO: error: cannot compute suffix of executables: cannot compile and link
+See \`config.log' for more details." >&5
+echo "$as_me: error: cannot compute suffix of executables: cannot compile and link
+See \`config.log' for more details." >&2;}
+   { (exit 1); exit 1; }; }
+fi
+
+rm -f conftest$ac_cv_exeext
+{ echo "$as_me:$LINENO: result: $ac_cv_exeext" >&5
+echo "${ECHO_T}$ac_cv_exeext" >&6; }
+
+rm -f conftest.$ac_ext
+EXEEXT=$ac_cv_exeext
+ac_exeext=$EXEEXT
+{ echo "$as_me:$LINENO: checking for suffix of object files" >&5
+echo $ECHO_N "checking for suffix of object files... $ECHO_C" >&6; }
+if test "${ac_cv_objext+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.o conftest.obj
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; then
+  for ac_file in conftest.o conftest.obj conftest.*; do
+  test -f "$ac_file" || continue;
+  case $ac_file in
+    *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf ) ;;
+    *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'`
+       break;;
+  esac
+done
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+{ { echo "$as_me:$LINENO: error: cannot compute suffix of object files: cannot compile
+See \`config.log' for more details." >&5
+echo "$as_me: error: cannot compute suffix of object files: cannot compile
+See \`config.log' for more details." >&2;}
+   { (exit 1); exit 1; }; }
+fi
+
+rm -f conftest.$ac_cv_objext conftest.$ac_ext
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_objext" >&5
+echo "${ECHO_T}$ac_cv_objext" >&6; }
+OBJEXT=$ac_cv_objext
+ac_objext=$OBJEXT
+{ echo "$as_me:$LINENO: checking whether we are using the GNU C compiler" >&5
+echo $ECHO_N "checking whether we are using the GNU C compiler... $ECHO_C" >&6; }
+if test "${ac_cv_c_compiler_gnu+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+int
+main ()
+{
+#ifndef __GNUC__
+       choke me
+#endif
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_compiler_gnu=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_compiler_gnu=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ac_cv_c_compiler_gnu=$ac_compiler_gnu
+
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_c_compiler_gnu" >&5
+echo "${ECHO_T}$ac_cv_c_compiler_gnu" >&6; }
+GCC=`test $ac_compiler_gnu = yes && echo yes`
+ac_test_CFLAGS=${CFLAGS+set}
+ac_save_CFLAGS=$CFLAGS
+{ echo "$as_me:$LINENO: checking whether $CC accepts -g" >&5
+echo $ECHO_N "checking whether $CC accepts -g... $ECHO_C" >&6; }
+if test "${ac_cv_prog_cc_g+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_save_c_werror_flag=$ac_c_werror_flag
+   ac_c_werror_flag=yes
+   ac_cv_prog_cc_g=no
+   CFLAGS="-g"
+   cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_cv_prog_cc_g=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       CFLAGS=""
+      cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  :
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_c_werror_flag=$ac_save_c_werror_flag
+        CFLAGS="-g"
+        cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_cv_prog_cc_g=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+   ac_c_werror_flag=$ac_save_c_werror_flag
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_prog_cc_g" >&5
+echo "${ECHO_T}$ac_cv_prog_cc_g" >&6; }
+if test "$ac_test_CFLAGS" = set; then
+  CFLAGS=$ac_save_CFLAGS
+elif test $ac_cv_prog_cc_g = yes; then
+  if test "$GCC" = yes; then
+    CFLAGS="-g -O2"
+  else
+    CFLAGS="-g"
+  fi
+else
+  if test "$GCC" = yes; then
+    CFLAGS="-O2"
+  else
+    CFLAGS=
+  fi
+fi
+{ echo "$as_me:$LINENO: checking for $CC option to accept ISO C89" >&5
+echo $ECHO_N "checking for $CC option to accept ISO C89... $ECHO_C" >&6; }
+if test "${ac_cv_prog_cc_c89+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_cv_prog_cc_c89=no
+ac_save_CC=$CC
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <stdarg.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+/* Most of the following tests are stolen from RCS 5.7's src/conf.sh.  */
+struct buf { int x; };
+FILE * (*rcsopen) (struct buf *, struct stat *, int);
+static char *e (p, i)
+     char **p;
+     int i;
+{
+  return p[i];
+}
+static char *f (char * (*g) (char **, int), char **p, ...)
+{
+  char *s;
+  va_list v;
+  va_start (v,p);
+  s = g (p, va_arg (v,int));
+  va_end (v);
+  return s;
+}
+
+/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default.  It has
+   function prototypes and stuff, but not '\xHH' hex character constants.
+   These don't provoke an error unfortunately, instead are silently treated
+   as 'x'.  The following induces an error, until -std is added to get
+   proper ANSI mode.  Curiously '\x00'!='x' always comes out true, for an
+   array size at least.  It's necessary to write '\x00'==0 to get something
+   that's true only with -std.  */
+int osf4_cc_array ['\x00' == 0 ? 1 : -1];
+
+/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters
+   inside strings and character constants.  */
+#define FOO(x) 'x'
+int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1];
+
+int test (int i, double x);
+struct s1 {int (*f) (int a);};
+struct s2 {int (*f) (double a);};
+int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int);
+int argc;
+char **argv;
+int
+main ()
+{
+return f (e, argv, 0) != argv[0]  ||  f (e, argv, 1) != argv[1];
+  ;
+  return 0;
+}
+_ACEOF
+for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \
+       -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__"
+do
+  CC="$ac_save_CC $ac_arg"
+  rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_cv_prog_cc_c89=$ac_arg
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+
+fi
+
+rm -f core conftest.err conftest.$ac_objext
+  test "x$ac_cv_prog_cc_c89" != "xno" && break
+done
+rm -f conftest.$ac_ext
+CC=$ac_save_CC
+
+fi
+# AC_CACHE_VAL
+case "x$ac_cv_prog_cc_c89" in
+  x)
+    { echo "$as_me:$LINENO: result: none needed" >&5
+echo "${ECHO_T}none needed" >&6; } ;;
+  xno)
+    { echo "$as_me:$LINENO: result: unsupported" >&5
+echo "${ECHO_T}unsupported" >&6; } ;;
+  *)
+    CC="$CC $ac_cv_prog_cc_c89"
+    { echo "$as_me:$LINENO: result: $ac_cv_prog_cc_c89" >&5
+echo "${ECHO_T}$ac_cv_prog_cc_c89" >&6; } ;;
+esac
+
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+if test -n "$ac_tool_prefix"; then
+  # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args.
+set dummy ${ac_tool_prefix}gcc; ac_word=$2
+{ echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
+if test "${ac_cv_prog_CC+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_CC="${ac_tool_prefix}gcc"
+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+  { echo "$as_me:$LINENO: result: $CC" >&5
+echo "${ECHO_T}$CC" >&6; }
+else
+  { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_CC"; then
+  ac_ct_CC=$CC
+  # Extract the first word of "gcc", so it can be a program name with args.
+set dummy gcc; ac_word=$2
+{ echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
+if test "${ac_cv_prog_ac_ct_CC+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if test -n "$ac_ct_CC"; then
+  ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_ac_ct_CC="gcc"
+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+  { echo "$as_me:$LINENO: result: $ac_ct_CC" >&5
+echo "${ECHO_T}$ac_ct_CC" >&6; }
+else
+  { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+fi
+
+  if test "x$ac_ct_CC" = x; then
+    CC=""
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ echo "$as_me:$LINENO: WARNING: In the future, Autoconf will not detect cross-tools
+whose name does not start with the host triplet.  If you think this
+configuration is useful to you, please write to autoconf@gnu.org." >&5
+echo "$as_me: WARNING: In the future, Autoconf will not detect cross-tools
+whose name does not start with the host triplet.  If you think this
+configuration is useful to you, please write to autoconf@gnu.org." >&2;}
+ac_tool_warned=yes ;;
+esac
+    CC=$ac_ct_CC
+  fi
+else
+  CC="$ac_cv_prog_CC"
+fi
+
+if test -z "$CC"; then
+          if test -n "$ac_tool_prefix"; then
+    # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args.
+set dummy ${ac_tool_prefix}cc; ac_word=$2
+{ echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
+if test "${ac_cv_prog_CC+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_CC="${ac_tool_prefix}cc"
+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+  { echo "$as_me:$LINENO: result: $CC" >&5
+echo "${ECHO_T}$CC" >&6; }
+else
+  { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+fi
+
+
+  fi
+fi
+if test -z "$CC"; then
+  # Extract the first word of "cc", so it can be a program name with args.
+set dummy cc; ac_word=$2
+{ echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
+if test "${ac_cv_prog_CC+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+  ac_prog_rejected=no
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then
+       ac_prog_rejected=yes
+       continue
+     fi
+    ac_cv_prog_CC="cc"
+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+IFS=$as_save_IFS
+
+if test $ac_prog_rejected = yes; then
+  # We found a bogon in the path, so make sure we never use it.
+  set dummy $ac_cv_prog_CC
+  shift
+  if test $# != 0; then
+    # We chose a different compiler from the bogus one.
+    # However, it has the same basename, so the bogon will be chosen
+    # first if we set CC to just the basename; use the full file name.
+    shift
+    ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@"
+  fi
+fi
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+  { echo "$as_me:$LINENO: result: $CC" >&5
+echo "${ECHO_T}$CC" >&6; }
+else
+  { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+fi
+
+
+fi
+if test -z "$CC"; then
+  if test -n "$ac_tool_prefix"; then
+  for ac_prog in cl.exe
+  do
+    # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
+set dummy $ac_tool_prefix$ac_prog; ac_word=$2
+{ echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
+if test "${ac_cv_prog_CC+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_CC="$ac_tool_prefix$ac_prog"
+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+  { echo "$as_me:$LINENO: result: $CC" >&5
+echo "${ECHO_T}$CC" >&6; }
+else
+  { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+fi
+
+
+    test -n "$CC" && break
+  done
+fi
+if test -z "$CC"; then
+  ac_ct_CC=$CC
+  for ac_prog in cl.exe
+do
+  # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
+if test "${ac_cv_prog_ac_ct_CC+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if test -n "$ac_ct_CC"; then
+  ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_ac_ct_CC="$ac_prog"
+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+  { echo "$as_me:$LINENO: result: $ac_ct_CC" >&5
+echo "${ECHO_T}$ac_ct_CC" >&6; }
+else
+  { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+fi
+
+
+  test -n "$ac_ct_CC" && break
+done
+
+  if test "x$ac_ct_CC" = x; then
+    CC=""
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ echo "$as_me:$LINENO: WARNING: In the future, Autoconf will not detect cross-tools
+whose name does not start with the host triplet.  If you think this
+configuration is useful to you, please write to autoconf@gnu.org." >&5
+echo "$as_me: WARNING: In the future, Autoconf will not detect cross-tools
+whose name does not start with the host triplet.  If you think this
+configuration is useful to you, please write to autoconf@gnu.org." >&2;}
+ac_tool_warned=yes ;;
+esac
+    CC=$ac_ct_CC
+  fi
+fi
+
+fi
+
+
+test -z "$CC" && { { echo "$as_me:$LINENO: error: no acceptable C compiler found in \$PATH
+See \`config.log' for more details." >&5
+echo "$as_me: error: no acceptable C compiler found in \$PATH
+See \`config.log' for more details." >&2;}
+   { (exit 1); exit 1; }; }
+
+# Provide some information about the compiler.
+echo "$as_me:$LINENO: checking for C compiler version" >&5
+ac_compiler=`set X $ac_compile; echo $2`
+{ (ac_try="$ac_compiler --version >&5"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compiler --version >&5") 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }
+{ (ac_try="$ac_compiler -v >&5"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compiler -v >&5") 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }
+{ (ac_try="$ac_compiler -V >&5"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compiler -V >&5") 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }
+
+{ echo "$as_me:$LINENO: checking whether we are using the GNU C compiler" >&5
+echo $ECHO_N "checking whether we are using the GNU C compiler... $ECHO_C" >&6; }
+if test "${ac_cv_c_compiler_gnu+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+int
+main ()
+{
+#ifndef __GNUC__
+       choke me
+#endif
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_compiler_gnu=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_compiler_gnu=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ac_cv_c_compiler_gnu=$ac_compiler_gnu
+
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_c_compiler_gnu" >&5
+echo "${ECHO_T}$ac_cv_c_compiler_gnu" >&6; }
+GCC=`test $ac_compiler_gnu = yes && echo yes`
+ac_test_CFLAGS=${CFLAGS+set}
+ac_save_CFLAGS=$CFLAGS
+{ echo "$as_me:$LINENO: checking whether $CC accepts -g" >&5
+echo $ECHO_N "checking whether $CC accepts -g... $ECHO_C" >&6; }
+if test "${ac_cv_prog_cc_g+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_save_c_werror_flag=$ac_c_werror_flag
+   ac_c_werror_flag=yes
+   ac_cv_prog_cc_g=no
+   CFLAGS="-g"
+   cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_cv_prog_cc_g=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       CFLAGS=""
+      cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  :
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_c_werror_flag=$ac_save_c_werror_flag
+        CFLAGS="-g"
+        cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_cv_prog_cc_g=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+   ac_c_werror_flag=$ac_save_c_werror_flag
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_prog_cc_g" >&5
+echo "${ECHO_T}$ac_cv_prog_cc_g" >&6; }
+if test "$ac_test_CFLAGS" = set; then
+  CFLAGS=$ac_save_CFLAGS
+elif test $ac_cv_prog_cc_g = yes; then
+  if test "$GCC" = yes; then
+    CFLAGS="-g -O2"
+  else
+    CFLAGS="-g"
+  fi
+else
+  if test "$GCC" = yes; then
+    CFLAGS="-O2"
+  else
+    CFLAGS=
+  fi
+fi
+{ echo "$as_me:$LINENO: checking for $CC option to accept ISO C89" >&5
+echo $ECHO_N "checking for $CC option to accept ISO C89... $ECHO_C" >&6; }
+if test "${ac_cv_prog_cc_c89+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_cv_prog_cc_c89=no
+ac_save_CC=$CC
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <stdarg.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+/* Most of the following tests are stolen from RCS 5.7's src/conf.sh.  */
+struct buf { int x; };
+FILE * (*rcsopen) (struct buf *, struct stat *, int);
+static char *e (p, i)
+     char **p;
+     int i;
+{
+  return p[i];
+}
+static char *f (char * (*g) (char **, int), char **p, ...)
+{
+  char *s;
+  va_list v;
+  va_start (v,p);
+  s = g (p, va_arg (v,int));
+  va_end (v);
+  return s;
+}
+
+/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default.  It has
+   function prototypes and stuff, but not '\xHH' hex character constants.
+   These don't provoke an error unfortunately, instead are silently treated
+   as 'x'.  The following induces an error, until -std is added to get
+   proper ANSI mode.  Curiously '\x00'!='x' always comes out true, for an
+   array size at least.  It's necessary to write '\x00'==0 to get something
+   that's true only with -std.  */
+int osf4_cc_array ['\x00' == 0 ? 1 : -1];
+
+/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters
+   inside strings and character constants.  */
+#define FOO(x) 'x'
+int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1];
+
+int test (int i, double x);
+struct s1 {int (*f) (int a);};
+struct s2 {int (*f) (double a);};
+int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int);
+int argc;
+char **argv;
+int
+main ()
+{
+return f (e, argv, 0) != argv[0]  ||  f (e, argv, 1) != argv[1];
+  ;
+  return 0;
+}
+_ACEOF
+for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \
+       -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__"
+do
+  CC="$ac_save_CC $ac_arg"
+  rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_cv_prog_cc_c89=$ac_arg
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+
+fi
+
+rm -f core conftest.err conftest.$ac_objext
+  test "x$ac_cv_prog_cc_c89" != "xno" && break
+done
+rm -f conftest.$ac_ext
+CC=$ac_save_CC
+
+fi
+# AC_CACHE_VAL
+case "x$ac_cv_prog_cc_c89" in
+  x)
+    { echo "$as_me:$LINENO: result: none needed" >&5
+echo "${ECHO_T}none needed" >&6; } ;;
+  xno)
+    { echo "$as_me:$LINENO: result: unsupported" >&5
+echo "${ECHO_T}unsupported" >&6; } ;;
+  *)
+    CC="$CC $ac_cv_prog_cc_c89"
+    { echo "$as_me:$LINENO: result: $ac_cv_prog_cc_c89" >&5
+echo "${ECHO_T}$ac_cv_prog_cc_c89" >&6; } ;;
+esac
+
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+am_cv_prog_cc_stdc=$ac_cv_prog_cc_stdc
+
+
+
+
+{ echo "$as_me:$LINENO: checking for library containing crypt" >&5
+echo $ECHO_N "checking for library containing crypt... $ECHO_C" >&6; }
+if test "${ac_cv_search_crypt+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_func_search_save_LIBS=$LIBS
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char crypt ();
+int
+main ()
+{
+return crypt ();
+  ;
+  return 0;
+}
+_ACEOF
+for ac_lib in '' descrypt crypt; do
+  if test -z "$ac_lib"; then
+    ac_res="none required"
+  else
+    ac_res=-l$ac_lib
+    LIBS="-l$ac_lib  $ac_func_search_save_LIBS"
+  fi
+  rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext &&
+       $as_test_x conftest$ac_exeext; then
+  ac_cv_search_crypt=$ac_res
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext
+  if test "${ac_cv_search_crypt+set}" = set; then
+  break
+fi
+done
+if test "${ac_cv_search_crypt+set}" = set; then
+  :
+else
+  ac_cv_search_crypt=no
+fi
+rm conftest.$ac_ext
+LIBS=$ac_func_search_save_LIBS
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_search_crypt" >&5
+echo "${ECHO_T}$ac_cv_search_crypt" >&6; }
+ac_res=$ac_cv_search_crypt
+if test "$ac_res" != no; then
+  test "$ac_res" = "none required" || LIBS="$ac_res $LIBS"
+
+else
+  { { echo "$as_me:$LINENO: error: Unable to find library containing crypt()" >&5
+echo "$as_me: error: Unable to find library containing crypt()" >&2;}
+   { (exit 1); exit 1; }; }
+fi
+
+
+
+   # Most operating systems have gethostbyname() in the default searched
+   # libraries (i.e. libc):
+   { echo "$as_me:$LINENO: checking for gethostbyname" >&5
+echo $ECHO_N "checking for gethostbyname... $ECHO_C" >&6; }
+if test "${ac_cv_func_gethostbyname+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+/* Define gethostbyname to an innocuous variant, in case <limits.h> declares gethostbyname.
+   For example, HP-UX 11i <limits.h> declares gettimeofday.  */
+#define gethostbyname innocuous_gethostbyname
+
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char gethostbyname (); below.
+    Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+    <limits.h> exists even on freestanding compilers.  */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef gethostbyname
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char gethostbyname ();
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined __stub_gethostbyname || defined __stub___gethostbyname
+choke me
+#endif
+
+int
+main ()
+{
+return gethostbyname ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext &&
+       $as_test_x conftest$ac_exeext; then
+  ac_cv_func_gethostbyname=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_func_gethostbyname=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_func_gethostbyname" >&5
+echo "${ECHO_T}$ac_cv_func_gethostbyname" >&6; }
+if test $ac_cv_func_gethostbyname = yes; then
+  :
+else
+  # Some OSes (eg. Solaris) place it in libnsl:
+
+{ echo "$as_me:$LINENO: checking for gethostbyname in -lnsl" >&5
+echo $ECHO_N "checking for gethostbyname in -lnsl... $ECHO_C" >&6; }
+if test "${ac_cv_lib_nsl_gethostbyname+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lnsl  $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char gethostbyname ();
+int
+main ()
+{
+return gethostbyname ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext &&
+       $as_test_x conftest$ac_exeext; then
+  ac_cv_lib_nsl_gethostbyname=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_lib_nsl_gethostbyname=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_lib_nsl_gethostbyname" >&5
+echo "${ECHO_T}$ac_cv_lib_nsl_gethostbyname" >&6; }
+if test $ac_cv_lib_nsl_gethostbyname = yes; then
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBNSL 1
+_ACEOF
+
+  LIBS="-lnsl $LIBS"
+
+else
+  # Some strange OSes (SINIX) have it in libsocket:
+
+{ echo "$as_me:$LINENO: checking for gethostbyname in -lsocket" >&5
+echo $ECHO_N "checking for gethostbyname in -lsocket... $ECHO_C" >&6; }
+if test "${ac_cv_lib_socket_gethostbyname+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lsocket  $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char gethostbyname ();
+int
+main ()
+{
+return gethostbyname ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext &&
+       $as_test_x conftest$ac_exeext; then
+  ac_cv_lib_socket_gethostbyname=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_lib_socket_gethostbyname=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_lib_socket_gethostbyname" >&5
+echo "${ECHO_T}$ac_cv_lib_socket_gethostbyname" >&6; }
+if test $ac_cv_lib_socket_gethostbyname = yes; then
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBSOCKET 1
+_ACEOF
+
+  LIBS="-lsocket $LIBS"
+
+else
+  # Unfortunately libsocket sometimes depends on libnsl.
+          # AC_CHECK_LIB's API is essentially broken so the following
+          # ugliness is necessary:
+          { echo "$as_me:$LINENO: checking for gethostbyname in -lsocket" >&5
+echo $ECHO_N "checking for gethostbyname in -lsocket... $ECHO_C" >&6; }
+if test "${ac_cv_lib_socket_gethostbyname+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lsocket -lnsl $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char gethostbyname ();
+int
+main ()
+{
+return gethostbyname ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext &&
+       $as_test_x conftest$ac_exeext; then
+  ac_cv_lib_socket_gethostbyname=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_lib_socket_gethostbyname=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_lib_socket_gethostbyname" >&5
+echo "${ECHO_T}$ac_cv_lib_socket_gethostbyname" >&6; }
+if test $ac_cv_lib_socket_gethostbyname = yes; then
+  LIBS="-lsocket -lnsl $LIBS"
+else
+
+{ echo "$as_me:$LINENO: checking for gethostbyname in -lresolv" >&5
+echo $ECHO_N "checking for gethostbyname in -lresolv... $ECHO_C" >&6; }
+if test "${ac_cv_lib_resolv_gethostbyname+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lresolv  $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char gethostbyname ();
+int
+main ()
+{
+return gethostbyname ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext &&
+       $as_test_x conftest$ac_exeext; then
+  ac_cv_lib_resolv_gethostbyname=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_lib_resolv_gethostbyname=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_lib_resolv_gethostbyname" >&5
+echo "${ECHO_T}$ac_cv_lib_resolv_gethostbyname" >&6; }
+if test $ac_cv_lib_resolv_gethostbyname = yes; then
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBRESOLV 1
+_ACEOF
+
+  LIBS="-lresolv $LIBS"
+
+fi
+
+fi
+
+
+fi
+
+
+fi
+
+
+fi
+
+  { echo "$as_me:$LINENO: checking for socket" >&5
+echo $ECHO_N "checking for socket... $ECHO_C" >&6; }
+if test "${ac_cv_func_socket+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+/* Define socket to an innocuous variant, in case <limits.h> declares socket.
+   For example, HP-UX 11i <limits.h> declares gettimeofday.  */
+#define socket innocuous_socket
+
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char socket (); below.
+    Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+    <limits.h> exists even on freestanding compilers.  */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef socket
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char socket ();
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined __stub_socket || defined __stub___socket
+choke me
+#endif
+
+int
+main ()
+{
+return socket ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext &&
+       $as_test_x conftest$ac_exeext; then
+  ac_cv_func_socket=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_func_socket=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_func_socket" >&5
+echo "${ECHO_T}$ac_cv_func_socket" >&6; }
+if test $ac_cv_func_socket = yes; then
+  :
+else
+
+{ echo "$as_me:$LINENO: checking for socket in -lsocket" >&5
+echo $ECHO_N "checking for socket in -lsocket... $ECHO_C" >&6; }
+if test "${ac_cv_lib_socket_socket+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lsocket  $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char socket ();
+int
+main ()
+{
+return socket ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext &&
+       $as_test_x conftest$ac_exeext; then
+  ac_cv_lib_socket_socket=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_lib_socket_socket=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_lib_socket_socket" >&5
+echo "${ECHO_T}$ac_cv_lib_socket_socket" >&6; }
+if test $ac_cv_lib_socket_socket = yes; then
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBSOCKET 1
+_ACEOF
+
+  LIBS="-lsocket $LIBS"
+
+else
+  { echo "$as_me:$LINENO: checking for socket in -lsocket" >&5
+echo $ECHO_N "checking for socket in -lsocket... $ECHO_C" >&6; }
+if test "${ac_cv_lib_socket_socket+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lsocket -lnsl $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char socket ();
+int
+main ()
+{
+return socket ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext &&
+       $as_test_x conftest$ac_exeext; then
+  ac_cv_lib_socket_socket=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_lib_socket_socket=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_lib_socket_socket" >&5
+echo "${ECHO_T}$ac_cv_lib_socket_socket" >&6; }
+if test $ac_cv_lib_socket_socket = yes; then
+  LIBS="-lsocket -lnsl $LIBS"
+fi
+
+fi
+
+fi
+
+
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+{ echo "$as_me:$LINENO: checking how to run the C preprocessor" >&5
+echo $ECHO_N "checking how to run the C preprocessor... $ECHO_C" >&6; }
+# On Suns, sometimes $CPP names a directory.
+if test -n "$CPP" && test -d "$CPP"; then
+  CPP=
+fi
+if test -z "$CPP"; then
+  if test "${ac_cv_prog_CPP+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+      # Double quotes because CPP needs to be expanded
+    for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp"
+    do
+      ac_preproc_ok=false
+for ac_c_preproc_warn_flag in '' yes
+do
+  # Use a header file that comes with gcc, so configuring glibc
+  # with a fresh cross-compiler works.
+  # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+  # <limits.h> exists even on freestanding compilers.
+  # On the NeXT, cc -E runs the code through the compiler's parser,
+  # not just through cpp. "Syntax error" is here to catch this case.
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+                    Syntax error
+_ACEOF
+if { (ac_try="$ac_cpp conftest.$ac_ext"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } >/dev/null && {
+        test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       }; then
+  :
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+  # Broken: fails on valid input.
+continue
+fi
+
+rm -f conftest.err conftest.$ac_ext
+
+  # OK, works on sane cases.  Now check whether nonexistent headers
+  # can be detected and how.
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <ac_nonexistent.h>
+_ACEOF
+if { (ac_try="$ac_cpp conftest.$ac_ext"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } >/dev/null && {
+        test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       }; then
+  # Broken: success on invalid input.
+continue
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+  # Passes both tests.
+ac_preproc_ok=:
+break
+fi
+
+rm -f conftest.err conftest.$ac_ext
+
+done
+# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
+rm -f conftest.err conftest.$ac_ext
+if $ac_preproc_ok; then
+  break
+fi
+
+    done
+    ac_cv_prog_CPP=$CPP
+
+fi
+  CPP=$ac_cv_prog_CPP
+else
+  ac_cv_prog_CPP=$CPP
+fi
+{ echo "$as_me:$LINENO: result: $CPP" >&5
+echo "${ECHO_T}$CPP" >&6; }
+ac_preproc_ok=false
+for ac_c_preproc_warn_flag in '' yes
+do
+  # Use a header file that comes with gcc, so configuring glibc
+  # with a fresh cross-compiler works.
+  # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+  # <limits.h> exists even on freestanding compilers.
+  # On the NeXT, cc -E runs the code through the compiler's parser,
+  # not just through cpp. "Syntax error" is here to catch this case.
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+                    Syntax error
+_ACEOF
+if { (ac_try="$ac_cpp conftest.$ac_ext"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } >/dev/null && {
+        test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       }; then
+  :
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+  # Broken: fails on valid input.
+continue
+fi
+
+rm -f conftest.err conftest.$ac_ext
+
+  # OK, works on sane cases.  Now check whether nonexistent headers
+  # can be detected and how.
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <ac_nonexistent.h>
+_ACEOF
+if { (ac_try="$ac_cpp conftest.$ac_ext"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } >/dev/null && {
+        test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       }; then
+  # Broken: success on invalid input.
+continue
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+  # Passes both tests.
+ac_preproc_ok=:
+break
+fi
+
+rm -f conftest.err conftest.$ac_ext
+
+done
+# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
+rm -f conftest.err conftest.$ac_ext
+if $ac_preproc_ok; then
+  :
+else
+  { { echo "$as_me:$LINENO: error: C preprocessor \"$CPP\" fails sanity check
+See \`config.log' for more details." >&5
+echo "$as_me: error: C preprocessor \"$CPP\" fails sanity check
+See \`config.log' for more details." >&2;}
+   { (exit 1); exit 1; }; }
+fi
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+{ echo "$as_me:$LINENO: checking for grep that handles long lines and -e" >&5
+echo $ECHO_N "checking for grep that handles long lines and -e... $ECHO_C" >&6; }
+if test "${ac_cv_path_GREP+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  # Extract the first word of "grep ggrep" to use in msg output
+if test -z "$GREP"; then
+set dummy grep ggrep; ac_prog_name=$2
+if test "${ac_cv_path_GREP+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_path_GREP_found=false
+# Loop through the user's path and test for each of PROGNAME-LIST
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_prog in grep ggrep; do
+  for ac_exec_ext in '' $ac_executable_extensions; do
+    ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext"
+    { test -f "$ac_path_GREP" && $as_test_x "$ac_path_GREP"; } || continue
+    # Check for GNU ac_path_GREP and select it if it is found.
+  # Check for GNU $ac_path_GREP
+case `"$ac_path_GREP" --version 2>&1` in
+*GNU*)
+  ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;;
+*)
+  ac_count=0
+  echo $ECHO_N "0123456789$ECHO_C" >"conftest.in"
+  while :
+  do
+    cat "conftest.in" "conftest.in" >"conftest.tmp"
+    mv "conftest.tmp" "conftest.in"
+    cp "conftest.in" "conftest.nl"
+    echo 'GREP' >> "conftest.nl"
+    "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break
+    diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
+    ac_count=`expr $ac_count + 1`
+    if test $ac_count -gt ${ac_path_GREP_max-0}; then
+      # Best one so far, save it but keep looking for a better one
+      ac_cv_path_GREP="$ac_path_GREP"
+      ac_path_GREP_max=$ac_count
+    fi
+    # 10*(2^10) chars as input seems more than enough
+    test $ac_count -gt 10 && break
+  done
+  rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
+esac
+
+
+    $ac_path_GREP_found && break 3
+  done
+done
+
+done
+IFS=$as_save_IFS
+
+
+fi
+
+GREP="$ac_cv_path_GREP"
+if test -z "$GREP"; then
+  { { echo "$as_me:$LINENO: error: no acceptable $ac_prog_name could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" >&5
+echo "$as_me: error: no acceptable $ac_prog_name could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" >&2;}
+   { (exit 1); exit 1; }; }
+fi
+
+else
+  ac_cv_path_GREP=$GREP
+fi
+
+
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_path_GREP" >&5
+echo "${ECHO_T}$ac_cv_path_GREP" >&6; }
+ GREP="$ac_cv_path_GREP"
+
+
+{ echo "$as_me:$LINENO: checking for egrep" >&5
+echo $ECHO_N "checking for egrep... $ECHO_C" >&6; }
+if test "${ac_cv_path_EGREP+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if echo a | $GREP -E '(a|b)' >/dev/null 2>&1
+   then ac_cv_path_EGREP="$GREP -E"
+   else
+     # Extract the first word of "egrep" to use in msg output
+if test -z "$EGREP"; then
+set dummy egrep; ac_prog_name=$2
+if test "${ac_cv_path_EGREP+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_path_EGREP_found=false
+# Loop through the user's path and test for each of PROGNAME-LIST
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_prog in egrep; do
+  for ac_exec_ext in '' $ac_executable_extensions; do
+    ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext"
+    { test -f "$ac_path_EGREP" && $as_test_x "$ac_path_EGREP"; } || continue
+    # Check for GNU ac_path_EGREP and select it if it is found.
+  # Check for GNU $ac_path_EGREP
+case `"$ac_path_EGREP" --version 2>&1` in
+*GNU*)
+  ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;;
+*)
+  ac_count=0
+  echo $ECHO_N "0123456789$ECHO_C" >"conftest.in"
+  while :
+  do
+    cat "conftest.in" "conftest.in" >"conftest.tmp"
+    mv "conftest.tmp" "conftest.in"
+    cp "conftest.in" "conftest.nl"
+    echo 'EGREP' >> "conftest.nl"
+    "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break
+    diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
+    ac_count=`expr $ac_count + 1`
+    if test $ac_count -gt ${ac_path_EGREP_max-0}; then
+      # Best one so far, save it but keep looking for a better one
+      ac_cv_path_EGREP="$ac_path_EGREP"
+      ac_path_EGREP_max=$ac_count
+    fi
+    # 10*(2^10) chars as input seems more than enough
+    test $ac_count -gt 10 && break
+  done
+  rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
+esac
+
+
+    $ac_path_EGREP_found && break 3
+  done
+done
+
+done
+IFS=$as_save_IFS
+
+
+fi
+
+EGREP="$ac_cv_path_EGREP"
+if test -z "$EGREP"; then
+  { { echo "$as_me:$LINENO: error: no acceptable $ac_prog_name could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" >&5
+echo "$as_me: error: no acceptable $ac_prog_name could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" >&2;}
+   { (exit 1); exit 1; }; }
+fi
+
+else
+  ac_cv_path_EGREP=$EGREP
+fi
+
+
+   fi
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_path_EGREP" >&5
+echo "${ECHO_T}$ac_cv_path_EGREP" >&6; }
+ EGREP="$ac_cv_path_EGREP"
+
+
+{ echo "$as_me:$LINENO: checking for ANSI C header files" >&5
+echo $ECHO_N "checking for ANSI C header files... $ECHO_C" >&6; }
+if test "${ac_cv_header_stdc+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <float.h>
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_cv_header_stdc=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_header_stdc=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
+if test $ac_cv_header_stdc = yes; then
+  # SunOS 4.x string.h does not declare mem*, contrary to ANSI.
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <string.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  $EGREP "memchr" >/dev/null 2>&1; then
+  :
+else
+  ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+  # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI.
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <stdlib.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  $EGREP "free" >/dev/null 2>&1; then
+  :
+else
+  ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+  # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi.
+  if test "$cross_compiling" = yes; then
+  :
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <ctype.h>
+#include <stdlib.h>
+#if ((' ' & 0x0FF) == 0x020)
+# define ISLOWER(c) ('a' <= (c) && (c) <= 'z')
+# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c))
+#else
+# define ISLOWER(c) \
+                  (('a' <= (c) && (c) <= 'i') \
+                    || ('j' <= (c) && (c) <= 'r') \
+                    || ('s' <= (c) && (c) <= 'z'))
+# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c))
+#endif
+
+#define XOR(e, f) (((e) && !(f)) || (!(e) && (f)))
+int
+main ()
+{
+  int i;
+  for (i = 0; i < 256; i++)
+    if (XOR (islower (i), ISLOWER (i))
+       || toupper (i) != TOUPPER (i))
+      return 2;
+  return 0;
+}
+_ACEOF
+rm -f conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
+  { (case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_try") 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  :
+else
+  echo "$as_me: program exited with status $ac_status" >&5
+echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+( exit $ac_status )
+ac_cv_header_stdc=no
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+fi
+
+
+fi
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_header_stdc" >&5
+echo "${ECHO_T}$ac_cv_header_stdc" >&6; }
+if test $ac_cv_header_stdc = yes; then
+
+cat >>confdefs.h <<\_ACEOF
+#define STDC_HEADERS 1
+_ACEOF
+
+fi
+
+# On IRIX 5.3, sys/types and inttypes.h are conflicting.
+
+
+
+
+
+
+
+
+
+for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \
+                 inttypes.h stdint.h unistd.h
+do
+as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
+{ echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; }
+if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+
+#include <$ac_header>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  eval "$as_ac_Header=yes"
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       eval "$as_ac_Header=no"
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+ac_res=`eval echo '${'$as_ac_Header'}'`
+              { echo "$as_me:$LINENO: result: $ac_res" >&5
+echo "${ECHO_T}$ac_res" >&6; }
+if test `eval echo '${'$as_ac_Header'}'` = yes; then
+  cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+
+
+
+
+
+
+
+
+
+
+
+for ac_header in crypt.h poll.h inttypes.h stdint.h sys/devpoll.h sys/epoll.h sys/event.h sys/param.h sys/resource.h sys/socket.h
+do
+as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
+if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
+  { echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; }
+if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+fi
+ac_res=`eval echo '${'$as_ac_Header'}'`
+              { echo "$as_me:$LINENO: result: $ac_res" >&5
+echo "${ECHO_T}$ac_res" >&6; }
+else
+  # Is the header compilable?
+{ echo "$as_me:$LINENO: checking $ac_header usability" >&5
+echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6; }
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+#include <$ac_header>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_header_compiler=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_header_compiler=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+{ echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
+echo "${ECHO_T}$ac_header_compiler" >&6; }
+
+# Is the header present?
+{ echo "$as_me:$LINENO: checking $ac_header presence" >&5
+echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6; }
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <$ac_header>
+_ACEOF
+if { (ac_try="$ac_cpp conftest.$ac_ext"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } >/dev/null && {
+        test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       }; then
+  ac_header_preproc=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+  ac_header_preproc=no
+fi
+
+rm -f conftest.err conftest.$ac_ext
+{ echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
+echo "${ECHO_T}$ac_header_preproc" >&6; }
+
+# So?  What about this header?
+case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
+  yes:no: )
+    { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5
+echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;}
+    ac_header_preproc=yes
+    ;;
+  no:yes:* )
+    { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5
+echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header:     check for missing prerequisite headers?" >&5
+echo "$as_me: WARNING: $ac_header:     check for missing prerequisite headers?" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5
+echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&5
+echo "$as_me: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5
+echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;}
+
+    ;;
+esac
+{ echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; }
+if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  eval "$as_ac_Header=\$ac_header_preproc"
+fi
+ac_res=`eval echo '${'$as_ac_Header'}'`
+              { echo "$as_me:$LINENO: result: $ac_res" >&5
+echo "${ECHO_T}$ac_res" >&6; }
+
+fi
+if test `eval echo '${'$as_ac_Header'}'` = yes; then
+  cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+
+{ echo "$as_me:$LINENO: checking whether byte ordering is bigendian" >&5
+echo $ECHO_N "checking whether byte ordering is bigendian... $ECHO_C" >&6; }
+if test "${ac_cv_c_bigendian+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  # See if sys/param.h defines the BYTE_ORDER macro.
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <sys/types.h>
+#include <sys/param.h>
+
+int
+main ()
+{
+#if  ! (defined BYTE_ORDER && defined BIG_ENDIAN && defined LITTLE_ENDIAN \
+       && BYTE_ORDER && BIG_ENDIAN && LITTLE_ENDIAN)
+ bogus endian macros
+#endif
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  # It does; now see whether it defined to BIG_ENDIAN or not.
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <sys/types.h>
+#include <sys/param.h>
+
+int
+main ()
+{
+#if BYTE_ORDER != BIG_ENDIAN
+ not big endian
+#endif
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_cv_c_bigendian=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_c_bigendian=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       # It does not; compile a test program.
+if test "$cross_compiling" = yes; then
+  # try to guess the endianness by grepping values into an object file
+  ac_cv_c_bigendian=unknown
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+short int ascii_mm[] = { 0x4249, 0x4765, 0x6E44, 0x6961, 0x6E53, 0x7953, 0 };
+short int ascii_ii[] = { 0x694C, 0x5454, 0x656C, 0x6E45, 0x6944, 0x6E61, 0 };
+void _ascii () { char *s = (char *) ascii_mm; s = (char *) ascii_ii; }
+short int ebcdic_ii[] = { 0x89D3, 0xE3E3, 0x8593, 0x95C5, 0x89C4, 0x9581, 0 };
+short int ebcdic_mm[] = { 0xC2C9, 0xC785, 0x95C4, 0x8981, 0x95E2, 0xA8E2, 0 };
+void _ebcdic () { char *s = (char *) ebcdic_mm; s = (char *) ebcdic_ii; }
+int
+main ()
+{
+ _ascii (); _ebcdic ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  if grep BIGenDianSyS conftest.$ac_objext >/dev/null ; then
+  ac_cv_c_bigendian=yes
+fi
+if grep LiTTleEnDian conftest.$ac_objext >/dev/null ; then
+  if test "$ac_cv_c_bigendian" = unknown; then
+    ac_cv_c_bigendian=no
+  else
+    # finding both strings is unlikely to happen, but who knows?
+    ac_cv_c_bigendian=unknown
+  fi
+fi
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+int
+main ()
+{
+
+  /* Are we little or big endian?  From Harbison&Steele.  */
+  union
+  {
+    long int l;
+    char c[sizeof (long int)];
+  } u;
+  u.l = 1;
+  return u.c[sizeof (long int) - 1] == 1;
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
+  { (case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_try") 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_c_bigendian=no
+else
+  echo "$as_me: program exited with status $ac_status" >&5
+echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+( exit $ac_status )
+ac_cv_c_bigendian=yes
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+fi
+
+
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_c_bigendian" >&5
+echo "${ECHO_T}$ac_cv_c_bigendian" >&6; }
+case $ac_cv_c_bigendian in
+  yes)
+
+cat >>confdefs.h <<\_ACEOF
+#define WORDS_BIGENDIAN 1
+_ACEOF
+ ;;
+  no)
+     ;;
+  *)
+    { { echo "$as_me:$LINENO: error: unknown endianness
+presetting ac_cv_c_bigendian=no (or yes) will help" >&5
+echo "$as_me: error: unknown endianness
+presetting ac_cv_c_bigendian=no (or yes) will help" >&2;}
+   { (exit 1); exit 1; }; } ;;
+esac
+
+{ echo "$as_me:$LINENO: checking for size_t" >&5
+echo $ECHO_N "checking for size_t... $ECHO_C" >&6; }
+if test "${ac_cv_type_size_t+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+typedef size_t ac__type_new_;
+int
+main ()
+{
+if ((ac__type_new_ *) 0)
+  return 0;
+if (sizeof (ac__type_new_))
+  return 0;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_cv_type_size_t=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_type_size_t=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_type_size_t" >&5
+echo "${ECHO_T}$ac_cv_type_size_t" >&6; }
+if test $ac_cv_type_size_t = yes; then
+  :
+else
+
+cat >>confdefs.h <<_ACEOF
+#define size_t unsigned int
+_ACEOF
+
+fi
+
+{ echo "$as_me:$LINENO: checking whether time.h and sys/time.h may both be included" >&5
+echo $ECHO_N "checking whether time.h and sys/time.h may both be included... $ECHO_C" >&6; }
+if test "${ac_cv_header_time+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <sys/types.h>
+#include <sys/time.h>
+#include <time.h>
+
+int
+main ()
+{
+if ((struct tm *) 0)
+return 0;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_cv_header_time=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_header_time=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_header_time" >&5
+echo "${ECHO_T}$ac_cv_header_time" >&6; }
+if test $ac_cv_header_time = yes; then
+
+cat >>confdefs.h <<\_ACEOF
+#define TIME_WITH_SYS_TIME 1
+_ACEOF
+
+fi
+
+{ echo "$as_me:$LINENO: checking whether struct tm is in sys/time.h or time.h" >&5
+echo $ECHO_N "checking whether struct tm is in sys/time.h or time.h... $ECHO_C" >&6; }
+if test "${ac_cv_struct_tm+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <sys/types.h>
+#include <time.h>
+
+int
+main ()
+{
+struct tm tm;
+                                    int *p = &tm.tm_sec;
+                                    return !p;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_cv_struct_tm=time.h
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_struct_tm=sys/time.h
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_struct_tm" >&5
+echo "${ECHO_T}$ac_cv_struct_tm" >&6; }
+if test $ac_cv_struct_tm = sys/time.h; then
+
+cat >>confdefs.h <<\_ACEOF
+#define TM_IN_SYS_TIME 1
+_ACEOF
+
+fi
+
+{ echo "$as_me:$LINENO: checking for uid_t in sys/types.h" >&5
+echo $ECHO_N "checking for uid_t in sys/types.h... $ECHO_C" >&6; }
+if test "${ac_cv_type_uid_t+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <sys/types.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  $EGREP "uid_t" >/dev/null 2>&1; then
+  ac_cv_type_uid_t=yes
+else
+  ac_cv_type_uid_t=no
+fi
+rm -f conftest*
+
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_type_uid_t" >&5
+echo "${ECHO_T}$ac_cv_type_uid_t" >&6; }
+if test $ac_cv_type_uid_t = no; then
+
+cat >>confdefs.h <<\_ACEOF
+#define uid_t int
+_ACEOF
+
+
+cat >>confdefs.h <<\_ACEOF
+#define gid_t int
+_ACEOF
+
+fi
+
+{ echo "$as_me:$LINENO: checking for short" >&5
+echo $ECHO_N "checking for short... $ECHO_C" >&6; }
+if test "${ac_cv_type_short+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+typedef short ac__type_new_;
+int
+main ()
+{
+if ((ac__type_new_ *) 0)
+  return 0;
+if (sizeof (ac__type_new_))
+  return 0;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_cv_type_short=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_type_short=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_type_short" >&5
+echo "${ECHO_T}$ac_cv_type_short" >&6; }
+
+# The cast to long int works around a bug in the HP C Compiler
+# version HP92453-01 B.11.11.23709.GP, which incorrectly rejects
+# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'.
+# This bug is HP SR number 8606223364.
+{ echo "$as_me:$LINENO: checking size of short" >&5
+echo $ECHO_N "checking size of short... $ECHO_C" >&6; }
+if test "${ac_cv_sizeof_short+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if test "$cross_compiling" = yes; then
+  # Depending upon the size, compute the lo and hi bounds.
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+   typedef short ac__type_sizeof_;
+int
+main ()
+{
+static int test_array [1 - 2 * !(((long int) (sizeof (ac__type_sizeof_))) >= 0)];
+test_array [0] = 0
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_lo=0 ac_mid=0
+  while :; do
+    cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+   typedef short ac__type_sizeof_;
+int
+main ()
+{
+static int test_array [1 - 2 * !(((long int) (sizeof (ac__type_sizeof_))) <= $ac_mid)];
+test_array [0] = 0
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_hi=$ac_mid; break
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_lo=`expr $ac_mid + 1`
+                       if test $ac_lo -le $ac_mid; then
+                         ac_lo= ac_hi=
+                         break
+                       fi
+                       ac_mid=`expr 2 '*' $ac_mid + 1`
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+  done
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+   typedef short ac__type_sizeof_;
+int
+main ()
+{
+static int test_array [1 - 2 * !(((long int) (sizeof (ac__type_sizeof_))) < 0)];
+test_array [0] = 0
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_hi=-1 ac_mid=-1
+  while :; do
+    cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+   typedef short ac__type_sizeof_;
+int
+main ()
+{
+static int test_array [1 - 2 * !(((long int) (sizeof (ac__type_sizeof_))) >= $ac_mid)];
+test_array [0] = 0
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_lo=$ac_mid; break
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_hi=`expr '(' $ac_mid ')' - 1`
+                       if test $ac_mid -le $ac_hi; then
+                         ac_lo= ac_hi=
+                         break
+                       fi
+                       ac_mid=`expr 2 '*' $ac_mid`
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+  done
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_lo= ac_hi=
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+# Binary search between lo and hi bounds.
+while test "x$ac_lo" != "x$ac_hi"; do
+  ac_mid=`expr '(' $ac_hi - $ac_lo ')' / 2 + $ac_lo`
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+   typedef short ac__type_sizeof_;
+int
+main ()
+{
+static int test_array [1 - 2 * !(((long int) (sizeof (ac__type_sizeof_))) <= $ac_mid)];
+test_array [0] = 0
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_hi=$ac_mid
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_lo=`expr '(' $ac_mid ')' + 1`
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+done
+case $ac_lo in
+?*) ac_cv_sizeof_short=$ac_lo;;
+'') if test "$ac_cv_type_short" = yes; then
+     { { echo "$as_me:$LINENO: error: cannot compute sizeof (short)
+See \`config.log' for more details." >&5
+echo "$as_me: error: cannot compute sizeof (short)
+See \`config.log' for more details." >&2;}
+   { (exit 77); exit 77; }; }
+   else
+     ac_cv_sizeof_short=0
+   fi ;;
+esac
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+   typedef short ac__type_sizeof_;
+static long int longval () { return (long int) (sizeof (ac__type_sizeof_)); }
+static unsigned long int ulongval () { return (long int) (sizeof (ac__type_sizeof_)); }
+#include <stdio.h>
+#include <stdlib.h>
+int
+main ()
+{
+
+  FILE *f = fopen ("conftest.val", "w");
+  if (! f)
+    return 1;
+  if (((long int) (sizeof (ac__type_sizeof_))) < 0)
+    {
+      long int i = longval ();
+      if (i != ((long int) (sizeof (ac__type_sizeof_))))
+       return 1;
+      fprintf (f, "%ld\n", i);
+    }
+  else
+    {
+      unsigned long int i = ulongval ();
+      if (i != ((long int) (sizeof (ac__type_sizeof_))))
+       return 1;
+      fprintf (f, "%lu\n", i);
+    }
+  return ferror (f) || fclose (f) != 0;
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
+  { (case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_try") 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_sizeof_short=`cat conftest.val`
+else
+  echo "$as_me: program exited with status $ac_status" >&5
+echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+( exit $ac_status )
+if test "$ac_cv_type_short" = yes; then
+     { { echo "$as_me:$LINENO: error: cannot compute sizeof (short)
+See \`config.log' for more details." >&5
+echo "$as_me: error: cannot compute sizeof (short)
+See \`config.log' for more details." >&2;}
+   { (exit 77); exit 77; }; }
+   else
+     ac_cv_sizeof_short=0
+   fi
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f conftest.val
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_sizeof_short" >&5
+echo "${ECHO_T}$ac_cv_sizeof_short" >&6; }
+
+
+
+cat >>confdefs.h <<_ACEOF
+#define SIZEOF_SHORT $ac_cv_sizeof_short
+_ACEOF
+
+
+{ echo "$as_me:$LINENO: checking for int" >&5
+echo $ECHO_N "checking for int... $ECHO_C" >&6; }
+if test "${ac_cv_type_int+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+typedef int ac__type_new_;
+int
+main ()
+{
+if ((ac__type_new_ *) 0)
+  return 0;
+if (sizeof (ac__type_new_))
+  return 0;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_cv_type_int=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_type_int=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_type_int" >&5
+echo "${ECHO_T}$ac_cv_type_int" >&6; }
+
+# The cast to long int works around a bug in the HP C Compiler
+# version HP92453-01 B.11.11.23709.GP, which incorrectly rejects
+# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'.
+# This bug is HP SR number 8606223364.
+{ echo "$as_me:$LINENO: checking size of int" >&5
+echo $ECHO_N "checking size of int... $ECHO_C" >&6; }
+if test "${ac_cv_sizeof_int+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if test "$cross_compiling" = yes; then
+  # Depending upon the size, compute the lo and hi bounds.
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+   typedef int ac__type_sizeof_;
+int
+main ()
+{
+static int test_array [1 - 2 * !(((long int) (sizeof (ac__type_sizeof_))) >= 0)];
+test_array [0] = 0
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_lo=0 ac_mid=0
+  while :; do
+    cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+   typedef int ac__type_sizeof_;
+int
+main ()
+{
+static int test_array [1 - 2 * !(((long int) (sizeof (ac__type_sizeof_))) <= $ac_mid)];
+test_array [0] = 0
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_hi=$ac_mid; break
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_lo=`expr $ac_mid + 1`
+                       if test $ac_lo -le $ac_mid; then
+                         ac_lo= ac_hi=
+                         break
+                       fi
+                       ac_mid=`expr 2 '*' $ac_mid + 1`
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+  done
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+   typedef int ac__type_sizeof_;
+int
+main ()
+{
+static int test_array [1 - 2 * !(((long int) (sizeof (ac__type_sizeof_))) < 0)];
+test_array [0] = 0
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_hi=-1 ac_mid=-1
+  while :; do
+    cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+   typedef int ac__type_sizeof_;
+int
+main ()
+{
+static int test_array [1 - 2 * !(((long int) (sizeof (ac__type_sizeof_))) >= $ac_mid)];
+test_array [0] = 0
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_lo=$ac_mid; break
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_hi=`expr '(' $ac_mid ')' - 1`
+                       if test $ac_mid -le $ac_hi; then
+                         ac_lo= ac_hi=
+                         break
+                       fi
+                       ac_mid=`expr 2 '*' $ac_mid`
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+  done
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_lo= ac_hi=
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+# Binary search between lo and hi bounds.
+while test "x$ac_lo" != "x$ac_hi"; do
+  ac_mid=`expr '(' $ac_hi - $ac_lo ')' / 2 + $ac_lo`
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+   typedef int ac__type_sizeof_;
+int
+main ()
+{
+static int test_array [1 - 2 * !(((long int) (sizeof (ac__type_sizeof_))) <= $ac_mid)];
+test_array [0] = 0
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_hi=$ac_mid
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_lo=`expr '(' $ac_mid ')' + 1`
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+done
+case $ac_lo in
+?*) ac_cv_sizeof_int=$ac_lo;;
+'') if test "$ac_cv_type_int" = yes; then
+     { { echo "$as_me:$LINENO: error: cannot compute sizeof (int)
+See \`config.log' for more details." >&5
+echo "$as_me: error: cannot compute sizeof (int)
+See \`config.log' for more details." >&2;}
+   { (exit 77); exit 77; }; }
+   else
+     ac_cv_sizeof_int=0
+   fi ;;
+esac
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+   typedef int ac__type_sizeof_;
+static long int longval () { return (long int) (sizeof (ac__type_sizeof_)); }
+static unsigned long int ulongval () { return (long int) (sizeof (ac__type_sizeof_)); }
+#include <stdio.h>
+#include <stdlib.h>
+int
+main ()
+{
+
+  FILE *f = fopen ("conftest.val", "w");
+  if (! f)
+    return 1;
+  if (((long int) (sizeof (ac__type_sizeof_))) < 0)
+    {
+      long int i = longval ();
+      if (i != ((long int) (sizeof (ac__type_sizeof_))))
+       return 1;
+      fprintf (f, "%ld\n", i);
+    }
+  else
+    {
+      unsigned long int i = ulongval ();
+      if (i != ((long int) (sizeof (ac__type_sizeof_))))
+       return 1;
+      fprintf (f, "%lu\n", i);
+    }
+  return ferror (f) || fclose (f) != 0;
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
+  { (case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_try") 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_sizeof_int=`cat conftest.val`
+else
+  echo "$as_me: program exited with status $ac_status" >&5
+echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+( exit $ac_status )
+if test "$ac_cv_type_int" = yes; then
+     { { echo "$as_me:$LINENO: error: cannot compute sizeof (int)
+See \`config.log' for more details." >&5
+echo "$as_me: error: cannot compute sizeof (int)
+See \`config.log' for more details." >&2;}
+   { (exit 77); exit 77; }; }
+   else
+     ac_cv_sizeof_int=0
+   fi
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f conftest.val
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_sizeof_int" >&5
+echo "${ECHO_T}$ac_cv_sizeof_int" >&6; }
+
+
+
+cat >>confdefs.h <<_ACEOF
+#define SIZEOF_INT $ac_cv_sizeof_int
+_ACEOF
+
+
+{ echo "$as_me:$LINENO: checking for long" >&5
+echo $ECHO_N "checking for long... $ECHO_C" >&6; }
+if test "${ac_cv_type_long+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+typedef long ac__type_new_;
+int
+main ()
+{
+if ((ac__type_new_ *) 0)
+  return 0;
+if (sizeof (ac__type_new_))
+  return 0;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_cv_type_long=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_type_long=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_type_long" >&5
+echo "${ECHO_T}$ac_cv_type_long" >&6; }
+
+# The cast to long int works around a bug in the HP C Compiler
+# version HP92453-01 B.11.11.23709.GP, which incorrectly rejects
+# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'.
+# This bug is HP SR number 8606223364.
+{ echo "$as_me:$LINENO: checking size of long" >&5
+echo $ECHO_N "checking size of long... $ECHO_C" >&6; }
+if test "${ac_cv_sizeof_long+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if test "$cross_compiling" = yes; then
+  # Depending upon the size, compute the lo and hi bounds.
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+   typedef long ac__type_sizeof_;
+int
+main ()
+{
+static int test_array [1 - 2 * !(((long int) (sizeof (ac__type_sizeof_))) >= 0)];
+test_array [0] = 0
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_lo=0 ac_mid=0
+  while :; do
+    cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+   typedef long ac__type_sizeof_;
+int
+main ()
+{
+static int test_array [1 - 2 * !(((long int) (sizeof (ac__type_sizeof_))) <= $ac_mid)];
+test_array [0] = 0
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_hi=$ac_mid; break
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_lo=`expr $ac_mid + 1`
+                       if test $ac_lo -le $ac_mid; then
+                         ac_lo= ac_hi=
+                         break
+                       fi
+                       ac_mid=`expr 2 '*' $ac_mid + 1`
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+  done
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+   typedef long ac__type_sizeof_;
+int
+main ()
+{
+static int test_array [1 - 2 * !(((long int) (sizeof (ac__type_sizeof_))) < 0)];
+test_array [0] = 0
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_hi=-1 ac_mid=-1
+  while :; do
+    cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+   typedef long ac__type_sizeof_;
+int
+main ()
+{
+static int test_array [1 - 2 * !(((long int) (sizeof (ac__type_sizeof_))) >= $ac_mid)];
+test_array [0] = 0
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_lo=$ac_mid; break
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_hi=`expr '(' $ac_mid ')' - 1`
+                       if test $ac_mid -le $ac_hi; then
+                         ac_lo= ac_hi=
+                         break
+                       fi
+                       ac_mid=`expr 2 '*' $ac_mid`
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+  done
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_lo= ac_hi=
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+# Binary search between lo and hi bounds.
+while test "x$ac_lo" != "x$ac_hi"; do
+  ac_mid=`expr '(' $ac_hi - $ac_lo ')' / 2 + $ac_lo`
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+   typedef long ac__type_sizeof_;
+int
+main ()
+{
+static int test_array [1 - 2 * !(((long int) (sizeof (ac__type_sizeof_))) <= $ac_mid)];
+test_array [0] = 0
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_hi=$ac_mid
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_lo=`expr '(' $ac_mid ')' + 1`
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+done
+case $ac_lo in
+?*) ac_cv_sizeof_long=$ac_lo;;
+'') if test "$ac_cv_type_long" = yes; then
+     { { echo "$as_me:$LINENO: error: cannot compute sizeof (long)
+See \`config.log' for more details." >&5
+echo "$as_me: error: cannot compute sizeof (long)
+See \`config.log' for more details." >&2;}
+   { (exit 77); exit 77; }; }
+   else
+     ac_cv_sizeof_long=0
+   fi ;;
+esac
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+   typedef long ac__type_sizeof_;
+static long int longval () { return (long int) (sizeof (ac__type_sizeof_)); }
+static unsigned long int ulongval () { return (long int) (sizeof (ac__type_sizeof_)); }
+#include <stdio.h>
+#include <stdlib.h>
+int
+main ()
+{
+
+  FILE *f = fopen ("conftest.val", "w");
+  if (! f)
+    return 1;
+  if (((long int) (sizeof (ac__type_sizeof_))) < 0)
+    {
+      long int i = longval ();
+      if (i != ((long int) (sizeof (ac__type_sizeof_))))
+       return 1;
+      fprintf (f, "%ld\n", i);
+    }
+  else
+    {
+      unsigned long int i = ulongval ();
+      if (i != ((long int) (sizeof (ac__type_sizeof_))))
+       return 1;
+      fprintf (f, "%lu\n", i);
+    }
+  return ferror (f) || fclose (f) != 0;
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
+  { (case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_try") 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_sizeof_long=`cat conftest.val`
+else
+  echo "$as_me: program exited with status $ac_status" >&5
+echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+( exit $ac_status )
+if test "$ac_cv_type_long" = yes; then
+     { { echo "$as_me:$LINENO: error: cannot compute sizeof (long)
+See \`config.log' for more details." >&5
+echo "$as_me: error: cannot compute sizeof (long)
+See \`config.log' for more details." >&2;}
+   { (exit 77); exit 77; }; }
+   else
+     ac_cv_sizeof_long=0
+   fi
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f conftest.val
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_sizeof_long" >&5
+echo "${ECHO_T}$ac_cv_sizeof_long" >&6; }
+
+
+
+cat >>confdefs.h <<_ACEOF
+#define SIZEOF_LONG $ac_cv_sizeof_long
+_ACEOF
+
+
+{ echo "$as_me:$LINENO: checking for void *" >&5
+echo $ECHO_N "checking for void *... $ECHO_C" >&6; }
+if test "${ac_cv_type_void_p+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+typedef void * ac__type_new_;
+int
+main ()
+{
+if ((ac__type_new_ *) 0)
+  return 0;
+if (sizeof (ac__type_new_))
+  return 0;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_cv_type_void_p=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_type_void_p=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_type_void_p" >&5
+echo "${ECHO_T}$ac_cv_type_void_p" >&6; }
+
+# The cast to long int works around a bug in the HP C Compiler
+# version HP92453-01 B.11.11.23709.GP, which incorrectly rejects
+# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'.
+# This bug is HP SR number 8606223364.
+{ echo "$as_me:$LINENO: checking size of void *" >&5
+echo $ECHO_N "checking size of void *... $ECHO_C" >&6; }
+if test "${ac_cv_sizeof_void_p+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if test "$cross_compiling" = yes; then
+  # Depending upon the size, compute the lo and hi bounds.
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+   typedef void * ac__type_sizeof_;
+int
+main ()
+{
+static int test_array [1 - 2 * !(((long int) (sizeof (ac__type_sizeof_))) >= 0)];
+test_array [0] = 0
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_lo=0 ac_mid=0
+  while :; do
+    cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+   typedef void * ac__type_sizeof_;
+int
+main ()
+{
+static int test_array [1 - 2 * !(((long int) (sizeof (ac__type_sizeof_))) <= $ac_mid)];
+test_array [0] = 0
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_hi=$ac_mid; break
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_lo=`expr $ac_mid + 1`
+                       if test $ac_lo -le $ac_mid; then
+                         ac_lo= ac_hi=
+                         break
+                       fi
+                       ac_mid=`expr 2 '*' $ac_mid + 1`
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+  done
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+   typedef void * ac__type_sizeof_;
+int
+main ()
+{
+static int test_array [1 - 2 * !(((long int) (sizeof (ac__type_sizeof_))) < 0)];
+test_array [0] = 0
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_hi=-1 ac_mid=-1
+  while :; do
+    cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+   typedef void * ac__type_sizeof_;
+int
+main ()
+{
+static int test_array [1 - 2 * !(((long int) (sizeof (ac__type_sizeof_))) >= $ac_mid)];
+test_array [0] = 0
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_lo=$ac_mid; break
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_hi=`expr '(' $ac_mid ')' - 1`
+                       if test $ac_mid -le $ac_hi; then
+                         ac_lo= ac_hi=
+                         break
+                       fi
+                       ac_mid=`expr 2 '*' $ac_mid`
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+  done
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_lo= ac_hi=
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+# Binary search between lo and hi bounds.
+while test "x$ac_lo" != "x$ac_hi"; do
+  ac_mid=`expr '(' $ac_hi - $ac_lo ')' / 2 + $ac_lo`
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+   typedef void * ac__type_sizeof_;
+int
+main ()
+{
+static int test_array [1 - 2 * !(((long int) (sizeof (ac__type_sizeof_))) <= $ac_mid)];
+test_array [0] = 0
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_hi=$ac_mid
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_lo=`expr '(' $ac_mid ')' + 1`
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+done
+case $ac_lo in
+?*) ac_cv_sizeof_void_p=$ac_lo;;
+'') if test "$ac_cv_type_void_p" = yes; then
+     { { echo "$as_me:$LINENO: error: cannot compute sizeof (void *)
+See \`config.log' for more details." >&5
+echo "$as_me: error: cannot compute sizeof (void *)
+See \`config.log' for more details." >&2;}
+   { (exit 77); exit 77; }; }
+   else
+     ac_cv_sizeof_void_p=0
+   fi ;;
+esac
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+   typedef void * ac__type_sizeof_;
+static long int longval () { return (long int) (sizeof (ac__type_sizeof_)); }
+static unsigned long int ulongval () { return (long int) (sizeof (ac__type_sizeof_)); }
+#include <stdio.h>
+#include <stdlib.h>
+int
+main ()
+{
+
+  FILE *f = fopen ("conftest.val", "w");
+  if (! f)
+    return 1;
+  if (((long int) (sizeof (ac__type_sizeof_))) < 0)
+    {
+      long int i = longval ();
+      if (i != ((long int) (sizeof (ac__type_sizeof_))))
+       return 1;
+      fprintf (f, "%ld\n", i);
+    }
+  else
+    {
+      unsigned long int i = ulongval ();
+      if (i != ((long int) (sizeof (ac__type_sizeof_))))
+       return 1;
+      fprintf (f, "%lu\n", i);
+    }
+  return ferror (f) || fclose (f) != 0;
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
+  { (case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_try") 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_sizeof_void_p=`cat conftest.val`
+else
+  echo "$as_me: program exited with status $ac_status" >&5
+echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+( exit $ac_status )
+if test "$ac_cv_type_void_p" = yes; then
+     { { echo "$as_me:$LINENO: error: cannot compute sizeof (void *)
+See \`config.log' for more details." >&5
+echo "$as_me: error: cannot compute sizeof (void *)
+See \`config.log' for more details." >&2;}
+   { (exit 77); exit 77; }; }
+   else
+     ac_cv_sizeof_void_p=0
+   fi
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f conftest.val
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_sizeof_void_p" >&5
+echo "${ECHO_T}$ac_cv_sizeof_void_p" >&6; }
+
+
+
+cat >>confdefs.h <<_ACEOF
+#define SIZEOF_VOID_P $ac_cv_sizeof_void_p
+_ACEOF
+
+
+{ echo "$as_me:$LINENO: checking for int64_t" >&5
+echo $ECHO_N "checking for int64_t... $ECHO_C" >&6; }
+if test "${ac_cv_type_int64_t+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+typedef int64_t ac__type_new_;
+int
+main ()
+{
+if ((ac__type_new_ *) 0)
+  return 0;
+if (sizeof (ac__type_new_))
+  return 0;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_cv_type_int64_t=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_type_int64_t=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_type_int64_t" >&5
+echo "${ECHO_T}$ac_cv_type_int64_t" >&6; }
+
+# The cast to long int works around a bug in the HP C Compiler
+# version HP92453-01 B.11.11.23709.GP, which incorrectly rejects
+# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'.
+# This bug is HP SR number 8606223364.
+{ echo "$as_me:$LINENO: checking size of int64_t" >&5
+echo $ECHO_N "checking size of int64_t... $ECHO_C" >&6; }
+if test "${ac_cv_sizeof_int64_t+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if test "$cross_compiling" = yes; then
+  # Depending upon the size, compute the lo and hi bounds.
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+   typedef int64_t ac__type_sizeof_;
+int
+main ()
+{
+static int test_array [1 - 2 * !(((long int) (sizeof (ac__type_sizeof_))) >= 0)];
+test_array [0] = 0
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_lo=0 ac_mid=0
+  while :; do
+    cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+   typedef int64_t ac__type_sizeof_;
+int
+main ()
+{
+static int test_array [1 - 2 * !(((long int) (sizeof (ac__type_sizeof_))) <= $ac_mid)];
+test_array [0] = 0
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_hi=$ac_mid; break
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_lo=`expr $ac_mid + 1`
+                       if test $ac_lo -le $ac_mid; then
+                         ac_lo= ac_hi=
+                         break
+                       fi
+                       ac_mid=`expr 2 '*' $ac_mid + 1`
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+  done
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+   typedef int64_t ac__type_sizeof_;
+int
+main ()
+{
+static int test_array [1 - 2 * !(((long int) (sizeof (ac__type_sizeof_))) < 0)];
+test_array [0] = 0
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_hi=-1 ac_mid=-1
+  while :; do
+    cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+   typedef int64_t ac__type_sizeof_;
+int
+main ()
+{
+static int test_array [1 - 2 * !(((long int) (sizeof (ac__type_sizeof_))) >= $ac_mid)];
+test_array [0] = 0
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_lo=$ac_mid; break
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_hi=`expr '(' $ac_mid ')' - 1`
+                       if test $ac_mid -le $ac_hi; then
+                         ac_lo= ac_hi=
+                         break
+                       fi
+                       ac_mid=`expr 2 '*' $ac_mid`
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+  done
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_lo= ac_hi=
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+# Binary search between lo and hi bounds.
+while test "x$ac_lo" != "x$ac_hi"; do
+  ac_mid=`expr '(' $ac_hi - $ac_lo ')' / 2 + $ac_lo`
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+   typedef int64_t ac__type_sizeof_;
+int
+main ()
+{
+static int test_array [1 - 2 * !(((long int) (sizeof (ac__type_sizeof_))) <= $ac_mid)];
+test_array [0] = 0
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_hi=$ac_mid
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_lo=`expr '(' $ac_mid ')' + 1`
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+done
+case $ac_lo in
+?*) ac_cv_sizeof_int64_t=$ac_lo;;
+'') if test "$ac_cv_type_int64_t" = yes; then
+     { { echo "$as_me:$LINENO: error: cannot compute sizeof (int64_t)
+See \`config.log' for more details." >&5
+echo "$as_me: error: cannot compute sizeof (int64_t)
+See \`config.log' for more details." >&2;}
+   { (exit 77); exit 77; }; }
+   else
+     ac_cv_sizeof_int64_t=0
+   fi ;;
+esac
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+   typedef int64_t ac__type_sizeof_;
+static long int longval () { return (long int) (sizeof (ac__type_sizeof_)); }
+static unsigned long int ulongval () { return (long int) (sizeof (ac__type_sizeof_)); }
+#include <stdio.h>
+#include <stdlib.h>
+int
+main ()
+{
+
+  FILE *f = fopen ("conftest.val", "w");
+  if (! f)
+    return 1;
+  if (((long int) (sizeof (ac__type_sizeof_))) < 0)
+    {
+      long int i = longval ();
+      if (i != ((long int) (sizeof (ac__type_sizeof_))))
+       return 1;
+      fprintf (f, "%ld\n", i);
+    }
+  else
+    {
+      unsigned long int i = ulongval ();
+      if (i != ((long int) (sizeof (ac__type_sizeof_))))
+       return 1;
+      fprintf (f, "%lu\n", i);
+    }
+  return ferror (f) || fclose (f) != 0;
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
+  { (case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_try") 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_sizeof_int64_t=`cat conftest.val`
+else
+  echo "$as_me: program exited with status $ac_status" >&5
+echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+( exit $ac_status )
+if test "$ac_cv_type_int64_t" = yes; then
+     { { echo "$as_me:$LINENO: error: cannot compute sizeof (int64_t)
+See \`config.log' for more details." >&5
+echo "$as_me: error: cannot compute sizeof (int64_t)
+See \`config.log' for more details." >&2;}
+   { (exit 77); exit 77; }; }
+   else
+     ac_cv_sizeof_int64_t=0
+   fi
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f conftest.val
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_sizeof_int64_t" >&5
+echo "${ECHO_T}$ac_cv_sizeof_int64_t" >&6; }
+
+
+
+cat >>confdefs.h <<_ACEOF
+#define SIZEOF_INT64_T $ac_cv_sizeof_int64_t
+_ACEOF
+
+
+{ echo "$as_me:$LINENO: checking for long long" >&5
+echo $ECHO_N "checking for long long... $ECHO_C" >&6; }
+if test "${ac_cv_type_long_long+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+typedef long long ac__type_new_;
+int
+main ()
+{
+if ((ac__type_new_ *) 0)
+  return 0;
+if (sizeof (ac__type_new_))
+  return 0;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_cv_type_long_long=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_type_long_long=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_type_long_long" >&5
+echo "${ECHO_T}$ac_cv_type_long_long" >&6; }
+
+# The cast to long int works around a bug in the HP C Compiler
+# version HP92453-01 B.11.11.23709.GP, which incorrectly rejects
+# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'.
+# This bug is HP SR number 8606223364.
+{ echo "$as_me:$LINENO: checking size of long long" >&5
+echo $ECHO_N "checking size of long long... $ECHO_C" >&6; }
+if test "${ac_cv_sizeof_long_long+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if test "$cross_compiling" = yes; then
+  # Depending upon the size, compute the lo and hi bounds.
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+   typedef long long ac__type_sizeof_;
+int
+main ()
+{
+static int test_array [1 - 2 * !(((long int) (sizeof (ac__type_sizeof_))) >= 0)];
+test_array [0] = 0
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_lo=0 ac_mid=0
+  while :; do
+    cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+   typedef long long ac__type_sizeof_;
+int
+main ()
+{
+static int test_array [1 - 2 * !(((long int) (sizeof (ac__type_sizeof_))) <= $ac_mid)];
+test_array [0] = 0
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_hi=$ac_mid; break
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_lo=`expr $ac_mid + 1`
+                       if test $ac_lo -le $ac_mid; then
+                         ac_lo= ac_hi=
+                         break
+                       fi
+                       ac_mid=`expr 2 '*' $ac_mid + 1`
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+  done
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+   typedef long long ac__type_sizeof_;
+int
+main ()
+{
+static int test_array [1 - 2 * !(((long int) (sizeof (ac__type_sizeof_))) < 0)];
+test_array [0] = 0
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_hi=-1 ac_mid=-1
+  while :; do
+    cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+   typedef long long ac__type_sizeof_;
+int
+main ()
+{
+static int test_array [1 - 2 * !(((long int) (sizeof (ac__type_sizeof_))) >= $ac_mid)];
+test_array [0] = 0
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_lo=$ac_mid; break
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_hi=`expr '(' $ac_mid ')' - 1`
+                       if test $ac_mid -le $ac_hi; then
+                         ac_lo= ac_hi=
+                         break
+                       fi
+                       ac_mid=`expr 2 '*' $ac_mid`
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+  done
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_lo= ac_hi=
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+# Binary search between lo and hi bounds.
+while test "x$ac_lo" != "x$ac_hi"; do
+  ac_mid=`expr '(' $ac_hi - $ac_lo ')' / 2 + $ac_lo`
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+   typedef long long ac__type_sizeof_;
+int
+main ()
+{
+static int test_array [1 - 2 * !(((long int) (sizeof (ac__type_sizeof_))) <= $ac_mid)];
+test_array [0] = 0
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_hi=$ac_mid
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_lo=`expr '(' $ac_mid ')' + 1`
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+done
+case $ac_lo in
+?*) ac_cv_sizeof_long_long=$ac_lo;;
+'') if test "$ac_cv_type_long_long" = yes; then
+     { { echo "$as_me:$LINENO: error: cannot compute sizeof (long long)
+See \`config.log' for more details." >&5
+echo "$as_me: error: cannot compute sizeof (long long)
+See \`config.log' for more details." >&2;}
+   { (exit 77); exit 77; }; }
+   else
+     ac_cv_sizeof_long_long=0
+   fi ;;
+esac
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+   typedef long long ac__type_sizeof_;
+static long int longval () { return (long int) (sizeof (ac__type_sizeof_)); }
+static unsigned long int ulongval () { return (long int) (sizeof (ac__type_sizeof_)); }
+#include <stdio.h>
+#include <stdlib.h>
+int
+main ()
+{
+
+  FILE *f = fopen ("conftest.val", "w");
+  if (! f)
+    return 1;
+  if (((long int) (sizeof (ac__type_sizeof_))) < 0)
+    {
+      long int i = longval ();
+      if (i != ((long int) (sizeof (ac__type_sizeof_))))
+       return 1;
+      fprintf (f, "%ld\n", i);
+    }
+  else
+    {
+      unsigned long int i = ulongval ();
+      if (i != ((long int) (sizeof (ac__type_sizeof_))))
+       return 1;
+      fprintf (f, "%lu\n", i);
+    }
+  return ferror (f) || fclose (f) != 0;
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
+  { (case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_try") 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_sizeof_long_long=`cat conftest.val`
+else
+  echo "$as_me: program exited with status $ac_status" >&5
+echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+( exit $ac_status )
+if test "$ac_cv_type_long_long" = yes; then
+     { { echo "$as_me:$LINENO: error: cannot compute sizeof (long long)
+See \`config.log' for more details." >&5
+echo "$as_me: error: cannot compute sizeof (long long)
+See \`config.log' for more details." >&2;}
+   { (exit 77); exit 77; }; }
+   else
+     ac_cv_sizeof_long_long=0
+   fi
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f conftest.val
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_sizeof_long_long" >&5
+echo "${ECHO_T}$ac_cv_sizeof_long_long" >&6; }
+
+
+
+cat >>confdefs.h <<_ACEOF
+#define SIZEOF_LONG_LONG $ac_cv_sizeof_long_long
+_ACEOF
+
+
+if test "$ac_cv_sizeof_int" = 2 ; then
+  { echo "$as_me:$LINENO: checking for int16_t" >&5
+echo $ECHO_N "checking for int16_t... $ECHO_C" >&6; }
+if test "${ac_cv_type_int16_t+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+typedef int16_t ac__type_new_;
+int
+main ()
+{
+if ((ac__type_new_ *) 0)
+  return 0;
+if (sizeof (ac__type_new_))
+  return 0;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_cv_type_int16_t=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_type_int16_t=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_type_int16_t" >&5
+echo "${ECHO_T}$ac_cv_type_int16_t" >&6; }
+if test $ac_cv_type_int16_t = yes; then
+  :
+else
+
+cat >>confdefs.h <<_ACEOF
+#define int16_t int
+_ACEOF
+
+fi
+
+  { echo "$as_me:$LINENO: checking for uint16_t" >&5
+echo $ECHO_N "checking for uint16_t... $ECHO_C" >&6; }
+if test "${ac_cv_type_uint16_t+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+typedef uint16_t ac__type_new_;
+int
+main ()
+{
+if ((ac__type_new_ *) 0)
+  return 0;
+if (sizeof (ac__type_new_))
+  return 0;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_cv_type_uint16_t=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_type_uint16_t=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_type_uint16_t" >&5
+echo "${ECHO_T}$ac_cv_type_uint16_t" >&6; }
+if test $ac_cv_type_uint16_t = yes; then
+  :
+else
+
+cat >>confdefs.h <<_ACEOF
+#define uint16_t unsigned int
+_ACEOF
+
+fi
+
+elif test "$ac_cv_sizeof_short" = 2 ; then
+  { echo "$as_me:$LINENO: checking for int16_t" >&5
+echo $ECHO_N "checking for int16_t... $ECHO_C" >&6; }
+if test "${ac_cv_type_int16_t+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+typedef int16_t ac__type_new_;
+int
+main ()
+{
+if ((ac__type_new_ *) 0)
+  return 0;
+if (sizeof (ac__type_new_))
+  return 0;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_cv_type_int16_t=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_type_int16_t=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_type_int16_t" >&5
+echo "${ECHO_T}$ac_cv_type_int16_t" >&6; }
+if test $ac_cv_type_int16_t = yes; then
+  :
+else
+
+cat >>confdefs.h <<_ACEOF
+#define int16_t short
+_ACEOF
+
+fi
+
+  { echo "$as_me:$LINENO: checking for uint16_t" >&5
+echo $ECHO_N "checking for uint16_t... $ECHO_C" >&6; }
+if test "${ac_cv_type_uint16_t+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+typedef uint16_t ac__type_new_;
+int
+main ()
+{
+if ((ac__type_new_ *) 0)
+  return 0;
+if (sizeof (ac__type_new_))
+  return 0;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_cv_type_uint16_t=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_type_uint16_t=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_type_uint16_t" >&5
+echo "${ECHO_T}$ac_cv_type_uint16_t" >&6; }
+if test $ac_cv_type_uint16_t = yes; then
+  :
+else
+
+cat >>confdefs.h <<_ACEOF
+#define uint16_t unsigned short
+_ACEOF
+
+fi
+
+else
+  { { echo "$as_me:$LINENO: error: Cannot find a type with size of 16 bits" >&5
+echo "$as_me: error: Cannot find a type with size of 16 bits" >&2;}
+   { (exit 1); exit 1; }; }
+fi
+if test "$ac_cv_sizeof_int" = 4 ; then
+  { echo "$as_me:$LINENO: checking for int32_t" >&5
+echo $ECHO_N "checking for int32_t... $ECHO_C" >&6; }
+if test "${ac_cv_type_int32_t+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+typedef int32_t ac__type_new_;
+int
+main ()
+{
+if ((ac__type_new_ *) 0)
+  return 0;
+if (sizeof (ac__type_new_))
+  return 0;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_cv_type_int32_t=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_type_int32_t=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_type_int32_t" >&5
+echo "${ECHO_T}$ac_cv_type_int32_t" >&6; }
+if test $ac_cv_type_int32_t = yes; then
+  :
+else
+
+cat >>confdefs.h <<_ACEOF
+#define int32_t int
+_ACEOF
+
+fi
+
+  { echo "$as_me:$LINENO: checking for uint32_t" >&5
+echo $ECHO_N "checking for uint32_t... $ECHO_C" >&6; }
+if test "${ac_cv_type_uint32_t+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+typedef uint32_t ac__type_new_;
+int
+main ()
+{
+if ((ac__type_new_ *) 0)
+  return 0;
+if (sizeof (ac__type_new_))
+  return 0;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_cv_type_uint32_t=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_type_uint32_t=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_type_uint32_t" >&5
+echo "${ECHO_T}$ac_cv_type_uint32_t" >&6; }
+if test $ac_cv_type_uint32_t = yes; then
+  :
+else
+
+cat >>confdefs.h <<_ACEOF
+#define uint32_t unsigned int
+_ACEOF
+
+fi
+
+elif test "$ac_cv_sizeof_short" = 4 ; then
+  { echo "$as_me:$LINENO: checking for int32_t" >&5
+echo $ECHO_N "checking for int32_t... $ECHO_C" >&6; }
+if test "${ac_cv_type_int32_t+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+typedef int32_t ac__type_new_;
+int
+main ()
+{
+if ((ac__type_new_ *) 0)
+  return 0;
+if (sizeof (ac__type_new_))
+  return 0;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_cv_type_int32_t=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_type_int32_t=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_type_int32_t" >&5
+echo "${ECHO_T}$ac_cv_type_int32_t" >&6; }
+if test $ac_cv_type_int32_t = yes; then
+  :
+else
+
+cat >>confdefs.h <<_ACEOF
+#define int32_t short
+_ACEOF
+
+fi
+
+  { echo "$as_me:$LINENO: checking for uint32_t" >&5
+echo $ECHO_N "checking for uint32_t... $ECHO_C" >&6; }
+if test "${ac_cv_type_uint32_t+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+typedef uint32_t ac__type_new_;
+int
+main ()
+{
+if ((ac__type_new_ *) 0)
+  return 0;
+if (sizeof (ac__type_new_))
+  return 0;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_cv_type_uint32_t=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_type_uint32_t=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_type_uint32_t" >&5
+echo "${ECHO_T}$ac_cv_type_uint32_t" >&6; }
+if test $ac_cv_type_uint32_t = yes; then
+  :
+else
+
+cat >>confdefs.h <<_ACEOF
+#define uint32_t unsigned short
+_ACEOF
+
+fi
+
+elif test "$ac_cv_sizeof_long" = 4 ; then
+  { echo "$as_me:$LINENO: checking for int32_t" >&5
+echo $ECHO_N "checking for int32_t... $ECHO_C" >&6; }
+if test "${ac_cv_type_int32_t+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+typedef int32_t ac__type_new_;
+int
+main ()
+{
+if ((ac__type_new_ *) 0)
+  return 0;
+if (sizeof (ac__type_new_))
+  return 0;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_cv_type_int32_t=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_type_int32_t=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_type_int32_t" >&5
+echo "${ECHO_T}$ac_cv_type_int32_t" >&6; }
+if test $ac_cv_type_int32_t = yes; then
+  :
+else
+
+cat >>confdefs.h <<_ACEOF
+#define int32_t long
+_ACEOF
+
+fi
+
+  { echo "$as_me:$LINENO: checking for uint32_t" >&5
+echo $ECHO_N "checking for uint32_t... $ECHO_C" >&6; }
+if test "${ac_cv_type_uint32_t+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+typedef uint32_t ac__type_new_;
+int
+main ()
+{
+if ((ac__type_new_ *) 0)
+  return 0;
+if (sizeof (ac__type_new_))
+  return 0;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_cv_type_uint32_t=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_type_uint32_t=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_type_uint32_t" >&5
+echo "${ECHO_T}$ac_cv_type_uint32_t" >&6; }
+if test $ac_cv_type_uint32_t = yes; then
+  :
+else
+
+cat >>confdefs.h <<_ACEOF
+#define uint32_t unsigned long
+_ACEOF
+
+fi
+
+else
+  { { echo "$as_me:$LINENO: error: Cannot find a type with size of 32 bits" >&5
+echo "$as_me: error: Cannot find a type with size of 32 bits" >&2;}
+   { (exit 1); exit 1; }; }
+fi
+if test "$ac_cv_sizeof_int64_t" = 8 ; then
+  { echo "$as_me:$LINENO: checking for int64_t" >&5
+echo $ECHO_N "checking for int64_t... $ECHO_C" >&6; }
+if test "${ac_cv_type_int64_t+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+typedef int64_t ac__type_new_;
+int
+main ()
+{
+if ((ac__type_new_ *) 0)
+  return 0;
+if (sizeof (ac__type_new_))
+  return 0;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_cv_type_int64_t=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_type_int64_t=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_type_int64_t" >&5
+echo "${ECHO_T}$ac_cv_type_int64_t" >&6; }
+
+  { echo "$as_me:$LINENO: checking for uint64_t" >&5
+echo $ECHO_N "checking for uint64_t... $ECHO_C" >&6; }
+if test "${ac_cv_type_uint64_t+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+typedef uint64_t ac__type_new_;
+int
+main ()
+{
+if ((ac__type_new_ *) 0)
+  return 0;
+if (sizeof (ac__type_new_))
+  return 0;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_cv_type_uint64_t=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_type_uint64_t=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_type_uint64_t" >&5
+echo "${ECHO_T}$ac_cv_type_uint64_t" >&6; }
+
+elif test "$ac_cv_sizeof_long_long" = 8 ; then
+  { echo "$as_me:$LINENO: checking for int64_t" >&5
+echo $ECHO_N "checking for int64_t... $ECHO_C" >&6; }
+if test "${ac_cv_type_int64_t+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+typedef int64_t ac__type_new_;
+int
+main ()
+{
+if ((ac__type_new_ *) 0)
+  return 0;
+if (sizeof (ac__type_new_))
+  return 0;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_cv_type_int64_t=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_type_int64_t=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_type_int64_t" >&5
+echo "${ECHO_T}$ac_cv_type_int64_t" >&6; }
+if test $ac_cv_type_int64_t = yes; then
+  :
+else
+
+cat >>confdefs.h <<_ACEOF
+#define int64_t long long
+_ACEOF
+
+fi
+
+  { echo "$as_me:$LINENO: checking for uint64_t" >&5
+echo $ECHO_N "checking for uint64_t... $ECHO_C" >&6; }
+if test "${ac_cv_type_uint64_t+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+typedef uint64_t ac__type_new_;
+int
+main ()
+{
+if ((ac__type_new_ *) 0)
+  return 0;
+if (sizeof (ac__type_new_))
+  return 0;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_cv_type_uint64_t=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_type_uint64_t=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_type_uint64_t" >&5
+echo "${ECHO_T}$ac_cv_type_uint64_t" >&6; }
+if test $ac_cv_type_uint64_t = yes; then
+  :
+else
+
+cat >>confdefs.h <<_ACEOF
+#define uint64_t unsigned long long
+_ACEOF
+
+fi
+
+else
+  { { echo "$as_me:$LINENO: error: Cannot find a type with size of 64 bits" >&5
+echo "$as_me: error: Cannot find a type with size of 64 bits" >&2;}
+   { (exit 1); exit 1; }; }
+fi
+{ echo "$as_me:$LINENO: checking for struct sockaddr_in6" >&5
+echo $ECHO_N "checking for struct sockaddr_in6... $ECHO_C" >&6; }
+if test "${ac_cv_type_struct_sockaddr_in6+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <sys/types.h>
+#include <netinet/in.h>
+
+typedef struct sockaddr_in6 ac__type_new_;
+int
+main ()
+{
+if ((ac__type_new_ *) 0)
+  return 0;
+if (sizeof (ac__type_new_))
+  return 0;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_cv_type_struct_sockaddr_in6=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_type_struct_sockaddr_in6=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_type_struct_sockaddr_in6" >&5
+echo "${ECHO_T}$ac_cv_type_struct_sockaddr_in6" >&6; }
+if test $ac_cv_type_struct_sockaddr_in6 = yes; then
+  unet_have_sockaddr_in6="yes"
+else
+  unet_have_sockaddr_in6="no"
+fi
+
+
+{ echo "$as_me:$LINENO: checking for socklen_t" >&5
+echo $ECHO_N "checking for socklen_t... $ECHO_C" >&6; }
+if test "${ac_cv_type_socklen_t+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <sys/types.h>
+#include<sys/socket.h>
+
+typedef socklen_t ac__type_new_;
+int
+main ()
+{
+if ((ac__type_new_ *) 0)
+  return 0;
+if (sizeof (ac__type_new_))
+  return 0;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_cv_type_socklen_t=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_type_socklen_t=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_type_socklen_t" >&5
+echo "${ECHO_T}$ac_cv_type_socklen_t" >&6; }
+if test $ac_cv_type_socklen_t = yes; then
+  :
+else
+
+  { echo "$as_me:$LINENO: checking for socklen_t equivalent" >&5
+echo $ECHO_N "checking for socklen_t equivalent... $ECHO_C" >&6; }
+  if test "${curl_cv_socklen_t_equiv+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+
+    curl_cv_socklen_t_equiv=
+    for arg2 in "struct sockaddr" void ; do
+      for t in int size_t unsigned long "unsigned long" ; do
+        cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <sys/types.h>
+#include <sys/socket.h>
+int getpeername (int $arg2 *, $t *);
+int
+main ()
+{
+$t len;
+  getpeername(0, 0, &len);
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  curl_cv_socklen_t_equiv="$t"
+  break
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+      done
+    done
+
+fi
+
+  { echo "$as_me:$LINENO: result: $curl_cv_socklen_t_equiv" >&5
+echo "${ECHO_T}$curl_cv_socklen_t_equiv" >&6; }
+
+cat >>confdefs.h <<_ACEOF
+#define socklen_t $curl_cv_socklen_t_equiv
+_ACEOF
+
+fi
+
+
+
+
+
+
+for ac_func in kqueue setrlimit getrusage times
+do
+as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
+{ echo "$as_me:$LINENO: checking for $ac_func" >&5
+echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6; }
+if { as_var=$as_ac_var; eval "test \"\${$as_var+set}\" = set"; }; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+/* Define $ac_func to an innocuous variant, in case <limits.h> declares $ac_func.
+   For example, HP-UX 11i <limits.h> declares gettimeofday.  */
+#define $ac_func innocuous_$ac_func
+
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char $ac_func (); below.
+    Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+    <limits.h> exists even on freestanding compilers.  */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef $ac_func
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char $ac_func ();
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined __stub_$ac_func || defined __stub___$ac_func
+choke me
+#endif
+
+int
+main ()
+{
+return $ac_func ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext &&
+       $as_test_x conftest$ac_exeext; then
+  eval "$as_ac_var=yes"
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       eval "$as_ac_var=no"
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+fi
+ac_res=`eval echo '${'$as_ac_var'}'`
+              { echo "$as_me:$LINENO: result: $ac_res" >&5
+echo "${ECHO_T}$ac_res" >&6; }
+if test `eval echo '${'$as_ac_var'}'` = yes; then
+  cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+done
+
+
+{ echo "$as_me:$LINENO: checking for donuts" >&5
+echo $ECHO_N "checking for donuts... $ECHO_C" >&6; }
+{ echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6; }
+
+for ac_prog in gawk mawk nawk awk
+do
+  # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
+if test "${ac_cv_prog_AWK+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if test -n "$AWK"; then
+  ac_cv_prog_AWK="$AWK" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_AWK="$ac_prog"
+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+IFS=$as_save_IFS
+
+fi
+fi
+AWK=$ac_cv_prog_AWK
+if test -n "$AWK"; then
+  { echo "$as_me:$LINENO: result: $AWK" >&5
+echo "${ECHO_T}$AWK" >&6; }
+else
+  { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+fi
+
+
+  test -n "$AWK" && break
+done
+
+{ echo "$as_me:$LINENO: checking whether ${MAKE-make} sets \$(MAKE)" >&5
+echo $ECHO_N "checking whether ${MAKE-make} sets \$(MAKE)... $ECHO_C" >&6; }
+set x ${MAKE-make}; ac_make=`echo "$2" | sed 's/+/p/g; s/[^a-zA-Z0-9_]/_/g'`
+if { as_var=ac_cv_prog_make_${ac_make}_set; eval "test \"\${$as_var+set}\" = set"; }; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.make <<\_ACEOF
+SHELL = /bin/sh
+all:
+       @echo '@@@%%%=$(MAKE)=@@@%%%'
+_ACEOF
+# GNU make sometimes prints "make[1]: Entering...", which would confuse us.
+case `${MAKE-make} -f conftest.make 2>/dev/null` in
+  *@@@%%%=?*=@@@%%%*)
+    eval ac_cv_prog_make_${ac_make}_set=yes;;
+  *)
+    eval ac_cv_prog_make_${ac_make}_set=no;;
+esac
+rm -f conftest.make
+fi
+if eval test \$ac_cv_prog_make_${ac_make}_set = yes; then
+  { echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6; }
+  SET_MAKE=
+else
+  { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+  SET_MAKE="MAKE=${MAKE-make}"
+fi
+
+# Find a good install program.  We prefer a C program (faster),
+# so one script is as good as another.  But avoid the broken or
+# incompatible versions:
+# SysV /etc/install, /usr/sbin/install
+# SunOS /usr/etc/install
+# IRIX /sbin/install
+# AIX /bin/install
+# AmigaOS /C/install, which installs bootblocks on floppy discs
+# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag
+# AFS /usr/afsws/bin/install, which mishandles nonexistent args
+# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff"
+# OS/2's system install, which has a completely different semantic
+# ./install, which can be erroneously created by make from ./install.sh.
+{ echo "$as_me:$LINENO: checking for a BSD-compatible install" >&5
+echo $ECHO_N "checking for a BSD-compatible install... $ECHO_C" >&6; }
+if test -z "$INSTALL"; then
+if test "${ac_cv_path_install+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  # Account for people who put trailing slashes in PATH elements.
+case $as_dir/ in
+  ./ | .// | /cC/* | \
+  /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \
+  ?:\\/os2\\/install\\/* | ?:\\/OS2\\/INSTALL\\/* | \
+  /usr/ucb/* ) ;;
+  *)
+    # OSF1 and SCO ODT 3.0 have their own names for install.
+    # Don't use installbsd from OSF since it installs stuff as root
+    # by default.
+    for ac_prog in ginstall scoinst install; do
+      for ac_exec_ext in '' $ac_executable_extensions; do
+       if { test -f "$as_dir/$ac_prog$ac_exec_ext" && $as_test_x "$as_dir/$ac_prog$ac_exec_ext"; }; then
+         if test $ac_prog = install &&
+           grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then
+           # AIX install.  It has an incompatible calling convention.
+           :
+         elif test $ac_prog = install &&
+           grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then
+           # program-specific install script used by HP pwplus--don't use.
+           :
+         else
+           ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c"
+           break 3
+         fi
+       fi
+      done
+    done
+    ;;
+esac
+done
+IFS=$as_save_IFS
+
+
+fi
+  if test "${ac_cv_path_install+set}" = set; then
+    INSTALL=$ac_cv_path_install
+  else
+    # As a last resort, use the slow shell script.  Don't cache a
+    # value for INSTALL within a source directory, because that will
+    # break other packages using the cache if that directory is
+    # removed, or if the value is a relative name.
+    INSTALL=$ac_install_sh
+  fi
+fi
+{ echo "$as_me:$LINENO: result: $INSTALL" >&5
+echo "${ECHO_T}$INSTALL" >&6; }
+
+# Use test -z because SunOS4 sh mishandles braces in ${var-val}.
+# It thinks the first close brace ends the variable substitution.
+test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}'
+
+test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}'
+
+test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644'
+
+{ echo "$as_me:$LINENO: checking whether ln -s works" >&5
+echo $ECHO_N "checking whether ln -s works... $ECHO_C" >&6; }
+LN_S=$as_ln_s
+if test "$LN_S" = "ln -s"; then
+  { echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6; }
+else
+  { echo "$as_me:$LINENO: result: no, using $LN_S" >&5
+echo "${ECHO_T}no, using $LN_S" >&6; }
+fi
+
+for ac_prog in rm
+do
+  # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
+if test "${ac_cv_path_RMPROG+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  case $RMPROG in
+  [\\/]* | ?:[\\/]*)
+  ac_cv_path_RMPROG="$RMPROG" # Let the user override the test with a path.
+  ;;
+  *)
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_path_RMPROG="$as_dir/$ac_word$ac_exec_ext"
+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+IFS=$as_save_IFS
+
+  ;;
+esac
+fi
+RMPROG=$ac_cv_path_RMPROG
+if test -n "$RMPROG"; then
+  { echo "$as_me:$LINENO: result: $RMPROG" >&5
+echo "${ECHO_T}$RMPROG" >&6; }
+else
+  { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+fi
+
+
+  test -n "$RMPROG" && break
+done
+test -n "$RMPROG" || RMPROG="/bin/rm"
+
+for ac_prog in sh
+do
+  # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
+if test "${ac_cv_path_SHPROG+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  case $SHPROG in
+  [\\/]* | ?:[\\/]*)
+  ac_cv_path_SHPROG="$SHPROG" # Let the user override the test with a path.
+  ;;
+  *)
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_path_SHPROG="$as_dir/$ac_word$ac_exec_ext"
+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+IFS=$as_save_IFS
+
+  ;;
+esac
+fi
+SHPROG=$ac_cv_path_SHPROG
+if test -n "$SHPROG"; then
+  { echo "$as_me:$LINENO: result: $SHPROG" >&5
+echo "${ECHO_T}$SHPROG" >&6; }
+else
+  { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+fi
+
+
+  test -n "$SHPROG" && break
+done
+test -n "$SHPROG" || SHPROG="/bin/sh"
+
+
+for ac_prog in flex lex
+do
+  # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
+if test "${ac_cv_prog_LEX+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if test -n "$LEX"; then
+  ac_cv_prog_LEX="$LEX" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_LEX="$ac_prog"
+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+IFS=$as_save_IFS
+
+fi
+fi
+LEX=$ac_cv_prog_LEX
+if test -n "$LEX"; then
+  { echo "$as_me:$LINENO: result: $LEX" >&5
+echo "${ECHO_T}$LEX" >&6; }
+else
+  { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+fi
+
+
+  test -n "$LEX" && break
+done
+test -n "$LEX" || LEX=":"
+
+if test "x$LEX" != "x:"; then
+  cat >conftest.l <<_ACEOF
+%%
+a { ECHO; }
+b { REJECT; }
+c { yymore (); }
+d { yyless (1); }
+e { yyless (input () != 0); }
+f { unput (yytext[0]); }
+. { BEGIN INITIAL; }
+%%
+#ifdef YYTEXT_POINTER
+extern char *yytext;
+#endif
+int
+main (void)
+{
+  return ! yylex () + ! yywrap ();
+}
+_ACEOF
+{ (ac_try="$LEX conftest.l"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$LEX conftest.l") 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }
+{ echo "$as_me:$LINENO: checking lex output file root" >&5
+echo $ECHO_N "checking lex output file root... $ECHO_C" >&6; }
+if test "${ac_cv_prog_lex_root+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+
+if test -f lex.yy.c; then
+  ac_cv_prog_lex_root=lex.yy
+elif test -f lexyy.c; then
+  ac_cv_prog_lex_root=lexyy
+else
+  { { echo "$as_me:$LINENO: error: cannot find output from $LEX; giving up" >&5
+echo "$as_me: error: cannot find output from $LEX; giving up" >&2;}
+   { (exit 1); exit 1; }; }
+fi
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_prog_lex_root" >&5
+echo "${ECHO_T}$ac_cv_prog_lex_root" >&6; }
+LEX_OUTPUT_ROOT=$ac_cv_prog_lex_root
+
+if test -z "${LEXLIB+set}"; then
+  { echo "$as_me:$LINENO: checking lex library" >&5
+echo $ECHO_N "checking lex library... $ECHO_C" >&6; }
+if test "${ac_cv_lib_lex+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+
+    ac_save_LIBS=$LIBS
+    ac_cv_lib_lex='none needed'
+    for ac_lib in '' -lfl -ll; do
+      LIBS="$ac_lib $ac_save_LIBS"
+      cat >conftest.$ac_ext <<_ACEOF
+`cat $LEX_OUTPUT_ROOT.c`
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext &&
+       $as_test_x conftest$ac_exeext; then
+  ac_cv_lib_lex=$ac_lib
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+      test "$ac_cv_lib_lex" != 'none needed' && break
+    done
+    LIBS=$ac_save_LIBS
+
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_lib_lex" >&5
+echo "${ECHO_T}$ac_cv_lib_lex" >&6; }
+  test "$ac_cv_lib_lex" != 'none needed' && LEXLIB=$ac_cv_lib_lex
+fi
+
+
+{ echo "$as_me:$LINENO: checking whether yytext is a pointer" >&5
+echo $ECHO_N "checking whether yytext is a pointer... $ECHO_C" >&6; }
+if test "${ac_cv_prog_lex_yytext_pointer+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  # POSIX says lex can declare yytext either as a pointer or an array; the
+# default is implementation-dependent.  Figure out which it is, since
+# not all implementations provide the %pointer and %array declarations.
+ac_cv_prog_lex_yytext_pointer=no
+ac_save_LIBS=$LIBS
+LIBS="$LEXLIB $ac_save_LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+#define YYTEXT_POINTER 1
+`cat $LEX_OUTPUT_ROOT.c`
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext &&
+       $as_test_x conftest$ac_exeext; then
+  ac_cv_prog_lex_yytext_pointer=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_save_LIBS
+
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_prog_lex_yytext_pointer" >&5
+echo "${ECHO_T}$ac_cv_prog_lex_yytext_pointer" >&6; }
+if test $ac_cv_prog_lex_yytext_pointer = yes; then
+
+cat >>confdefs.h <<\_ACEOF
+#define YYTEXT_POINTER 1
+_ACEOF
+
+fi
+rm -f conftest.l $LEX_OUTPUT_ROOT.c
+
+fi
+if test "$LEX" = ":" ; then
+  { { echo "$as_me:$LINENO: error: Cannot find flex." >&5
+echo "$as_me: error: Cannot find flex." >&2;}
+   { (exit 1); exit 1; }; }
+elif echo "" | $LEX -V -v --version > /dev/null 2>&1 ; then
+  :
+else
+  { { echo "$as_me:$LINENO: error: Cannot use $LEX as flex." >&5
+echo "$as_me: error: Cannot use $LEX as flex." >&2;}
+   { (exit 1); exit 1; }; }
+fi
+
+for ac_prog in 'bison -y' byacc
+do
+  # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
+if test "${ac_cv_prog_YACC+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if test -n "$YACC"; then
+  ac_cv_prog_YACC="$YACC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_YACC="$ac_prog"
+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+IFS=$as_save_IFS
+
+fi
+fi
+YACC=$ac_cv_prog_YACC
+if test -n "$YACC"; then
+  { echo "$as_me:$LINENO: result: $YACC" >&5
+echo "${ECHO_T}$YACC" >&6; }
+else
+  { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+fi
+
+
+  test -n "$YACC" && break
+done
+test -n "$YACC" || YACC="yacc"
+
+if test "$YACC" = ":" ; then
+  { { echo "$as_me:$LINENO: error: Cannot find yacc." >&5
+echo "$as_me: error: Cannot find yacc." >&2;}
+   { (exit 1); exit 1; }; }
+elif echo "" | $YACC -V -v --version > /dev/null 2>&1 ; then
+  :
+else
+  { echo "$as_me:$LINENO: WARNING: $YACC may not work as yacc." >&5
+echo "$as_me: WARNING: $YACC may not work as yacc." >&2;}
+fi
+
+{ echo "$as_me:$LINENO: checking for posix non-blocking" >&5
+echo $ECHO_N "checking for posix non-blocking... $ECHO_C" >&6; }
+if test "${unet_cv_sys_nonblocking_posix+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if test "$cross_compiling" = yes; then
+  { { echo "$as_me:$LINENO: error: cannot run test program while cross compiling
+See \`config.log' for more details." >&5
+echo "$as_me: error: cannot run test program while cross compiling
+See \`config.log' for more details." >&2;}
+   { (exit 1); exit 1; }; }
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <sys/file.h>
+#include <signal.h>
+$ac_cv_type_signal alarmed() { exit(1); }
+int main(void)
+{
+  char b[12];
+  struct sockaddr x;
+  size_t l = sizeof(x);
+  int f = socket(AF_INET, SOCK_DGRAM, 0);
+  if (f >= 0 && !(fcntl(f, F_SETFL, O_NONBLOCK)))
+  {
+    signal(SIGALRM, alarmed);
+    alarm(2);
+    recvfrom(f, b, 12, 0, &x, &l);
+    alarm(0);
+    exit(0);
+  }
+  exit(1);
+}
+_ACEOF
+rm -f conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
+  { (case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_try") 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  unet_cv_sys_nonblocking_posix=yes
+else
+  echo "$as_me: program exited with status $ac_status" >&5
+echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+( exit $ac_status )
+unet_cv_sys_nonblocking_posix=no
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+fi
+
+
+fi
+{ echo "$as_me:$LINENO: result: $unet_cv_sys_nonblocking_posix" >&5
+echo "${ECHO_T}$unet_cv_sys_nonblocking_posix" >&6; }
+if test $unet_cv_sys_nonblocking_posix = yes; then
+
+cat >>confdefs.h <<\_ACEOF
+#define NBLOCK_POSIX
+_ACEOF
+
+else
+{ echo "$as_me:$LINENO: checking for bsd non-blocking" >&5
+echo $ECHO_N "checking for bsd non-blocking... $ECHO_C" >&6; }
+if test "${unet_cv_sys_nonblocking_bsd+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if test "$cross_compiling" = yes; then
+  { { echo "$as_me:$LINENO: error: cannot run test program while cross compiling
+See \`config.log' for more details." >&5
+echo "$as_me: error: cannot run test program while cross compiling
+See \`config.log' for more details." >&2;}
+   { (exit 1); exit 1; }; }
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <sys/file.h>
+#include <signal.h>
+$ac_cv_type_signal alarmed() { exit(1); }
+int main(void)
+{
+  char b[12];
+  struct sockaddr x;
+  size_t l = sizeof(x);
+  int f = socket(AF_INET, SOCK_DGRAM, 0);
+  if (f >= 0 && !(fcntl(f, F_SETFL, O_NDELAY)))
+  {
+    signal(SIGALRM, alarmed);
+    alarm(2);
+    recvfrom(f, b, 12, 0, &x, &l);
+    alarm(0);
+    exit(0);
+  }
+  exit(1);
+}
+_ACEOF
+rm -f conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
+  { (case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_try") 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  unet_cv_sys_nonblocking_bsd=yes
+else
+  echo "$as_me: program exited with status $ac_status" >&5
+echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+( exit $ac_status )
+unet_cv_sys_nonblocking_bsd=no
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+fi
+
+
+fi
+{ echo "$as_me:$LINENO: result: $unet_cv_sys_nonblocking_bsd" >&5
+echo "${ECHO_T}$unet_cv_sys_nonblocking_bsd" >&6; }
+if test $unet_cv_sys_nonblocking_bsd = yes; then
+
+cat >>confdefs.h <<\_ACEOF
+#define NBLOCK_BSD
+_ACEOF
+
+else
+
+cat >>confdefs.h <<\_ACEOF
+#define NBLOCK_SYSV
+_ACEOF
+
+fi
+fi
+{ echo "$as_me:$LINENO: checking for posix signals" >&5
+echo $ECHO_N "checking for posix signals... $ECHO_C" >&6; }
+if test "${unet_cv_sys_signal_posix+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <signal.h>
+int
+main ()
+{
+sigaction(SIGTERM, (struct sigaction *)0L, (struct sigaction *)0L)
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  unet_cv_sys_signal_posix=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       unet_cv_sys_signal_posix=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ echo "$as_me:$LINENO: result: $unet_cv_sys_signal_posix" >&5
+echo "${ECHO_T}$unet_cv_sys_signal_posix" >&6; }
+if test $unet_cv_sys_signal_posix = yes; then
+
+cat >>confdefs.h <<\_ACEOF
+#define POSIX_SIGNALS
+_ACEOF
+
+else
+{ echo "$as_me:$LINENO: checking for bsd reliable signals" >&5
+echo $ECHO_N "checking for bsd reliable signals... $ECHO_C" >&6; }
+if test "${unet_cv_sys_signal_bsd+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if test "$cross_compiling" = yes; then
+  { { echo "$as_me:$LINENO: error: cannot run test program while cross compiling
+See \`config.log' for more details." >&5
+echo "$as_me: error: cannot run test program while cross compiling
+See \`config.log' for more details." >&2;}
+   { (exit 1); exit 1; }; }
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <signal.h>
+int calls = 0;
+$ac_cv_type_signal handler()
+{
+  if (calls) return;
+  calls++;
+  kill(getpid(), SIGTERM);
+  sleep(1);
+}
+int main(void)
+{
+  signal(SIGTERM, handler);
+  kill(getpid(), SIGTERM);
+  exit (0);
+}
+_ACEOF
+rm -f conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
+  { (case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_try") 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  unet_cv_sys_signal_bsd=yes
+else
+  echo "$as_me: program exited with status $ac_status" >&5
+echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+( exit $ac_status )
+unet_cv_sys_signal_bsd=no
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+fi
+
+
+fi
+{ echo "$as_me:$LINENO: result: $unet_cv_sys_signal_bsd" >&5
+echo "${ECHO_T}$unet_cv_sys_signal_bsd" >&6; }
+if test $unet_cv_sys_signal_bsd = yes; then
+
+cat >>confdefs.h <<\_ACEOF
+#define BSD_RELIABLE_SIGNALS
+_ACEOF
+
+else
+
+cat >>confdefs.h <<\_ACEOF
+#define SYSV_UNRELIABLE_SIGNALS
+_ACEOF
+
+fi
+fi
+
+{ echo "$as_me:$LINENO: checking for OS-dependent information" >&5
+echo $ECHO_N "checking for OS-dependent information... $ECHO_C" >&6; }
+case "$host" in
+    *-linux*)
+       { echo "$as_me:$LINENO: result: Linux ($host) found." >&5
+echo "${ECHO_T}Linux ($host) found." >&6; }
+       unet_poll_syscall=yes
+       ;;
+
+    *-solaris*)
+       { echo "$as_me:$LINENO: result: Solaris ($host) found." >&5
+echo "${ECHO_T}Solaris ($host) found." >&6; }
+       if test x"$ac_cv_header_poll_h" = xyes; then
+           unet_poll_syscall=yes
+       else
+           unet_poll_syscall=no
+       fi
+
+cat >>confdefs.h <<\_ACEOF
+#define IRCU_SOLARIS 1
+_ACEOF
+
+       ;;
+
+    *-sunos*)
+       { echo "$as_me:$LINENO: result: Solaris ($host) found." >&5
+echo "${ECHO_T}Solaris ($host) found." >&6; }
+       unet_poll_syscall=no
+       ;;
+
+    *-openbsd*)
+       { echo "$as_me:$LINENO: result: OpenBSD ($host) found." >&5
+echo "${ECHO_T}OpenBSD ($host) found." >&6; }
+       if test x"$ac_cv_header_poll_h" = xyes; then
+           unet_poll_syscall=yes
+       else
+           unet_poll_syscall=no
+       fi
+       ;;
+
+    *-*bsd*)
+       { echo "$as_me:$LINENO: result: Generic BSD ($host) found." >&5
+echo "${ECHO_T}Generic BSD ($host) found." >&6; }
+       if test x"$ac_cv_header_poll_h" = xyes; then
+           unet_poll_syscall=yes
+       else
+           unet_poll_syscall=no
+       fi
+       ;;
+
+    *-darwin*)
+       { echo "$as_me:$LINENO: result: Darwin (Mac OS X) ($host) found." >&5
+echo "${ECHO_T}Darwin (Mac OS X) ($host) found." >&6; }
+       unet_poll_syscall=no
+
+cat >>confdefs.h <<\_ACEOF
+#define _DARWIN_C_SOURCE 1
+_ACEOF
+
+       ;;
+
+    *)
+       { echo "$as_me:$LINENO: result: Unknown system type $host found." >&5
+echo "${ECHO_T}Unknown system type $host found." >&6; }
+       { echo "$as_me:$LINENO: WARNING: Unknown OS type; using generic routines." >&5
+echo "$as_me: WARNING: Unknown OS type; using generic routines." >&2;}
+       unet_poll_syscall=no
+       ;;
+esac
+
+{ echo "$as_me:$LINENO: checking whether to enable use of poll()" >&5
+echo $ECHO_N "checking whether to enable use of poll()... $ECHO_C" >&6; }
+# Check whether --enable-poll was given.
+if test "${enable_poll+set}" = set; then
+  enableval=$enable_poll; unet_cv_enable_poll=$enable_poll
+else
+  if test "${unet_cv_enable_poll+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  unet_cv_enable_poll=$unet_poll_syscall
+fi
+
+fi
+
+
+# Force poll to be disabled if there is no poll.h
+if test x"$ac_cv_header_poll_h" != xyes; then
+    unet_cv_enable_poll=no
+fi
+
+{ echo "$as_me:$LINENO: result: $unet_cv_enable_poll" >&5
+echo "${ECHO_T}$unet_cv_enable_poll" >&6; }
+
+if test x"$unet_cv_enable_poll" = xyes; then
+
+cat >>confdefs.h <<\_ACEOF
+#define USE_POLL 1
+_ACEOF
+
+    ENGINE_C=engine_poll.c
+else
+    ENGINE_C=engine_select.c
+fi
+
+
+{ echo "$as_me:$LINENO: checking whether to enable debug mode" >&5
+echo $ECHO_N "checking whether to enable debug mode... $ECHO_C" >&6; }
+# Check whether --enable-debug was given.
+if test "${enable_debug+set}" = set; then
+  enableval=$enable_debug; unet_cv_enable_debug=$enable_debug
+else
+  if test "${unet_cv_enable_debug+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  unet_cv_enable_debug=no
+fi
+
+fi
+
+{ echo "$as_me:$LINENO: result: $unet_cv_enable_debug" >&5
+echo "${ECHO_T}$unet_cv_enable_debug" >&6; }
+
+if test x"$unet_cv_enable_debug" = xyes; then
+
+cat >>confdefs.h <<\_ACEOF
+#define DEBUGMODE 1
+_ACEOF
+
+    CFLAGS="$CFLAGS -O0 -g"
+fi
+
+{ echo "$as_me:$LINENO: checking whether to enable leak detection" >&5
+echo $ECHO_N "checking whether to enable leak detection... $ECHO_C" >&6; }
+
+# Check whether --with-leak-detect was given.
+if test "${with_leak_detect+set}" = set; then
+  withval=$with_leak_detect; unet_cv_with_leak_detect=$with_leak_detect
+else
+  if test "${unet_cv_with_leak_detect+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  unet_cv_with_leak_detect=no
+fi
+
+fi
+
+{ echo "$as_me:$LINENO: result: $unet_cv_enable_leak_detect" >&5
+echo "${ECHO_T}$unet_cv_enable_leak_detect" >&6; }
+
+if test x"$unet_cv_with_leak_detect" != xno; then
+    LIBS="-lgc $LIBS"
+    CFLAGS="-DMDEBUG $CFLAGS"
+    if test x"$unet_cv_with_leak_detect" != xyes; then
+       LIBS="-L$unet_cv_with_leak_detect $LIBS"
+    fi
+fi
+
+
+# Check whether --with-ipv6 was given.
+if test "${with_ipv6+set}" = set; then
+  withval=$with_ipv6; ac_cv_use_ipv6=$withval
+else
+  ac_cv_use_ipv6=$unet_have_sockaddr_in6
+fi
+
+{ echo "$as_me:$LINENO: checking whether to use IPv6" >&5
+echo $ECHO_N "checking whether to use IPv6... $ECHO_C" >&6; }
+if test "${ac_cv_use_ipv6+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_cv_use_ipv6=no
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_use_ipv6" >&5
+echo "${ECHO_T}$ac_cv_use_ipv6" >&6; }
+if test x"$ac_cv_use_ipv6" != "xno" ; then
+
+cat >>confdefs.h <<\_ACEOF
+#define IPV6 1
+_ACEOF
+
+fi
+
+{ echo "$as_me:$LINENO: checking whether to enable asserts" >&5
+echo $ECHO_N "checking whether to enable asserts... $ECHO_C" >&6; }
+# Check whether --enable-asserts was given.
+if test "${enable_asserts+set}" = set; then
+  enableval=$enable_asserts; unet_cv_enable_asserts=$enable_asserts
+else
+  if test "${unet_cv_enable_asserts+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  unet_cv_enable_asserts=yes
+fi
+
+fi
+
+{ echo "$as_me:$LINENO: result: $unet_cv_enable_asserts" >&5
+echo "${ECHO_T}$unet_cv_enable_asserts" >&6; }
+
+if test x"$unet_cv_enable_asserts" = xno; then
+
+cat >>confdefs.h <<\_ACEOF
+#define NDEBUG 1
+_ACEOF
+
+fi
+
+{ echo "$as_me:$LINENO: checking whether to enable profiling support (gprof)" >&5
+echo $ECHO_N "checking whether to enable profiling support (gprof)... $ECHO_C" >&6; }
+# Check whether --enable-profile was given.
+if test "${enable_profile+set}" = set; then
+  enableval=$enable_profile; unet_cv_enable_profile=$enable_profile
+else
+  if test "${unet_cv_enable_profile+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  unet_cv_enable_profile=no
+fi
+
+fi
+
+{ echo "$as_me:$LINENO: result: $unet_cv_enable_profile" >&5
+echo "${ECHO_T}$unet_cv_enable_profile" >&6; }
+
+if test x"$unet_cv_enable_profile" = xyes; then
+    CFLAGS="-pg $CFLAGS"
+    LDFLAGS="-pg $LDFLAGS"
+fi
+
+{ echo "$as_me:$LINENO: checking whether to enable pedantic compiler warnings" >&5
+echo $ECHO_N "checking whether to enable pedantic compiler warnings... $ECHO_C" >&6; }
+# Check whether --enable-pedantic was given.
+if test "${enable_pedantic+set}" = set; then
+  enableval=$enable_pedantic; unet_cv_enable_pedantic=$enable_pedantic
+else
+  if test "${unet_cv_enable_pedantic+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  unet_cv_enable_pedantic=no
+fi
+
+fi
+
+{ echo "$as_me:$LINENO: result: $unet_cv_enable_pedantic" >&5
+echo "${ECHO_T}$unet_cv_enable_pedantic" >&6; }
+
+if test x"$unet_cv_enable_pedantic" = xyes; then
+    CFLAGS="-pedantic $CFLAGS"
+fi
+
+{ echo "$as_me:$LINENO: checking whether to enable compiler warnings" >&5
+echo $ECHO_N "checking whether to enable compiler warnings... $ECHO_C" >&6; }
+# Check whether --enable-warnings was given.
+if test "${enable_warnings+set}" = set; then
+  enableval=$enable_warnings; unet_cv_enable_warnings=$enable_warnings
+else
+  if test "${unet_cv_enable_warnings+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  unet_cv_enable_warnings=no
+fi
+
+fi
+
+{ echo "$as_me:$LINENO: result: $unet_cv_enable_warnings" >&5
+echo "${ECHO_T}$unet_cv_enable_warnings" >&6; }
+
+if test x"$unet_cv_enable_warnings" = xyes; then
+    CFLAGS="-Wall $CFLAGS"
+fi
+
+{ echo "$as_me:$LINENO: checking whether to enable inlining for a few critical functions" >&5
+echo $ECHO_N "checking whether to enable inlining for a few critical functions... $ECHO_C" >&6; }
+# Check whether --enable-inlines was given.
+if test "${enable_inlines+set}" = set; then
+  enableval=$enable_inlines; unet_cv_enable_inlines=$enable_inlines
+else
+  if test "${unet_cv_enable_inlines+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  unet_cv_enable_inlines=yes
+fi
+
+fi
+
+{ echo "$as_me:$LINENO: result: $unet_cv_enable_inlines" >&5
+echo "${ECHO_T}$unet_cv_enable_inlines" >&6; }
+
+if test x"$unet_cv_enable_inlines" = xyes; then
+
+cat >>confdefs.h <<\_ACEOF
+#define FORCEINLINE 1
+_ACEOF
+
+fi
+
+{ echo "$as_me:$LINENO: checking whether to enable the /dev/poll event engine" >&5
+echo $ECHO_N "checking whether to enable the /dev/poll event engine... $ECHO_C" >&6; }
+# Check whether --enable-devpoll was given.
+if test "${enable_devpoll+set}" = set; then
+  enableval=$enable_devpoll; unet_cv_enable_devpoll=$enable_devpoll
+else
+  if test "${unet_cv_enable_devpoll+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  unet_cv_enable_devpoll=yes
+fi
+
+fi
+
+
+if test x"$ac_cv_header_sys_devpoll_h" = xno; then
+    unet_cv_enable_devpoll=no
+fi
+
+{ echo "$as_me:$LINENO: result: $unet_cv_enable_devpoll" >&5
+echo "${ECHO_T}$unet_cv_enable_devpoll" >&6; }
+
+if test x"$unet_cv_enable_devpoll" != xno; then
+
+cat >>confdefs.h <<\_ACEOF
+#define USE_DEVPOLL 1
+_ACEOF
+
+    ENGINE_C="engine_devpoll.c $ENGINE_C"
+fi
+
+{ echo "$as_me:$LINENO: checking whether to enable the kqueue event engine" >&5
+echo $ECHO_N "checking whether to enable the kqueue event engine... $ECHO_C" >&6; }
+# Check whether --enable-kqueue was given.
+if test "${enable_kqueue+set}" = set; then
+  enableval=$enable_kqueue; unet_cv_enable_kqueue=$enable_kqueue
+else
+  if test "${unet_cv_enable_kqueue+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  unet_cv_enable_kqueue=yes
+fi
+
+fi
+
+
+if test x"$ac_cv_header_sys_event_h" = xno -o x"$ac_cv_func_kqueue" = xno; then
+    unet_cv_enable_kqueue=no
+fi
+
+{ echo "$as_me:$LINENO: result: $unet_cv_enable_kqueue" >&5
+echo "${ECHO_T}$unet_cv_enable_kqueue" >&6; }
+
+if test x"$unet_cv_enable_kqueue" != xno; then
+
+cat >>confdefs.h <<\_ACEOF
+#define USE_KQUEUE 1
+_ACEOF
+
+    ENGINE_C="engine_kqueue.c $ENGINE_C"
+fi
+
+{ echo "$as_me:$LINENO: checking whether to enable the epoll event engine" >&5
+echo $ECHO_N "checking whether to enable the epoll event engine... $ECHO_C" >&6; }
+# Check whether --enable-epoll was given.
+if test "${enable_epoll+set}" = set; then
+  enableval=$enable_epoll; unet_cv_enable_epoll=$enable_epoll
+else
+  if test "${unet_cv_enable_epoll+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  unet_cv_enable_epoll=yes
+fi
+
+fi
+
+
+if test x"$ac_cv_header_sys_epoll_h" = xno -o x"$ac_cv_func_epoll" = xno; then
+    unet_cv_enable_epoll=no
+fi
+
+{ echo "$as_me:$LINENO: result: $unet_cv_enable_epoll" >&5
+echo "${ECHO_T}$unet_cv_enable_epoll" >&6; }
+
+if test x"$unet_cv_enable_epoll" != xno; then
+    { echo "$as_me:$LINENO: checking whether epoll functions are properly defined" >&5
+echo $ECHO_N "checking whether epoll functions are properly defined... $ECHO_C" >&6; }
+    cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <sys/epoll.h>
+int
+main ()
+{
+epoll_create(10);
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext &&
+       $as_test_x conftest$ac_exeext; then
+  { echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6; }
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+
+cat >>confdefs.h <<\_ACEOF
+#define EPOLL_NEED_BODY 1
+_ACEOF
+
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+
+cat >>confdefs.h <<\_ACEOF
+#define USE_EPOLL 1
+_ACEOF
+
+    ENGINE_C="engine_epoll.c $ENGINE_C"
+fi
+
+{ echo "$as_me:$LINENO: checking for va_copy" >&5
+echo $ECHO_N "checking for va_copy... $ECHO_C" >&6; }
+if test "${unet_cv_c_va_copy+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <stdarg.h>
+int
+main ()
+{
+va_list ap1, ap2; va_copy(ap1, ap2);
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext &&
+       $as_test_x conftest$ac_exeext; then
+  unet_cv_c_va_copy="yes"
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       unet_cv_c_va_copy="no"
+
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+fi
+{ echo "$as_me:$LINENO: result: $unet_cv_c_va_copy" >&5
+echo "${ECHO_T}$unet_cv_c_va_copy" >&6; }
+if test "$unet_cv_c_va_copy" = "yes" ; then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_VA_COPY 1
+_ACEOF
+
+fi
+
+{ echo "$as_me:$LINENO: checking for __va_copy" >&5
+echo $ECHO_N "checking for __va_copy... $ECHO_C" >&6; }
+if test "${unet_cv_c___va_copy+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <stdarg.h>
+int
+main ()
+{
+va_list ap1, ap2; __va_copy(ap1, ap2);
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext &&
+       $as_test_x conftest$ac_exeext; then
+  unet_cv_c___va_copy="yes"
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       unet_cv_c___va_copy="no"
+
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+fi
+{ echo "$as_me:$LINENO: result: $unet_cv_c___va_copy" >&5
+echo "${ECHO_T}$unet_cv_c___va_copy" >&6; }
+if test "$unet_cv_c___va_copy" = "yes" ; then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE___VA_COPY 1
+_ACEOF
+
+fi
+
+{ echo "$as_me:$LINENO: checking what name to give the symlink" >&5
+echo $ECHO_N "checking what name to give the symlink... $ECHO_C" >&6; }
+
+# Check whether --with-symlink was given.
+if test "${with_symlink+set}" = set; then
+  withval=$with_symlink; unet_cv_with_symlink=$with_symlink
+else
+  if test "${unet_cv_with_symlink+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  unet_cv_with_symlink="ircd"
+fi
+
+fi
+
+
+if test x"$unet_cv_with_symlink" = xyes; then
+    unet_cv_with_symlink="ircd"
+fi
+
+{ echo "$as_me:$LINENO: result: $unet_cv_with_symlink" >&5
+echo "${ECHO_T}$unet_cv_with_symlink" >&6; }
+
+if test x"$unet_cv_with_symlink" = xno; then
+    INSTALL_RULE=install-no-symlink
+    SYMLINK=
+else
+    INSTALL_RULE=install-with-symlink
+    SYMLINK=$unet_cv_with_symlink
+fi
+
+
+
+{ echo "$as_me:$LINENO: checking what permissions to set on the installed binary" >&5
+echo $ECHO_N "checking what permissions to set on the installed binary... $ECHO_C" >&6; }
+
+# Check whether --with-mode was given.
+if test "${with_mode+set}" = set; then
+  withval=$with_mode; unet_cv_with_mode=$with_mode
+else
+  if test "${unet_cv_with_mode+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  unet_cv_with_mode=711
+fi
+
+fi
+
+
+if test x"$unet_cv_with_mode" = xyes -o x"$unet_cv_with_mode" = xno; then
+    unet_cv_with_mode=711
+fi
+
+{ echo "$as_me:$LINENO: result: $unet_cv_with_mode" >&5
+echo "${ECHO_T}$unet_cv_with_mode" >&6; }
+
+IRCDMODE=$unet_cv_with_mode
+
+
+unet_uid=`id | sed -e 's/.*uid=[0-9]*(//' -e 's/).*//' 2> /dev/null`
+{ echo "$as_me:$LINENO: checking which user should own the installed binary" >&5
+echo $ECHO_N "checking which user should own the installed binary... $ECHO_C" >&6; }
+
+# Check whether --with-owner was given.
+if test "${with_owner+set}" = set; then
+  withval=$with_owner; unet_cv_with_owner=$with_owner
+else
+  if test "${unet_cv_with_owner+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  unet_cv_with_owner=$unet_uid
+fi
+
+fi
+
+
+if test x"$unet_cv_with_owner" = xyes -o x"$unet_cv_with_owner" = xno; then
+    unet_cv_with_owner=$unet_uid
+fi
+
+{ echo "$as_me:$LINENO: result: $unet_cv_with_owner" >&5
+echo "${ECHO_T}$unet_cv_with_owner" >&6; }
+
+IRCDOWN=$unet_cv_with_owner
+
+
+unet_gid=`id | sed -e 's/.*gid=[0-9]*(//' -e 's/).*//' 2> /dev/null`
+{ echo "$as_me:$LINENO: checking which group should own the installed binary" >&5
+echo $ECHO_N "checking which group should own the installed binary... $ECHO_C" >&6; }
+
+# Check whether --with-group was given.
+if test "${with_group+set}" = set; then
+  withval=$with_group; unet_cv_with_group=$with_group
+else
+  if test "${unet_cv_with_group+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  unet_cv_with_group=$unet_gid
+fi
+
+fi
+
+
+if test x"$unet_cv_with_group" = xyes -o x"$unet_cv_with_group" = xno; then
+    unet_cv_with_group=$unet_gid
+fi
+
+{ echo "$as_me:$LINENO: result: $unet_cv_with_group" >&5
+echo "${ECHO_T}$unet_cv_with_group" >&6; }
+
+IRCDGRP=$unet_cv_with_group
+
+
+unet_domain=
+if test -f /etc/resolv.conf; then
+    unet_domain=`awk '/^domain/ { print $2; exit }' /etc/resolv.conf`
+    if test x"$unet_domain" = x; then
+       unet_domain=`awk '/^search/ { print $2; exit }' /etc/resolv.conf`
+    fi
+fi
+{ echo "$as_me:$LINENO: checking for site domain name" >&5
+echo $ECHO_N "checking for site domain name... $ECHO_C" >&6; }
+
+# Check whether --with-domain was given.
+if test "${with_domain+set}" = set; then
+  withval=$with_domain; unet_cv_with_domain=$with_domain
+else
+  if test "${unet_cv_with_domain+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  unet_cv_with_domain=$unet_domain
+fi
+
+fi
+
+
+if test x"$unet_cv_with_domain" = xyes -o x"$unet_cv_with_domain" = xno; then
+    unet_cv_with_domain=$unet_domain
+fi
+if test x"$unet_cv_with_domain" = xno; then
+    { { echo "$as_me:$LINENO: error: Unable to determine server DNS domain; use --with-domain to set it" >&5
+echo "$as_me: error: Unable to determine server DNS domain; use --with-domain to set it" >&2;}
+   { (exit 1); exit 1; }; }
+fi
+
+{ echo "$as_me:$LINENO: result: $unet_cv_with_domain" >&5
+echo "${ECHO_T}$unet_cv_with_domain" >&6; }
+
+
+cat >>confdefs.h <<_ACEOF
+#define DOMAINNAME "*$unet_cv_with_domain"
+_ACEOF
+
+
+{ echo "$as_me:$LINENO: checking if chroot operation is desired" >&5
+echo $ECHO_N "checking if chroot operation is desired... $ECHO_C" >&6; }
+
+# Check whether --with-chroot was given.
+if test "${with_chroot+set}" = set; then
+  withval=$with_chroot; unet_cv_with_chroot=$with_chroot
+else
+  if test "${unet_cv_with_chroot+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  unet_cv_with_chroot=no
+fi
+
+fi
+
+
+if test x"$unet_cv_with_chroot" = xyes; then
+    { { echo "$as_me:$LINENO: error: --with-chroot given with no directory.  See doc/readme.chroot." >&5
+echo "$as_me: error: --with-chroot given with no directory.  See doc/readme.chroot." >&2;}
+   { (exit 1); exit 1; }; }
+fi
+
+# Ensure there are no trailing /'s to mess us up
+unet_cv_with_chroot=`echo "$unet_cv_with_chroot" | sed 's%/*$%%'`
+
+{ echo "$as_me:$LINENO: result: $unet_cv_with_chroot" >&5
+echo "${ECHO_T}$unet_cv_with_chroot" >&6; }
+
+# Deal with the annoying value "NONE" here
+unet_save_prefix=$prefix
+if test x"$prefix" = xNONE; then
+    prefix=$ac_default_prefix
+else
+    prefix=$prefix
+fi
+
+unet_save_exec_prefix=$exec_prefix
+if test x"$exec_prefix" = xNONE; then
+    exec_prefix=$prefix
+else
+    exec_prefix=$exec_prefix
+fi
+
+# Obtain the actual interesting directories
+unet_bindir=`eval echo "$bindir"`
+unet_libdir=`eval echo "$libdir"`
+
+# Restore the original settings of $prefix and $exec_prefix
+prefix=$unet_save_prefix
+exec_prefix=$unet_save_exec_prefix
+
+{ echo "$as_me:$LINENO: checking where the binary will be for /restart" >&5
+echo $ECHO_N "checking where the binary will be for /restart... $ECHO_C" >&6; }
+if test x"$unet_cv_with_symlink" = xno; then
+    unet_spath="$unet_bindir/ircd"
+else
+    unet_spath="$unet_bindir/$unet_cv_with_symlink"
+fi
+{ echo "$as_me:$LINENO: result: $unet_spath" >&5
+echo "${ECHO_T}$unet_spath" >&6; }
+
+if test x"$unet_cv_with_chroot" != xno; then
+    if echo "$unet_spath" | grep "^$unet_cv_with_chroot" > /dev/null 2>&1; then
+       unet_spath=`echo "$unet_spath" | sed "s%^$unet_cv_with_chroot%%"`
+    else
+       { echo "$as_me:$LINENO: WARNING: Binary $unet_spath not relative to root directory $unet_cv_with_chroot; restarts will probably fail" >&5
+echo "$as_me: WARNING: Binary $unet_spath not relative to root directory $unet_cv_with_chroot; restarts will probably fail" >&2;}
+    fi
+fi
+
+
+cat >>confdefs.h <<_ACEOF
+#define SPATH "$unet_spath"
+_ACEOF
+
+
+{ echo "$as_me:$LINENO: checking what the data directory should be" >&5
+echo $ECHO_N "checking what the data directory should be... $ECHO_C" >&6; }
+
+# Check whether --with-dpath was given.
+if test "${with_dpath+set}" = set; then
+  withval=$with_dpath; unet_cv_with_dpath=$with_dpath
+else
+  if test "${unet_cv_with_dpath+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  unet_cv_with_dpath=$unet_libdir
+fi
+
+fi
+
+
+if test x"$unet_cv_with_dpath" = xyes -o x"$unet_cv_with_dpath" = xno; then
+    unet_cv_with_dpath=$unet_libdir
+fi
+
+# Ensure there are no trailing /'s to mess us up
+unet_cv_with_dpath=`echo "$unet_cv_with_dpath" | sed 's%/*$%%'`
+
+{ echo "$as_me:$LINENO: result: $unet_cv_with_dpath" >&5
+echo "${ECHO_T}$unet_cv_with_dpath" >&6; }
+
+if test x"$unet_cv_with_chroot" != xno; then
+    if echo "$unet_cv_with_dpath" | grep "^$unet_cv_with_chroot" > /dev/null 2>&1; then
+       unet_dpath=`echo "$unet_cv_with_dpath" | sed "s%^$unet_cv_with_chroot%%"`
+    else
+       { { echo "$as_me:$LINENO: error: Data directory $unet_cv_with_dpath not relative to root directory $unet_cv_with_chroot" >&5
+echo "$as_me: error: Data directory $unet_cv_with_dpath not relative to root directory $unet_cv_with_chroot" >&2;}
+   { (exit 1); exit 1; }; }
+    fi
+else
+    unet_dpath=$unet_cv_with_dpath
+fi
+
+
+cat >>confdefs.h <<_ACEOF
+#define DPATH "$unet_dpath"
+_ACEOF
+
+
+DPATH=$unet_cv_with_dpath
+
+
+{ echo "$as_me:$LINENO: checking where the default configuration file resides" >&5
+echo $ECHO_N "checking where the default configuration file resides... $ECHO_C" >&6; }
+
+# Check whether --with-cpath was given.
+if test "${with_cpath+set}" = set; then
+  withval=$with_cpath; unet_cv_with_cpath=$with_cpath
+else
+  if test "${unet_cv_with_cpath+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  unet_cv_with_cpath="ircd.conf"
+fi
+
+fi
+
+
+if test x"$unet_cv_with_cpath" = xyes -o x"$unet_cv_with_cpath" = xno; then
+    unet_cv_with_cpath="ircd.conf"
+fi
+
+{ echo "$as_me:$LINENO: result: $unet_cv_with_cpath" >&5
+echo "${ECHO_T}$unet_cv_with_cpath" >&6; }
+
+if echo "$unet_cv_with_cpath" | grep '^/' > /dev/null 2>&1; then
+    # Absolute path; check against chroot stuff
+    if test x"$unet_cv_with_chroot" != xno; then
+       if echo "$unet_cv_with_cpath" | grep "^$unet_cv_with_chroot" > /dev/null 2>&1; then
+           unet_cpath=`echo "$unet_cv_with_cpath" | sed "s%^$unet_cv_with_chroot%%"`
+       else
+           { { echo "$as_me:$LINENO: error: Configuration file $unet_cv_with_cpath not relative to root directory $unet_cv_with_chroot" >&5
+echo "$as_me: error: Configuration file $unet_cv_with_cpath not relative to root directory $unet_cv_with_chroot" >&2;}
+   { (exit 1); exit 1; }; }
+       fi
+    else
+       unet_cpath=$unet_cv_with_cpath
+    fi
+else
+    unet_cpath=$unet_cv_with_cpath
+fi
+
+
+cat >>confdefs.h <<_ACEOF
+#define CPATH "$unet_cpath"
+_ACEOF
+
+
+{ echo "$as_me:$LINENO: checking where to put the debugging log if debugging enabled" >&5
+echo $ECHO_N "checking where to put the debugging log if debugging enabled... $ECHO_C" >&6; }
+
+# Check whether --with-lpath was given.
+if test "${with_lpath+set}" = set; then
+  withval=$with_lpath; unet_cv_with_lpath=$with_lpath
+else
+  if test "${unet_cv_with_lpath+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  unet_cv_with_lpath="ircd.log"
+fi
+
+fi
+
+
+if test x"$unet_cv_with_lpath" = xyes -o x"$unet_cv_with_lpath" = xno; then
+    unet_cv_with_lpath="ircd.log"
+fi
+
+{ echo "$as_me:$LINENO: result: $unet_cv_with_lpath" >&5
+echo "${ECHO_T}$unet_cv_with_lpath" >&6; }
+
+if echo "$unet_cv_with_lpath" | grep '^/' > /dev/null 2>&1; then
+    # Absolute path; check against chroot stuff
+    if test x"$unet_cv_with_chroot" != xno; then
+       if echo "$unet_cv_with_lpath" | grep "^$unet_cv_with_chroot" > /dev/null 2>&1; then
+           unet_lpath=`echo "$unet_cv_with_lpath" | sed "s%^$unet_cv_with_chroot%%"`
+       else
+           { echo "$as_me:$LINENO: WARNING: Log file $unet_cv_with_lpath not relative to root directory $unet_cv_with_chroot; using default ircd.log instead" >&5
+echo "$as_me: WARNING: Log file $unet_cv_with_lpath not relative to root directory $unet_cv_with_chroot; using default ircd.log instead" >&2;}
+           unet_cv_with_lpath="ircd.log"
+           unet_lpath="ircd.log"
+       fi
+    else
+       unet_lpath=$unet_cv_with_lpath
+    fi
+else
+    unet_lpath=$unet_cv_with_lpath
+fi
+
+
+cat >>confdefs.h <<_ACEOF
+#define LPATH "$unet_lpath"
+_ACEOF
+
+
+unet_maxcon=`ulimit -Hn`
+if test x"$unet_maxcon" = xunlimited; then
+    unet_maxcon=`ulimit -Sn`
+fi
+unet_maxcon=`expr $unet_maxcon - 4`
+{ echo "$as_me:$LINENO: checking max connections" >&5
+echo $ECHO_N "checking max connections... $ECHO_C" >&6; }
+
+# Check whether --with-maxcon was given.
+if test "${with_maxcon+set}" = set; then
+  withval=$with_maxcon; unet_cv_with_maxcon=$with_maxcon
+else
+  if test "${unet_cv_with_maxcon+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  unet_cv_with_maxcon=$unet_maxcon
+fi
+
+fi
+
+
+if test x"$unet_cv_with_maxcon" = xyes -o x"$unet_cv_with_maxcon" = xno; then
+    if test "$unet_maxcon" -lt 32; then
+      { { echo "$as_me:$LINENO: error: Maximum connections (number of open files minus 4) must be at least 32." >&5
+echo "$as_me: error: Maximum connections (number of open files minus 4) must be at least 32." >&2;}
+   { (exit 1); exit 1; }; }
+    fi
+    unet_cv_with_maxcon=$unet_maxcon
+elif test "$unet_cv_with_maxcon" -lt 32; then
+    { { echo "$as_me:$LINENO: error: Maximum connections (--with-maxcon) must be at least 32." >&5
+echo "$as_me: error: Maximum connections (--with-maxcon) must be at least 32." >&2;}
+   { (exit 1); exit 1; }; }
+fi
+
+{ echo "$as_me:$LINENO: result: $unet_cv_with_maxcon" >&5
+echo "${ECHO_T}$unet_cv_with_maxcon" >&6; }
+
+
+cat >>confdefs.h <<_ACEOF
+#define MAXCONNECTIONS $unet_cv_with_maxcon
+_ACEOF
+
+
+unet_cv_enable_compat="yes"
+{ echo "$as_me:$LINENO: checking whether to enable OGN-compat mode" >&5
+echo $ECHO_N "checking whether to enable OGN-compat mode... $ECHO_C" >&6; }
+# Check whether --enable-compat was given.
+if test "${enable_compat+set}" = set; then
+  enableval=$enable_compat; unet_cv_enable_compat=$enable_compat
+fi
+
+{ echo "$as_me:$LINENO: result: $unet_cv_enable_compat" >&5
+echo "${ECHO_T}$unet_cv_enable_compat" >&6; }
+
+if test $unet_cv_enable_compat = "no" ; then
+    # do nothing
+    unet_cv_enable_compat="no"
+else
+
+cat >>confdefs.h <<\_ACEOF
+#define OLD_OGN_IRCU_COMPAT 1
+_ACEOF
+
+fi
+
+unet_cv_enable_unstable="no"
+{ echo "$as_me:$LINENO: checking whether to enable unstable features" >&5
+echo $ECHO_N "checking whether to enable unstable features... $ECHO_C" >&6; }
+# Check whether --enable-unstable was given.
+if test "${enable_unstable+set}" = set; then
+  enableval=$enable_unstable; unet_cv_enable_unstable=$enable_unstable
+fi
+
+{ echo "$as_me:$LINENO: result: $unet_cv_enable_unstable" >&5
+echo "${ECHO_T}$unet_cv_enable_unstable" >&6; }
+
+if test $unet_cv_enable_unstable = "yes" ; then
+
+cat >>confdefs.h <<\_ACEOF
+#define WITH_UNSTABLE_FEAT 1
+_ACEOF
+
+fi
+
+
+unet_cv_enable_gnutls="no"
+unet_cv_enable_openssl="yes"
+
+{ echo "$as_me:$LINENO: checking for GnuTLS" >&5
+echo $ECHO_N "checking for GnuTLS... $ECHO_C" >&6; }
+# Check whether --enable-gnutls was given.
+if test "${enable_gnutls+set}" = set; then
+  enableval=$enable_gnutls; unet_cv_enable_gnutls=$enable_gnutls
+fi
+
+{ echo "$as_me:$LINENO: result: $unet_cv_enable_gnutls" >&5
+echo "${ECHO_T}$unet_cv_enable_gnutls" >&6; }
+
+{ echo "$as_me:$LINENO: checking for OpenSSL" >&5
+echo $ECHO_N "checking for OpenSSL... $ECHO_C" >&6; }
+# Check whether --enable-openssl was given.
+if test "${enable_openssl+set}" = set; then
+  enableval=$enable_openssl; unet_cv_enable_openssl=$enable_openssl
+fi
+
+{ echo "$as_me:$LINENO: result: $unet_cv_enable_openssl" >&5
+echo "${ECHO_T}$unet_cv_enable_openssl" >&6; }
+
+if test x"$unet_cv_enable_gnutls" = xyes; then
+  unet_cv_enable_gnutls="no";
+  { echo "$as_me:$LINENO: checking for gnutls_init in -lgnutls" >&5
+echo $ECHO_N "checking for gnutls_init in -lgnutls... $ECHO_C" >&6; }
+if test "${ac_cv_lib_gnutls_gnutls_init+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lgnutls  $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char gnutls_init ();
+int
+main ()
+{
+return gnutls_init ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext &&
+       $as_test_x conftest$ac_exeext; then
+  ac_cv_lib_gnutls_gnutls_init=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_lib_gnutls_gnutls_init=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_lib_gnutls_gnutls_init" >&5
+echo "${ECHO_T}$ac_cv_lib_gnutls_gnutls_init" >&6; }
+if test $ac_cv_lib_gnutls_gnutls_init = yes; then
+
+
+for ac_header in gnutls/gnutls.h
+do
+as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
+if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
+  { echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; }
+if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+fi
+ac_res=`eval echo '${'$as_ac_Header'}'`
+              { echo "$as_me:$LINENO: result: $ac_res" >&5
+echo "${ECHO_T}$ac_res" >&6; }
+else
+  # Is the header compilable?
+{ echo "$as_me:$LINENO: checking $ac_header usability" >&5
+echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6; }
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+#include <$ac_header>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_header_compiler=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_header_compiler=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+{ echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
+echo "${ECHO_T}$ac_header_compiler" >&6; }
+
+# Is the header present?
+{ echo "$as_me:$LINENO: checking $ac_header presence" >&5
+echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6; }
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <$ac_header>
+_ACEOF
+if { (ac_try="$ac_cpp conftest.$ac_ext"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } >/dev/null && {
+        test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       }; then
+  ac_header_preproc=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+  ac_header_preproc=no
+fi
+
+rm -f conftest.err conftest.$ac_ext
+{ echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
+echo "${ECHO_T}$ac_header_preproc" >&6; }
+
+# So?  What about this header?
+case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
+  yes:no: )
+    { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5
+echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;}
+    ac_header_preproc=yes
+    ;;
+  no:yes:* )
+    { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5
+echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header:     check for missing prerequisite headers?" >&5
+echo "$as_me: WARNING: $ac_header:     check for missing prerequisite headers?" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5
+echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&5
+echo "$as_me: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5
+echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;}
+
+    ;;
+esac
+{ echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; }
+if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  eval "$as_ac_Header=\$ac_header_preproc"
+fi
+ac_res=`eval echo '${'$as_ac_Header'}'`
+              { echo "$as_me:$LINENO: result: $ac_res" >&5
+echo "${ECHO_T}$ac_res" >&6; }
+
+fi
+if test `eval echo '${'$as_ac_Header'}'` = yes; then
+  cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+      unet_cv_enable_gnutls="yes";
+
+fi
+
+done
+
+
+fi
+
+fi
+
+if test x"$unet_cv_enable_openssl" = xyes; then
+  unet_cv_enable_openssl="no";
+  { echo "$as_me:$LINENO: checking for SSL_read in -lssl" >&5
+echo $ECHO_N "checking for SSL_read in -lssl... $ECHO_C" >&6; }
+if test "${ac_cv_lib_ssl_SSL_read+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lssl  $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char SSL_read ();
+int
+main ()
+{
+return SSL_read ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext &&
+       $as_test_x conftest$ac_exeext; then
+  ac_cv_lib_ssl_SSL_read=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_lib_ssl_SSL_read=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_lib_ssl_SSL_read" >&5
+echo "${ECHO_T}$ac_cv_lib_ssl_SSL_read" >&6; }
+if test $ac_cv_lib_ssl_SSL_read = yes; then
+
+    { echo "$as_me:$LINENO: checking for X509_new in -lcrypto" >&5
+echo $ECHO_N "checking for X509_new in -lcrypto... $ECHO_C" >&6; }
+if test "${ac_cv_lib_crypto_X509_new+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lcrypto  $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char X509_new ();
+int
+main ()
+{
+return X509_new ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext &&
+       $as_test_x conftest$ac_exeext; then
+  ac_cv_lib_crypto_X509_new=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_lib_crypto_X509_new=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_lib_crypto_X509_new" >&5
+echo "${ECHO_T}$ac_cv_lib_crypto_X509_new" >&6; }
+if test $ac_cv_lib_crypto_X509_new = yes; then
+
+
+
+for ac_header in openssl/ssl.h openssl/err.h
+do
+as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
+if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
+  { echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; }
+if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+fi
+ac_res=`eval echo '${'$as_ac_Header'}'`
+              { echo "$as_me:$LINENO: result: $ac_res" >&5
+echo "${ECHO_T}$ac_res" >&6; }
+else
+  # Is the header compilable?
+{ echo "$as_me:$LINENO: checking $ac_header usability" >&5
+echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6; }
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+#include <$ac_header>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_header_compiler=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_header_compiler=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+{ echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
+echo "${ECHO_T}$ac_header_compiler" >&6; }
+
+# Is the header present?
+{ echo "$as_me:$LINENO: checking $ac_header presence" >&5
+echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6; }
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <$ac_header>
+_ACEOF
+if { (ac_try="$ac_cpp conftest.$ac_ext"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } >/dev/null && {
+        test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       }; then
+  ac_header_preproc=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+  ac_header_preproc=no
+fi
+
+rm -f conftest.err conftest.$ac_ext
+{ echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
+echo "${ECHO_T}$ac_header_preproc" >&6; }
+
+# So?  What about this header?
+case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
+  yes:no: )
+    { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5
+echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;}
+    ac_header_preproc=yes
+    ;;
+  no:yes:* )
+    { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5
+echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header:     check for missing prerequisite headers?" >&5
+echo "$as_me: WARNING: $ac_header:     check for missing prerequisite headers?" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5
+echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&5
+echo "$as_me: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5
+echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;}
+
+    ;;
+esac
+{ echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; }
+if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  eval "$as_ac_Header=\$ac_header_preproc"
+fi
+ac_res=`eval echo '${'$as_ac_Header'}'`
+              { echo "$as_me:$LINENO: result: $ac_res" >&5
+echo "${ECHO_T}$ac_res" >&6; }
+
+fi
+if test `eval echo '${'$as_ac_Header'}'` = yes; then
+  cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+        unet_cv_enable_openssl="yes";
+
+fi
+
+done
+
+
+fi
+
+
+fi
+
+fi
+
+if test x"$unet_cv_enable_gnutls" = xyes; then
+    LIBS="$LIBS -lgnutls"
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_GNUTLS 1
+_ACEOF
+
+fi
+
+if test x"$unet_cv_enable_openssl" = xyes ; then
+    LIBS="$LIBS -lssl -lcrypto"
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_OPENSSL 1
+_ACEOF
+
+fi
+
+ac_config_files="$ac_config_files Makefile ircd/Makefile doc/Makefile"
+
+ac_config_commands="$ac_config_commands default"
+
+cat >confcache <<\_ACEOF
+# This file is a shell script that caches the results of configure
+# tests run on this system so they can be shared between configure
+# scripts and configure runs, see configure's option --config-cache.
+# It is not useful on other systems.  If it contains results you don't
+# want to keep, you may remove or edit it.
+#
+# config.status only pays attention to the cache file if you give it
+# the --recheck option to rerun configure.
+#
+# `ac_cv_env_foo' variables (set or unset) will be overridden when
+# loading this file, other *unset* `ac_cv_foo' will be assigned the
+# following values.
+
+_ACEOF
+
+# The following way of writing the cache mishandles newlines in values,
+# but we know of no workaround that is simple, portable, and efficient.
+# So, we kill variables containing newlines.
+# Ultrix sh set writes to stderr and can't be redirected directly,
+# and sets the high bit in the cache file unless we assign to the vars.
+(
+  for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do
+    eval ac_val=\$$ac_var
+    case $ac_val in #(
+    *${as_nl}*)
+      case $ac_var in #(
+      *_cv_*) { echo "$as_me:$LINENO: WARNING: Cache variable $ac_var contains a newline." >&5
+echo "$as_me: WARNING: Cache variable $ac_var contains a newline." >&2;} ;;
+      esac
+      case $ac_var in #(
+      _ | IFS | as_nl) ;; #(
+      *) $as_unset $ac_var ;;
+      esac ;;
+    esac
+  done
+
+  (set) 2>&1 |
+    case $as_nl`(ac_space=' '; set) 2>&1` in #(
+    *${as_nl}ac_space=\ *)
+      # `set' does not quote correctly, so add quotes (double-quote
+      # substitution turns \\\\ into \\, and sed turns \\ into \).
+      sed -n \
+       "s/'/'\\\\''/g;
+         s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p"
+      ;; #(
+    *)
+      # `set' quotes correctly as required by POSIX, so do not add quotes.
+      sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p"
+      ;;
+    esac |
+    sort
+) |
+  sed '
+     /^ac_cv_env_/b end
+     t clear
+     :clear
+     s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/
+     t end
+     s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/
+     :end' >>confcache
+if diff "$cache_file" confcache >/dev/null 2>&1; then :; else
+  if test -w "$cache_file"; then
+    test "x$cache_file" != "x/dev/null" &&
+      { echo "$as_me:$LINENO: updating cache $cache_file" >&5
+echo "$as_me: updating cache $cache_file" >&6;}
+    cat confcache >$cache_file
+  else
+    { echo "$as_me:$LINENO: not updating unwritable cache $cache_file" >&5
+echo "$as_me: not updating unwritable cache $cache_file" >&6;}
+  fi
+fi
+rm -f confcache
+
+test "x$prefix" = xNONE && prefix=$ac_default_prefix
+# Let make expand exec_prefix.
+test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
+
+DEFS=-DHAVE_CONFIG_H
+
+ac_libobjs=
+ac_ltlibobjs=
+for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue
+  # 1. Remove the extension, and $U if already installed.
+  ac_script='s/\$U\././;s/\.o$//;s/\.obj$//'
+  ac_i=`echo "$ac_i" | sed "$ac_script"`
+  # 2. Prepend LIBOBJDIR.  When used with automake>=1.10 LIBOBJDIR
+  #    will be set to the directory where LIBOBJS objects are built.
+  ac_libobjs="$ac_libobjs \${LIBOBJDIR}$ac_i\$U.$ac_objext"
+  ac_ltlibobjs="$ac_ltlibobjs \${LIBOBJDIR}$ac_i"'$U.lo'
+done
+LIBOBJS=$ac_libobjs
+
+LTLIBOBJS=$ac_ltlibobjs
+
+
+
+: ${CONFIG_STATUS=./config.status}
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files $CONFIG_STATUS"
+{ echo "$as_me:$LINENO: creating $CONFIG_STATUS" >&5
+echo "$as_me: creating $CONFIG_STATUS" >&6;}
+cat >$CONFIG_STATUS <<_ACEOF
+#! $SHELL
+# Generated by $as_me.
+# Run this file to recreate the current configuration.
+# Compiler output produced by configure, useful for debugging
+# configure, is in config.log if it exists.
+
+debug=false
+ac_cs_recheck=false
+ac_cs_silent=false
+SHELL=\${CONFIG_SHELL-$SHELL}
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF
+## --------------------- ##
+## M4sh Initialization.  ##
+## --------------------- ##
+
+# Be more Bourne compatible
+DUALCASE=1; export DUALCASE # for MKS sh
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then
+  emulate sh
+  NULLCMD=:
+  # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which
+  # is contrary to our usage.  Disable this feature.
+  alias -g '${1+"$@"}'='"$@"'
+  setopt NO_GLOB_SUBST
+else
+  case `(set -o) 2>/dev/null` in
+  *posix*) set -o posix ;;
+esac
+
+fi
+
+
+
+
+# PATH needs CR
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+  echo "#! /bin/sh" >conf$$.sh
+  echo  "exit 0"   >>conf$$.sh
+  chmod +x conf$$.sh
+  if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then
+    PATH_SEPARATOR=';'
+  else
+    PATH_SEPARATOR=:
+  fi
+  rm -f conf$$.sh
+fi
+
+# Support unset when possible.
+if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then
+  as_unset=unset
+else
+  as_unset=false
+fi
+
+
+# IFS
+# We need space, tab and new line, in precisely that order.  Quoting is
+# there to prevent editors from complaining about space-tab.
+# (If _AS_PATH_WALK were called with IFS unset, it would disable word
+# splitting by setting IFS to empty value.)
+as_nl='
+'
+IFS=" ""       $as_nl"
+
+# Find who we are.  Look in the path if we contain no directory separator.
+case $0 in
+  *[\\/]* ) as_myself=$0 ;;
+  *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+done
+IFS=$as_save_IFS
+
+     ;;
+esac
+# We did not find ourselves, most probably we were run as `sh COMMAND'
+# in which case we are not to be found in the path.
+if test "x$as_myself" = x; then
+  as_myself=$0
+fi
+if test ! -f "$as_myself"; then
+  echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
+  { (exit 1); exit 1; }
+fi
+
+# Work around bugs in pre-3.0 UWIN ksh.
+for as_var in ENV MAIL MAILPATH
+do ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var
+done
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+for as_var in \
+  LANG LANGUAGE LC_ADDRESS LC_ALL LC_COLLATE LC_CTYPE LC_IDENTIFICATION \
+  LC_MEASUREMENT LC_MESSAGES LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER \
+  LC_TELEPHONE LC_TIME
+do
+  if (set +x; test -z "`(eval $as_var=C; export $as_var) 2>&1`"); then
+    eval $as_var=C; export $as_var
+  else
+    ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var
+  fi
+done
+
+# Required to use basename.
+if expr a : '\(a\)' >/dev/null 2>&1 &&
+   test "X`expr 00001 : '.*\(...\)'`" = X001; then
+  as_expr=expr
+else
+  as_expr=false
+fi
+
+if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then
+  as_basename=basename
+else
+  as_basename=false
+fi
+
+
+# Name of the executable.
+as_me=`$as_basename -- "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+        X"$0" : 'X\(//\)$' \| \
+        X"$0" : 'X\(/\)' \| . 2>/dev/null ||
+echo X/"$0" |
+    sed '/^.*\/\([^/][^/]*\)\/*$/{
+           s//\1/
+           q
+         }
+         /^X\/\(\/\/\)$/{
+           s//\1/
+           q
+         }
+         /^X\/\(\/\).*/{
+           s//\1/
+           q
+         }
+         s/.*/./; q'`
+
+# CDPATH.
+$as_unset CDPATH
+
+
+
+  as_lineno_1=$LINENO
+  as_lineno_2=$LINENO
+  test "x$as_lineno_1" != "x$as_lineno_2" &&
+  test "x`expr $as_lineno_1 + 1`" = "x$as_lineno_2" || {
+
+  # Create $as_me.lineno as a copy of $as_myself, but with $LINENO
+  # uniformly replaced by the line number.  The first 'sed' inserts a
+  # line-number line after each line using $LINENO; the second 'sed'
+  # does the real work.  The second script uses 'N' to pair each
+  # line-number line with the line containing $LINENO, and appends
+  # trailing '-' during substitution so that $LINENO is not a special
+  # case at line end.
+  # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the
+  # scripts with optimization help from Paolo Bonzini.  Blame Lee
+  # E. McMahon (1931-1989) for sed's syntax.  :-)
+  sed -n '
+    p
+    /[$]LINENO/=
+  ' <$as_myself |
+    sed '
+      s/[$]LINENO.*/&-/
+      t lineno
+      b
+      :lineno
+      N
+      :loop
+      s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/
+      t loop
+      s/-\n.*//
+    ' >$as_me.lineno &&
+  chmod +x "$as_me.lineno" ||
+    { echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2
+   { (exit 1); exit 1; }; }
+
+  # Don't try to exec as it changes $[0], causing all sort of problems
+  # (the dirname of $[0] is not the place where we might find the
+  # original and so on.  Autoconf is especially sensitive to this).
+  . "./$as_me.lineno"
+  # Exit status is that of the last command.
+  exit
+}
+
+
+if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
+  as_dirname=dirname
+else
+  as_dirname=false
+fi
+
+ECHO_C= ECHO_N= ECHO_T=
+case `echo -n x` in
+-n*)
+  case `echo 'x\c'` in
+  *c*) ECHO_T='        ';;     # ECHO_T is single tab character.
+  *)   ECHO_C='\c';;
+  esac;;
+*)
+  ECHO_N='-n';;
+esac
+
+if expr a : '\(a\)' >/dev/null 2>&1 &&
+   test "X`expr 00001 : '.*\(...\)'`" = X001; then
+  as_expr=expr
+else
+  as_expr=false
+fi
+
+rm -f conf$$ conf$$.exe conf$$.file
+if test -d conf$$.dir; then
+  rm -f conf$$.dir/conf$$.file
+else
+  rm -f conf$$.dir
+  mkdir conf$$.dir
+fi
+echo >conf$$.file
+if ln -s conf$$.file conf$$ 2>/dev/null; then
+  as_ln_s='ln -s'
+  # ... but there are two gotchas:
+  # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
+  # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
+  # In both cases, we have to default to `cp -p'.
+  ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
+    as_ln_s='cp -p'
+elif ln conf$$.file conf$$ 2>/dev/null; then
+  as_ln_s=ln
+else
+  as_ln_s='cp -p'
+fi
+rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
+rmdir conf$$.dir 2>/dev/null
+
+if mkdir -p . 2>/dev/null; then
+  as_mkdir_p=:
+else
+  test -d ./-p && rmdir ./-p
+  as_mkdir_p=false
+fi
+
+if test -x / >/dev/null 2>&1; then
+  as_test_x='test -x'
+else
+  if ls -dL / >/dev/null 2>&1; then
+    as_ls_L_option=L
+  else
+    as_ls_L_option=
+  fi
+  as_test_x='
+    eval sh -c '\''
+      if test -d "$1"; then
+        test -d "$1/.";
+      else
+       case $1 in
+        -*)set "./$1";;
+       esac;
+       case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in
+       ???[sx]*):;;*)false;;esac;fi
+    '\'' sh
+  '
+fi
+as_executable_p=$as_test_x
+
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
+
+# Sed expression to map a string onto a valid variable name.
+as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
+
+
+exec 6>&1
+
+# Save the log message, to keep $[0] and so on meaningful, and to
+# report actual input values of CONFIG_FILES etc. instead of their
+# values after options handling.
+ac_log="
+This file was extended by $as_me, which was
+generated by GNU Autoconf 2.61.  Invocation command line was
+
+  CONFIG_FILES    = $CONFIG_FILES
+  CONFIG_HEADERS  = $CONFIG_HEADERS
+  CONFIG_LINKS    = $CONFIG_LINKS
+  CONFIG_COMMANDS = $CONFIG_COMMANDS
+  $ $0 $@
+
+on `(hostname || uname -n) 2>/dev/null | sed 1q`
+"
+
+_ACEOF
+
+cat >>$CONFIG_STATUS <<_ACEOF
+# Files that config.status was made for.
+config_files="$ac_config_files"
+config_headers="$ac_config_headers"
+config_commands="$ac_config_commands"
+
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF
+ac_cs_usage="\
+\`$as_me' instantiates files from templates according to the
+current configuration.
+
+Usage: $0 [OPTIONS] [FILE]...
+
+  -h, --help       print this help, then exit
+  -V, --version    print version number and configuration settings, then exit
+  -q, --quiet      do not print progress messages
+  -d, --debug      don't remove temporary files
+      --recheck    update $as_me by reconfiguring in the same conditions
+  --file=FILE[:TEMPLATE]
+                  instantiate the configuration file FILE
+  --header=FILE[:TEMPLATE]
+                  instantiate the configuration header FILE
+
+Configuration files:
+$config_files
+
+Configuration headers:
+$config_headers
+
+Configuration commands:
+$config_commands
+
+Report bugs to <bug-autoconf@gnu.org>."
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF
+ac_cs_version="\\
+config.status
+configured by $0, generated by GNU Autoconf 2.61,
+  with options \\"`echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`\\"
+
+Copyright (C) 2006 Free Software Foundation, Inc.
+This config.status script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it."
+
+ac_pwd='$ac_pwd'
+srcdir='$srcdir'
+INSTALL='$INSTALL'
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF
+# If no file are specified by the user, then we need to provide default
+# value.  By we need to know if files were specified by the user.
+ac_need_defaults=:
+while test $# != 0
+do
+  case $1 in
+  --*=*)
+    ac_option=`expr "X$1" : 'X\([^=]*\)='`
+    ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'`
+    ac_shift=:
+    ;;
+  *)
+    ac_option=$1
+    ac_optarg=$2
+    ac_shift=shift
+    ;;
+  esac
+
+  case $ac_option in
+  # Handling of the options.
+  -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
+    ac_cs_recheck=: ;;
+  --version | --versio | --versi | --vers | --ver | --ve | --v | -V )
+    echo "$ac_cs_version"; exit ;;
+  --debug | --debu | --deb | --de | --d | -d )
+    debug=: ;;
+  --file | --fil | --fi | --f )
+    $ac_shift
+    CONFIG_FILES="$CONFIG_FILES $ac_optarg"
+    ac_need_defaults=false;;
+  --header | --heade | --head | --hea )
+    $ac_shift
+    CONFIG_HEADERS="$CONFIG_HEADERS $ac_optarg"
+    ac_need_defaults=false;;
+  --he | --h)
+    # Conflict between --help and --header
+    { echo "$as_me: error: ambiguous option: $1
+Try \`$0 --help' for more information." >&2
+   { (exit 1); exit 1; }; };;
+  --help | --hel | -h )
+    echo "$ac_cs_usage"; exit ;;
+  -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+  | -silent | --silent | --silen | --sile | --sil | --si | --s)
+    ac_cs_silent=: ;;
+
+  # This is an error.
+  -*) { echo "$as_me: error: unrecognized option: $1
+Try \`$0 --help' for more information." >&2
+   { (exit 1); exit 1; }; } ;;
+
+  *) ac_config_targets="$ac_config_targets $1"
+     ac_need_defaults=false ;;
+
+  esac
+  shift
+done
+
+ac_configure_extra_args=
+
+if $ac_cs_silent; then
+  exec 6>/dev/null
+  ac_configure_extra_args="$ac_configure_extra_args --silent"
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF
+if \$ac_cs_recheck; then
+  echo "running CONFIG_SHELL=$SHELL $SHELL $0 "$ac_configure_args \$ac_configure_extra_args " --no-create --no-recursion" >&6
+  CONFIG_SHELL=$SHELL
+  export CONFIG_SHELL
+  exec $SHELL "$0"$ac_configure_args \$ac_configure_extra_args --no-create --no-recursion
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF
+exec 5>>config.log
+{
+  echo
+  sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX
+## Running $as_me. ##
+_ASBOX
+  echo "$ac_log"
+} >&5
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF
+
+# Handling of arguments.
+for ac_config_target in $ac_config_targets
+do
+  case $ac_config_target in
+    "config.h") CONFIG_HEADERS="$CONFIG_HEADERS config.h" ;;
+    "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;;
+    "ircd/Makefile") CONFIG_FILES="$CONFIG_FILES ircd/Makefile" ;;
+    "doc/Makefile") CONFIG_FILES="$CONFIG_FILES doc/Makefile" ;;
+    "default") CONFIG_COMMANDS="$CONFIG_COMMANDS default" ;;
+
+  *) { { echo "$as_me:$LINENO: error: invalid argument: $ac_config_target" >&5
+echo "$as_me: error: invalid argument: $ac_config_target" >&2;}
+   { (exit 1); exit 1; }; };;
+  esac
+done
+
+
+# If the user did not use the arguments to specify the items to instantiate,
+# then the envvar interface is used.  Set only those that are not.
+# We use the long form for the default assignment because of an extremely
+# bizarre bug on SunOS 4.1.3.
+if $ac_need_defaults; then
+  test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files
+  test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers
+  test "${CONFIG_COMMANDS+set}" = set || CONFIG_COMMANDS=$config_commands
+fi
+
+# Have a temporary directory for convenience.  Make it in the build tree
+# simply because there is no reason against having it here, and in addition,
+# creating and moving files from /tmp can sometimes cause problems.
+# Hook for its removal unless debugging.
+# Note that there is a small window in which the directory will not be cleaned:
+# after its creation but before its name has been assigned to `$tmp'.
+$debug ||
+{
+  tmp=
+  trap 'exit_status=$?
+  { test -z "$tmp" || test ! -d "$tmp" || rm -fr "$tmp"; } && exit $exit_status
+' 0
+  trap '{ (exit 1); exit 1; }' 1 2 13 15
+}
+# Create a (secure) tmp directory for tmp files.
+
+{
+  tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` &&
+  test -n "$tmp" && test -d "$tmp"
+}  ||
+{
+  tmp=./conf$$-$RANDOM
+  (umask 077 && mkdir "$tmp")
+} ||
+{
+   echo "$me: cannot create a temporary directory in ." >&2
+   { (exit 1); exit 1; }
+}
+
+#
+# Set up the sed scripts for CONFIG_FILES section.
+#
+
+# No need to generate the scripts if there are no CONFIG_FILES.
+# This happens for instance when ./config.status config.h
+if test -n "$CONFIG_FILES"; then
+
+_ACEOF
+
+
+
+ac_delim='%!_!# '
+for ac_last_try in false false false false false :; do
+  cat >conf$$subs.sed <<_ACEOF
+SHELL!$SHELL$ac_delim
+PATH_SEPARATOR!$PATH_SEPARATOR$ac_delim
+PACKAGE_NAME!$PACKAGE_NAME$ac_delim
+PACKAGE_TARNAME!$PACKAGE_TARNAME$ac_delim
+PACKAGE_VERSION!$PACKAGE_VERSION$ac_delim
+PACKAGE_STRING!$PACKAGE_STRING$ac_delim
+PACKAGE_BUGREPORT!$PACKAGE_BUGREPORT$ac_delim
+exec_prefix!$exec_prefix$ac_delim
+prefix!$prefix$ac_delim
+program_transform_name!$program_transform_name$ac_delim
+bindir!$bindir$ac_delim
+sbindir!$sbindir$ac_delim
+libexecdir!$libexecdir$ac_delim
+datarootdir!$datarootdir$ac_delim
+datadir!$datadir$ac_delim
+sysconfdir!$sysconfdir$ac_delim
+sharedstatedir!$sharedstatedir$ac_delim
+localstatedir!$localstatedir$ac_delim
+includedir!$includedir$ac_delim
+oldincludedir!$oldincludedir$ac_delim
+docdir!$docdir$ac_delim
+infodir!$infodir$ac_delim
+htmldir!$htmldir$ac_delim
+dvidir!$dvidir$ac_delim
+pdfdir!$pdfdir$ac_delim
+psdir!$psdir$ac_delim
+libdir!$libdir$ac_delim
+localedir!$localedir$ac_delim
+mandir!$mandir$ac_delim
+DEFS!$DEFS$ac_delim
+ECHO_C!$ECHO_C$ac_delim
+ECHO_N!$ECHO_N$ac_delim
+ECHO_T!$ECHO_T$ac_delim
+LIBS!$LIBS$ac_delim
+build_alias!$build_alias$ac_delim
+host_alias!$host_alias$ac_delim
+target_alias!$target_alias$ac_delim
+build!$build$ac_delim
+build_cpu!$build_cpu$ac_delim
+build_vendor!$build_vendor$ac_delim
+build_os!$build_os$ac_delim
+host!$host$ac_delim
+host_cpu!$host_cpu$ac_delim
+host_vendor!$host_vendor$ac_delim
+host_os!$host_os$ac_delim
+CC!$CC$ac_delim
+CFLAGS!$CFLAGS$ac_delim
+LDFLAGS!$LDFLAGS$ac_delim
+CPPFLAGS!$CPPFLAGS$ac_delim
+ac_ct_CC!$ac_ct_CC$ac_delim
+EXEEXT!$EXEEXT$ac_delim
+OBJEXT!$OBJEXT$ac_delim
+CPP!$CPP$ac_delim
+GREP!$GREP$ac_delim
+EGREP!$EGREP$ac_delim
+AWK!$AWK$ac_delim
+SET_MAKE!$SET_MAKE$ac_delim
+INSTALL_PROGRAM!$INSTALL_PROGRAM$ac_delim
+INSTALL_SCRIPT!$INSTALL_SCRIPT$ac_delim
+INSTALL_DATA!$INSTALL_DATA$ac_delim
+LN_S!$LN_S$ac_delim
+RMPROG!$RMPROG$ac_delim
+SHPROG!$SHPROG$ac_delim
+LEX!$LEX$ac_delim
+LEX_OUTPUT_ROOT!$LEX_OUTPUT_ROOT$ac_delim
+LEXLIB!$LEXLIB$ac_delim
+YACC!$YACC$ac_delim
+YFLAGS!$YFLAGS$ac_delim
+ENGINE_C!$ENGINE_C$ac_delim
+INSTALL_RULE!$INSTALL_RULE$ac_delim
+SYMLINK!$SYMLINK$ac_delim
+IRCDMODE!$IRCDMODE$ac_delim
+IRCDOWN!$IRCDOWN$ac_delim
+IRCDGRP!$IRCDGRP$ac_delim
+DPATH!$DPATH$ac_delim
+LIBOBJS!$LIBOBJS$ac_delim
+LTLIBOBJS!$LTLIBOBJS$ac_delim
+_ACEOF
+
+  if test `sed -n "s/.*$ac_delim\$/X/p" conf$$subs.sed | grep -c X` = 77; then
+    break
+  elif $ac_last_try; then
+    { { echo "$as_me:$LINENO: error: could not make $CONFIG_STATUS" >&5
+echo "$as_me: error: could not make $CONFIG_STATUS" >&2;}
+   { (exit 1); exit 1; }; }
+  else
+    ac_delim="$ac_delim!$ac_delim _$ac_delim!! "
+  fi
+done
+
+ac_eof=`sed -n '/^CEOF[0-9]*$/s/CEOF/0/p' conf$$subs.sed`
+if test -n "$ac_eof"; then
+  ac_eof=`echo "$ac_eof" | sort -nru | sed 1q`
+  ac_eof=`expr $ac_eof + 1`
+fi
+
+cat >>$CONFIG_STATUS <<_ACEOF
+cat >"\$tmp/subs-1.sed" <<\CEOF$ac_eof
+/@[a-zA-Z_][a-zA-Z_0-9]*@/!b end
+_ACEOF
+sed '
+s/[,\\&]/\\&/g; s/@/@|#_!!_#|/g
+s/^/s,@/; s/!/@,|#_!!_#|/
+:n
+t n
+s/'"$ac_delim"'$/,g/; t
+s/$/\\/; p
+N; s/^.*\n//; s/[,\\&]/\\&/g; s/@/@|#_!!_#|/g; b n
+' >>$CONFIG_STATUS <conf$$subs.sed
+rm -f conf$$subs.sed
+cat >>$CONFIG_STATUS <<_ACEOF
+:end
+s/|#_!!_#|//g
+CEOF$ac_eof
+_ACEOF
+
+
+# VPATH may cause trouble with some makes, so we remove $(srcdir),
+# ${srcdir} and @srcdir@ from VPATH if srcdir is ".", strip leading and
+# trailing colons and then remove the whole line if VPATH becomes empty
+# (actually we leave an empty line to preserve line numbers).
+if test "x$srcdir" = x.; then
+  ac_vpsub='/^[         ]*VPATH[        ]*=/{
+s/:*\$(srcdir):*/:/
+s/:*\${srcdir}:*/:/
+s/:*@srcdir@:*/:/
+s/^\([^=]*=[    ]*\):*/\1/
+s/:*$//
+s/^[^=]*=[      ]*$//
+}'
+fi
+
+cat >>$CONFIG_STATUS <<\_ACEOF
+fi # test -n "$CONFIG_FILES"
+
+
+for ac_tag in  :F $CONFIG_FILES  :H $CONFIG_HEADERS    :C $CONFIG_COMMANDS
+do
+  case $ac_tag in
+  :[FHLC]) ac_mode=$ac_tag; continue;;
+  esac
+  case $ac_mode$ac_tag in
+  :[FHL]*:*);;
+  :L* | :C*:*) { { echo "$as_me:$LINENO: error: Invalid tag $ac_tag." >&5
+echo "$as_me: error: Invalid tag $ac_tag." >&2;}
+   { (exit 1); exit 1; }; };;
+  :[FH]-) ac_tag=-:-;;
+  :[FH]*) ac_tag=$ac_tag:$ac_tag.in;;
+  esac
+  ac_save_IFS=$IFS
+  IFS=:
+  set x $ac_tag
+  IFS=$ac_save_IFS
+  shift
+  ac_file=$1
+  shift
+
+  case $ac_mode in
+  :L) ac_source=$1;;
+  :[FH])
+    ac_file_inputs=
+    for ac_f
+    do
+      case $ac_f in
+      -) ac_f="$tmp/stdin";;
+      *) # Look for the file first in the build tree, then in the source tree
+        # (if the path is not absolute).  The absolute path cannot be DOS-style,
+        # because $ac_f cannot contain `:'.
+        test -f "$ac_f" ||
+          case $ac_f in
+          [\\/$]*) false;;
+          *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";;
+          esac ||
+          { { echo "$as_me:$LINENO: error: cannot find input file: $ac_f" >&5
+echo "$as_me: error: cannot find input file: $ac_f" >&2;}
+   { (exit 1); exit 1; }; };;
+      esac
+      ac_file_inputs="$ac_file_inputs $ac_f"
+    done
+
+    # Let's still pretend it is `configure' which instantiates (i.e., don't
+    # use $as_me), people would be surprised to read:
+    #    /* config.h.  Generated by config.status.  */
+    configure_input="Generated from "`IFS=:
+         echo $* | sed 's|^[^:]*/||;s|:[^:]*/|, |g'`" by configure."
+    if test x"$ac_file" != x-; then
+      configure_input="$ac_file.  $configure_input"
+      { echo "$as_me:$LINENO: creating $ac_file" >&5
+echo "$as_me: creating $ac_file" >&6;}
+    fi
+
+    case $ac_tag in
+    *:-:* | *:-) cat >"$tmp/stdin";;
+    esac
+    ;;
+  esac
+
+  ac_dir=`$as_dirname -- "$ac_file" ||
+$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+        X"$ac_file" : 'X\(//\)[^/]' \| \
+        X"$ac_file" : 'X\(//\)$' \| \
+        X"$ac_file" : 'X\(/\)' \| . 2>/dev/null ||
+echo X"$ac_file" |
+    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+           s//\1/
+           q
+         }
+         /^X\(\/\/\)[^/].*/{
+           s//\1/
+           q
+         }
+         /^X\(\/\/\)$/{
+           s//\1/
+           q
+         }
+         /^X\(\/\).*/{
+           s//\1/
+           q
+         }
+         s/.*/./; q'`
+  { as_dir="$ac_dir"
+  case $as_dir in #(
+  -*) as_dir=./$as_dir;;
+  esac
+  test -d "$as_dir" || { $as_mkdir_p && mkdir -p "$as_dir"; } || {
+    as_dirs=
+    while :; do
+      case $as_dir in #(
+      *\'*) as_qdir=`echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #(
+      *) as_qdir=$as_dir;;
+      esac
+      as_dirs="'$as_qdir' $as_dirs"
+      as_dir=`$as_dirname -- "$as_dir" ||
+$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+        X"$as_dir" : 'X\(//\)[^/]' \| \
+        X"$as_dir" : 'X\(//\)$' \| \
+        X"$as_dir" : 'X\(/\)' \| . 2>/dev/null ||
+echo X"$as_dir" |
+    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+           s//\1/
+           q
+         }
+         /^X\(\/\/\)[^/].*/{
+           s//\1/
+           q
+         }
+         /^X\(\/\/\)$/{
+           s//\1/
+           q
+         }
+         /^X\(\/\).*/{
+           s//\1/
+           q
+         }
+         s/.*/./; q'`
+      test -d "$as_dir" && break
+    done
+    test -z "$as_dirs" || eval "mkdir $as_dirs"
+  } || test -d "$as_dir" || { { echo "$as_me:$LINENO: error: cannot create directory $as_dir" >&5
+echo "$as_me: error: cannot create directory $as_dir" >&2;}
+   { (exit 1); exit 1; }; }; }
+  ac_builddir=.
+
+case "$ac_dir" in
+.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
+*)
+  ac_dir_suffix=/`echo "$ac_dir" | sed 's,^\.[\\/],,'`
+  # A ".." for each directory in $ac_dir_suffix.
+  ac_top_builddir_sub=`echo "$ac_dir_suffix" | sed 's,/[^\\/]*,/..,g;s,/,,'`
+  case $ac_top_builddir_sub in
+  "") ac_top_builddir_sub=. ac_top_build_prefix= ;;
+  *)  ac_top_build_prefix=$ac_top_builddir_sub/ ;;
+  esac ;;
+esac
+ac_abs_top_builddir=$ac_pwd
+ac_abs_builddir=$ac_pwd$ac_dir_suffix
+# for backward compatibility:
+ac_top_builddir=$ac_top_build_prefix
+
+case $srcdir in
+  .)  # We are building in place.
+    ac_srcdir=.
+    ac_top_srcdir=$ac_top_builddir_sub
+    ac_abs_top_srcdir=$ac_pwd ;;
+  [\\/]* | ?:[\\/]* )  # Absolute name.
+    ac_srcdir=$srcdir$ac_dir_suffix;
+    ac_top_srcdir=$srcdir
+    ac_abs_top_srcdir=$srcdir ;;
+  *) # Relative name.
+    ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix
+    ac_top_srcdir=$ac_top_build_prefix$srcdir
+    ac_abs_top_srcdir=$ac_pwd/$srcdir ;;
+esac
+ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix
+
+
+  case $ac_mode in
+  :F)
+  #
+  # CONFIG_FILE
+  #
+
+  case $INSTALL in
+  [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;;
+  *) ac_INSTALL=$ac_top_build_prefix$INSTALL ;;
+  esac
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF
+# If the template does not know about datarootdir, expand it.
+# FIXME: This hack should be removed a few years after 2.60.
+ac_datarootdir_hack=; ac_datarootdir_seen=
+
+case `sed -n '/datarootdir/ {
+  p
+  q
+}
+/@datadir@/p
+/@docdir@/p
+/@infodir@/p
+/@localedir@/p
+/@mandir@/p
+' $ac_file_inputs` in
+*datarootdir*) ac_datarootdir_seen=yes;;
+*@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*)
+  { echo "$as_me:$LINENO: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5
+echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;}
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF
+  ac_datarootdir_hack='
+  s&@datadir@&$datadir&g
+  s&@docdir@&$docdir&g
+  s&@infodir@&$infodir&g
+  s&@localedir@&$localedir&g
+  s&@mandir@&$mandir&g
+    s&\\\${datarootdir}&$datarootdir&g' ;;
+esac
+_ACEOF
+
+# Neutralize VPATH when `$srcdir' = `.'.
+# Shell code in configure.ac might set extrasub.
+# FIXME: do we really want to maintain this feature?
+cat >>$CONFIG_STATUS <<_ACEOF
+  sed "$ac_vpsub
+$extrasub
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF
+:t
+/@[a-zA-Z_][a-zA-Z_0-9]*@/!b
+s&@configure_input@&$configure_input&;t t
+s&@top_builddir@&$ac_top_builddir_sub&;t t
+s&@srcdir@&$ac_srcdir&;t t
+s&@abs_srcdir@&$ac_abs_srcdir&;t t
+s&@top_srcdir@&$ac_top_srcdir&;t t
+s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t
+s&@builddir@&$ac_builddir&;t t
+s&@abs_builddir@&$ac_abs_builddir&;t t
+s&@abs_top_builddir@&$ac_abs_top_builddir&;t t
+s&@INSTALL@&$ac_INSTALL&;t t
+$ac_datarootdir_hack
+" $ac_file_inputs | sed -f "$tmp/subs-1.sed" >$tmp/out
+
+test -z "$ac_datarootdir_hack$ac_datarootdir_seen" &&
+  { ac_out=`sed -n '/\${datarootdir}/p' "$tmp/out"`; test -n "$ac_out"; } &&
+  { ac_out=`sed -n '/^[         ]*datarootdir[  ]*:*=/p' "$tmp/out"`; test -z "$ac_out"; } &&
+  { echo "$as_me:$LINENO: WARNING: $ac_file contains a reference to the variable \`datarootdir'
+which seems to be undefined.  Please make sure it is defined." >&5
+echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir'
+which seems to be undefined.  Please make sure it is defined." >&2;}
+
+  rm -f "$tmp/stdin"
+  case $ac_file in
+  -) cat "$tmp/out"; rm -f "$tmp/out";;
+  *) rm -f "$ac_file"; mv "$tmp/out" $ac_file;;
+  esac
+ ;;
+  :H)
+  #
+  # CONFIG_HEADER
+  #
+_ACEOF
+
+# Transform confdefs.h into a sed script `conftest.defines', that
+# substitutes the proper values into config.h.in to produce config.h.
+rm -f conftest.defines conftest.tail
+# First, append a space to every undef/define line, to ease matching.
+echo 's/$/ /' >conftest.defines
+# Then, protect against being on the right side of a sed subst, or in
+# an unquoted here document, in config.status.  If some macros were
+# called several times there might be several #defines for the same
+# symbol, which is useless.  But do not sort them, since the last
+# AC_DEFINE must be honored.
+ac_word_re=[_$as_cr_Letters][_$as_cr_alnum]*
+# These sed commands are passed to sed as "A NAME B PARAMS C VALUE D", where
+# NAME is the cpp macro being defined, VALUE is the value it is being given.
+# PARAMS is the parameter list in the macro definition--in most cases, it's
+# just an empty string.
+ac_dA='s,^\\([  #]*\\)[^        ]*\\([  ]*'
+ac_dB='\\)[     (].*,\\1define\\2'
+ac_dC=' '
+ac_dD=' ,'
+
+uniq confdefs.h |
+  sed -n '
+       t rset
+       :rset
+       s/^[     ]*#[    ]*define[       ][      ]*//
+       t ok
+       d
+       :ok
+       s/[\\&,]/\\&/g
+       s/^\('"$ac_word_re"'\)\(([^()]*)\)[      ]*\(.*\)/ '"$ac_dA"'\1'"$ac_dB"'\2'"${ac_dC}"'\3'"$ac_dD"'/p
+       s/^\('"$ac_word_re"'\)[  ]*\(.*\)/'"$ac_dA"'\1'"$ac_dB$ac_dC"'\2'"$ac_dD"'/p
+  ' >>conftest.defines
+
+# Remove the space that was appended to ease matching.
+# Then replace #undef with comments.  This is necessary, for
+# example, in the case of _POSIX_SOURCE, which is predefined and required
+# on some systems where configure will not decide to define it.
+# (The regexp can be short, since the line contains either #define or #undef.)
+echo 's/ $//
+s,^[    #]*u.*,/* & */,' >>conftest.defines
+
+# Break up conftest.defines:
+ac_max_sed_lines=50
+
+# First sed command is:         sed -f defines.sed $ac_file_inputs >"$tmp/out1"
+# Second one is:        sed -f defines.sed "$tmp/out1" >"$tmp/out2"
+# Third one will be:    sed -f defines.sed "$tmp/out2" >"$tmp/out1"
+# et cetera.
+ac_in='$ac_file_inputs'
+ac_out='"$tmp/out1"'
+ac_nxt='"$tmp/out2"'
+
+while :
+do
+  # Write a here document:
+    cat >>$CONFIG_STATUS <<_ACEOF
+    # First, check the format of the line:
+    cat >"\$tmp/defines.sed" <<\\CEOF
+/^[     ]*#[    ]*undef[        ][      ]*$ac_word_re[  ]*\$/b def
+/^[     ]*#[    ]*define[       ][      ]*$ac_word_re[(         ]/b def
+b
+:def
+_ACEOF
+  sed ${ac_max_sed_lines}q conftest.defines >>$CONFIG_STATUS
+  echo 'CEOF
+    sed -f "$tmp/defines.sed"' "$ac_in >$ac_out" >>$CONFIG_STATUS
+  ac_in=$ac_out; ac_out=$ac_nxt; ac_nxt=$ac_in
+  sed 1,${ac_max_sed_lines}d conftest.defines >conftest.tail
+  grep . conftest.tail >/dev/null || break
+  rm -f conftest.defines
+  mv conftest.tail conftest.defines
+done
+rm -f conftest.defines conftest.tail
+
+echo "ac_result=$ac_in" >>$CONFIG_STATUS
+cat >>$CONFIG_STATUS <<\_ACEOF
+  if test x"$ac_file" != x-; then
+    echo "/* $configure_input  */" >"$tmp/config.h"
+    cat "$ac_result" >>"$tmp/config.h"
+    if diff $ac_file "$tmp/config.h" >/dev/null 2>&1; then
+      { echo "$as_me:$LINENO: $ac_file is unchanged" >&5
+echo "$as_me: $ac_file is unchanged" >&6;}
+    else
+      rm -f $ac_file
+      mv "$tmp/config.h" $ac_file
+    fi
+  else
+    echo "/* $configure_input  */"
+    cat "$ac_result"
+  fi
+  rm -f "$tmp/out12"
+ ;;
+
+  :C)  { echo "$as_me:$LINENO: executing $ac_file commands" >&5
+echo "$as_me: executing $ac_file commands" >&6;}
+ ;;
+  esac
+
+
+  case $ac_file$ac_mode in
+    "default":C) echo timestamp > stamp-h ;;
+
+  esac
+done # for ac_tag
+
+
+{ (exit 0); exit 0; }
+_ACEOF
+chmod +x $CONFIG_STATUS
+ac_clean_files=$ac_clean_files_save
+
+
+# configure is writing to config.log, and then calls config.status.
+# config.status does its own redirection, appending to config.log.
+# Unfortunately, on DOS this fails, as config.log is still kept open
+# by configure, so config.status won't be able to write to it; its
+# output is simply discarded.  So we exec the FD to /dev/null,
+# effectively closing config.log, so it can be properly (re)opened and
+# appended to by config.status.  When coming back to configure, we
+# need to make the FD available again.
+if test "$no_create" != yes; then
+  ac_cs_success=:
+  ac_config_status_args=
+  test "$silent" = yes &&
+    ac_config_status_args="$ac_config_status_args --quiet"
+  exec 5>/dev/null
+  $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false
+  exec 5>>config.log
+  # Use ||, not &&, to avoid exiting from the if with $? = 1, which
+  # would make configure fail if this is the last instruction.
+  $ac_cs_success || { (exit 1); exit 1; }
+fi
+
+
+{ echo "$as_me:$LINENO: result:
+ircu is now hopefully configured for your system.
+
+  Host system:         $host_os
+  Prefix:              $prefix
+  Asserts:             $unet_cv_enable_asserts
+  Warnings:            $unet_cv_enable_warnings
+  Debug:               $unet_cv_enable_debug
+  Profile:             $unet_cv_enable_profile
+  Owner/mode:          $unet_cv_with_owner.$unet_cv_with_group ($unet_cv_with_mode)
+  Chroot:              $unet_cv_with_chroot
+  OpenSSL:             $unet_cv_enable_openssl
+  GnuTLS:              $unet_cv_enable_gnutls
+  Compatibility mode:  $unet_cv_enable_compat
+  Unstable features:   $unet_cv_enable_unstable
+
+  Domain:              $unet_cv_with_domain
+  DPath:               $unet_cv_with_dpath
+  CPath:               $unet_cv_with_cpath
+  LPath:               $unet_cv_with_lpath
+  Maximum connections: $unet_cv_with_maxcon
+
+  poll() engine:       $unet_cv_enable_poll
+  kqueue() engine:     $unet_cv_enable_kqueue
+  /dev/poll engine:    $unet_cv_enable_devpoll
+  epoll() engine:      $unet_cv_enable_epoll
+" >&5
+echo "${ECHO_T}
+ircu is now hopefully configured for your system.
+
+  Host system:         $host_os
+  Prefix:              $prefix
+  Asserts:             $unet_cv_enable_asserts
+  Warnings:            $unet_cv_enable_warnings
+  Debug:               $unet_cv_enable_debug
+  Profile:             $unet_cv_enable_profile
+  Owner/mode:          $unet_cv_with_owner.$unet_cv_with_group ($unet_cv_with_mode)
+  Chroot:              $unet_cv_with_chroot
+  OpenSSL:             $unet_cv_enable_openssl
+  GnuTLS:              $unet_cv_enable_gnutls
+  Compatibility mode:  $unet_cv_enable_compat
+  Unstable features:   $unet_cv_enable_unstable
+
+  Domain:              $unet_cv_with_domain
+  DPath:               $unet_cv_with_dpath
+  CPath:               $unet_cv_with_cpath
+  LPath:               $unet_cv_with_lpath
+  Maximum connections: $unet_cv_with_maxcon
+
+  poll() engine:       $unet_cv_enable_poll
+  kqueue() engine:     $unet_cv_enable_kqueue
+  /dev/poll engine:    $unet_cv_enable_devpoll
+  epoll() engine:      $unet_cv_enable_epoll
+" >&6; }
diff --git a/configure.in b/configure.in
new file mode 100644 (file)
index 0000000..d3c75a3
--- /dev/null
@@ -0,0 +1,824 @@
+dnl Prefered emacs editing mode: -*- shell-script -*-
+dnl
+dnl Process this file with autoconf to produce a configure script.
+dnl
+dnl Copyright (c) 1997, by Carlo Wood <carlo@runaway.xs4all.nl>
+dnl Copyright (C) 2001  Kevin L. Mitchell <klmitch@mit.edu>
+dnl
+dnl This program is free software; you can redistribute it and/or modify
+dnl it under the terms of the GNU General Public License as published by
+dnl the Free Software Foundation; either version 1, or (at your option)
+dnl any later version.
+dnl
+dnl This program is distributed in the hope that it will be useful,
+dnl but WITHOUT ANY WARRANTY; without even the implied warranty of
+dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+dnl GNU General Public License for more details.
+dnl
+dnl You should have received a copy of the GNU General Public License
+dnl along with this program; if not, write to the Free Software
+dnl Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+dnl
+dnl $Id$
+
+dnl Make sure we are in the correct directory (someone could have run
+dnl 'configure' with a wrong '--srcdir').
+AC_INIT(ircd/ircd.c)
+
+dnl Set the default prefix
+AC_PREFIX_DEFAULT([$HOME])
+AC_MSG_CHECKING([for installation prefix])
+AC_CACHE_VAL(unet_cv_prefix, [unet_cv_prefix=$HOME])
+if test x"$prefix" != xNONE; then
+    unet_cv_prefix=$prefix
+fi
+AC_MSG_RESULT([$unet_cv_prefix])
+dnl HACK WARNING: We are referencing an autoconf internal variable.  This is
+dnl the only way to force the prefix to be retrieved from the config.cache
+dnl file!
+ac_default_prefix=$unet_cv_prefix
+
+dnl Define the input and output configuration header file.
+AC_CONFIG_HEADER([config.h])
+
+dnl Demand at least version 2.59 of autoconf (for AS_HELP_STRING)
+AC_PREREQ(2.59)
+
+dnl Find out what type of system we are
+AC_CANONICAL_HOST
+
+dnl This should be done early.
+AC_PROG_CC
+
+dnl ANSIfy the C compiler whenever possible.
+AM_PROG_CC_STDC
+
+dnl Checks for libraries.
+
+dnl Locate the library containing crypt
+AC_SEARCH_LIBS(crypt, descrypt crypt, ,
+[AC_MSG_ERROR([Unable to find library containing crypt()])])
+
+dnl Do all the checks necessary to figure out -lnsl / -lsocket stuff
+AC_LIBRARY_NET
+
+dnl Checks for header files.
+AC_HEADER_STDC
+AC_CHECK_HEADERS(crypt.h poll.h inttypes.h stdint.h sys/devpoll.h sys/epoll.h sys/event.h sys/param.h sys/resource.h sys/socket.h)
+
+dnl Checks for typedefs, structures, and compiler characteristics
+dnl AC_C_CONST
+AC_C_BIGENDIAN
+AC_TYPE_SIZE_T
+AC_HEADER_TIME
+AC_STRUCT_TM
+AC_TYPE_UID_T
+unet_CHECK_TYPE_SIZES
+AC_CHECK_TYPE(struct sockaddr_in6, [unet_have_sockaddr_in6="yes"], [unet_have_sockaddr_in6="no"], [#include <sys/types.h>
+#include <netinet/in.h>])
+
+dnl Check for socklen_t.  In traditional BSD this is an int, but some
+dnl OSes use a different type.  Test until we find something that will
+dnl work properly.  Test borrowed from a patch submitted for Python.
+AC_CHECK_TYPE([socklen_t], ,[
+  AC_MSG_CHECKING([for socklen_t equivalent])
+  AC_CACHE_VAL([curl_cv_socklen_t_equiv],
+  [
+dnl Systems have either "struct sockaddr*" or "void*" as second
+dnl arg to getpeername.
+    curl_cv_socklen_t_equiv=
+    for arg2 in "struct sockaddr" void ; do
+      for t in int size_t unsigned long "unsigned long" ; do
+        AC_TRY_COMPILE([#include <sys/types.h>
+#include <sys/socket.h>
+int getpeername (int $arg2 *, $t *);],[$t len;
+  getpeername(0, 0, &len);], [curl_cv_socklen_t_equiv="$t"
+  break])
+      done
+    done
+  ])
+  AC_MSG_RESULT($curl_cv_socklen_t_equiv)
+  AC_DEFINE_UNQUOTED(socklen_t, $curl_cv_socklen_t_equiv,
+      [type to use in place of socklen_t if not defined])],
+  [#include <sys/types.h>
+#include<sys/socket.h>])
+
+dnl Checks for library functions.
+AC_CHECK_FUNCS([kqueue setrlimit getrusage times])
+
+dnl Check for required features for admins?
+AC_MSG_CHECKING([for donuts])
+AC_MSG_RESULT([yes])
+
+dnl Test for programs
+AC_PROG_AWK
+AC_PROG_MAKE_SET
+AC_PROG_INSTALL
+AC_PROG_LN_S
+AC_PATH_PROGS(RMPROG, rm, /bin/rm)
+AC_PATH_PROGS(SHPROG, sh, /bin/sh)
+
+dnl (F)LEX - needed for the new conf file parser
+AC_PROG_LEX
+dnl The autoconf docs say $LEX defaults to 'lex'.  They lie.
+if test "$LEX" = ":" ; then
+  AC_MSG_ERROR([Cannot find flex.])
+elif echo "" | $LEX -V -v --version > /dev/null 2>&1 ; then
+  :
+else
+  AC_MSG_ERROR([Cannot use $LEX as flex.])
+fi
+
+dnl YACC - ditto
+AC_PROG_YACC
+dnl The autoconf docs say $YACC defaults to 'yacc'.  This seems to be true,
+dnl but judging from AC_PROG_LEX, it may not stay true.
+if test "$YACC" = ":" ; then
+  AC_MSG_ERROR([Cannot find yacc.])
+elif echo "" | $YACC -V -v --version > /dev/null 2>&1 ; then
+  :
+else
+dnl byacc does not seem to have any way to test for workingness, so only warn.
+  AC_MSG_WARN([$YACC may not work as yacc.])
+fi
+
+unet_NONBLOCKING
+unet_SIGNALS
+
+dnl Check OS for os_dep files.
+AC_MSG_CHECKING(for OS-dependent information)
+case "$host" in
+    *-linux*)
+       AC_MSG_RESULT([Linux ($host) found.])
+       unet_poll_syscall=yes
+       ;;
+
+    *-solaris*)
+       AC_MSG_RESULT([Solaris ($host) found.])
+       if test x"$ac_cv_header_poll_h" = xyes; then
+           unet_poll_syscall=yes
+       else
+           unet_poll_syscall=no
+       fi
+        AC_DEFINE([IRCU_SOLARIS], 1, [Define if building on Solaris])
+       ;;
+
+    *-sunos*)
+       AC_MSG_RESULT([Solaris ($host) found.])
+       unet_poll_syscall=no
+       ;;
+
+    *-openbsd*)
+       AC_MSG_RESULT([OpenBSD ($host) found.])
+       if test x"$ac_cv_header_poll_h" = xyes; then
+           unet_poll_syscall=yes
+       else
+           unet_poll_syscall=no
+       fi
+       ;;
+
+    *-*bsd*)
+       AC_MSG_RESULT([Generic BSD ($host) found.])
+       if test x"$ac_cv_header_poll_h" = xyes; then
+           unet_poll_syscall=yes
+       else
+           unet_poll_syscall=no
+       fi
+       ;;
+
+    *-darwin*)
+       AC_MSG_RESULT([Darwin (Mac OS X) ($host) found.])
+       unet_poll_syscall=no
+       AC_DEFINE([_DARWIN_C_SOURCE], 1, [Define to enable POSIX compatibility on Darwin.])
+       ;;
+
+    *)
+       AC_MSG_RESULT([Unknown system type $host found.])
+       AC_MSG_WARN([Unknown OS type; using generic routines.])
+       unet_poll_syscall=no
+       ;;
+esac
+
+dnl Check user configuration options
+dnl Start with --enable-poll
+AC_MSG_CHECKING([whether to enable use of poll()])
+AC_ARG_ENABLE([poll],
+[  --enable-poll           Force poll to be used regardless of whether or not
+                          it is a system call],
+[unet_cv_enable_poll=$enable_poll],
+[AC_CACHE_VAL(unet_cv_enable_poll,
+[unet_cv_enable_poll=$unet_poll_syscall])])
+
+# Force poll to be disabled if there is no poll.h
+if test x"$ac_cv_header_poll_h" != xyes; then
+    unet_cv_enable_poll=no
+fi
+
+AC_MSG_RESULT([$unet_cv_enable_poll])
+
+if test x"$unet_cv_enable_poll" = xyes; then
+    AC_DEFINE([USE_POLL], 1, [Specify whether or not to use poll()])
+    ENGINE_C=engine_poll.c
+else
+    ENGINE_C=engine_select.c
+fi
+AC_SUBST(ENGINE_C)
+
+dnl Now look for --enable-debug
+AC_MSG_CHECKING([whether to enable debug mode])
+AC_ARG_ENABLE([debug],
+[  --enable-debug          Turn on debugging mode],
+[unet_cv_enable_debug=$enable_debug],
+[AC_CACHE_VAL(unet_cv_enable_debug,
+[unet_cv_enable_debug=no])])
+AC_MSG_RESULT([$unet_cv_enable_debug])
+
+if test x"$unet_cv_enable_debug" = xyes; then
+    AC_DEFINE([DEBUGMODE], 1, [Enable debugging code])
+    CFLAGS="$CFLAGS -O0 -g"
+fi
+
+dnl Now look for --enable-leak-detect
+AC_MSG_CHECKING([whether to enable leak detection])
+AC_ARG_WITH([leak-detect],
+[  --with-leak-detect          Turn on the leak detector(requires patched boehm)],
+[unet_cv_with_leak_detect=$with_leak_detect],
+[AC_CACHE_VAL(unet_cv_with_leak_detect,
+[unet_cv_with_leak_detect=no])])
+AC_MSG_RESULT([$unet_cv_enable_leak_detect])
+
+if test x"$unet_cv_with_leak_detect" != xno; then
+    LIBS="-lgc $LIBS"
+    CFLAGS="-DMDEBUG $CFLAGS"
+    if test x"$unet_cv_with_leak_detect" != xyes; then
+       LIBS="-L$unet_cv_with_leak_detect $LIBS"
+    fi
+fi
+
+AC_ARG_WITH([ipv6],
+    AS_HELP_STRING([--without-ipv6], [disable IPv6 support (default is autodetect)]),
+    [ac_cv_use_ipv6=$withval],
+    [ac_cv_use_ipv6=$unet_have_sockaddr_in6])
+AC_CACHE_CHECK([whether to use IPv6], [ac_cv_use_ipv6], [ac_cv_use_ipv6=no])
+if test x"$ac_cv_use_ipv6" != "xno" ; then
+    AC_DEFINE([IPV6], 1, [Enable IPv6 support])
+fi
+
+dnl And now for --disable-asserts
+AC_MSG_CHECKING([whether to enable asserts])
+AC_ARG_ENABLE([asserts],
+[  --disable-asserts       Disable assertion checking],
+[unet_cv_enable_asserts=$enable_asserts],
+[AC_CACHE_VAL(unet_cv_enable_asserts,
+[unet_cv_enable_asserts=yes])])
+AC_MSG_RESULT([$unet_cv_enable_asserts])
+
+if test x"$unet_cv_enable_asserts" = xno; then
+    AC_DEFINE([NDEBUG], 1, [Disable assertions])
+fi
+
+dnl Now check for --enable-profile
+AC_MSG_CHECKING([whether to enable profiling support (gprof)])
+AC_ARG_ENABLE([profile],
+[  --enable-profile        Enable profiling support (add -pg to CFLAGS and LDFLAGS)],
+[unet_cv_enable_profile=$enable_profile],
+[AC_CACHE_VAL(unet_cv_enable_profile,
+[unet_cv_enable_profile=no])])
+AC_MSG_RESULT([$unet_cv_enable_profile])
+
+if test x"$unet_cv_enable_profile" = xyes; then
+    CFLAGS="-pg $CFLAGS"
+    LDFLAGS="-pg $LDFLAGS"
+fi
+
+dnl Now check for --enable-pedantic
+AC_MSG_CHECKING([whether to enable pedantic compiler warnings])
+AC_ARG_ENABLE([pedantic],
+[  --enable-pedantic       Enable pedantic warnings (add -pedantic to CFLAGS)],
+[unet_cv_enable_pedantic=$enable_pedantic],
+[AC_CACHE_VAL(unet_cv_enable_pedantic,
+[unet_cv_enable_pedantic=no])])
+AC_MSG_RESULT([$unet_cv_enable_pedantic])
+
+if test x"$unet_cv_enable_pedantic" = xyes; then
+    CFLAGS="-pedantic $CFLAGS"
+fi
+
+dnl Now check for --enable-warnings
+AC_MSG_CHECKING([whether to enable compiler warnings])
+AC_ARG_ENABLE([warnings],
+[  --enable-warnings       Enable warnings (add -Wall to CFLAGS)],
+[unet_cv_enable_warnings=$enable_warnings],
+[AC_CACHE_VAL(unet_cv_enable_warnings,
+[unet_cv_enable_warnings=no])])
+AC_MSG_RESULT([$unet_cv_enable_warnings])
+
+if test x"$unet_cv_enable_warnings" = xyes; then
+    CFLAGS="-Wall $CFLAGS"
+fi
+
+dnl --disable-inlines check...
+AC_MSG_CHECKING([whether to enable inlining for a few critical functions])
+AC_ARG_ENABLE([inlines],
+[  --disable-inlines       Disable inlining for a few critical functions],
+[unet_cv_enable_inlines=$enable_inlines],
+[AC_CACHE_VAL(unet_cv_enable_inlines,
+[unet_cv_enable_inlines=yes])])
+AC_MSG_RESULT([$unet_cv_enable_inlines])
+
+if test x"$unet_cv_enable_inlines" = xyes; then
+    AC_DEFINE([FORCEINLINE], 1, [Force inlining for a few critical functions])
+fi
+
+dnl --disable-devpoll check...
+AC_MSG_CHECKING([whether to enable the /dev/poll event engine])
+AC_ARG_ENABLE([devpoll],
+[  --disable-devpoll       Disable the /dev/poll-based engine],
+[unet_cv_enable_devpoll=$enable_devpoll],
+[AC_CACHE_VAL(unet_cv_enable_devpoll,
+[unet_cv_enable_devpoll=yes])])
+
+if test x"$ac_cv_header_sys_devpoll_h" = xno; then
+    unet_cv_enable_devpoll=no
+fi
+
+AC_MSG_RESULT([$unet_cv_enable_devpoll])
+
+if test x"$unet_cv_enable_devpoll" != xno; then
+    AC_DEFINE([USE_DEVPOLL], 1, [Define to enable the /dev/poll engine])
+    ENGINE_C="engine_devpoll.c $ENGINE_C"
+fi
+
+dnl --disable-kqueue check...
+AC_MSG_CHECKING([whether to enable the kqueue event engine])
+AC_ARG_ENABLE([kqueue],
+[  --disable-kqueue        Disable the kqueue-based engine],
+[unet_cv_enable_kqueue=$enable_kqueue],
+[AC_CACHE_VAL(unet_cv_enable_kqueue,
+[unet_cv_enable_kqueue=yes])])
+
+if test x"$ac_cv_header_sys_event_h" = xno -o x"$ac_cv_func_kqueue" = xno; then
+    unet_cv_enable_kqueue=no
+fi
+
+AC_MSG_RESULT([$unet_cv_enable_kqueue])
+
+if test x"$unet_cv_enable_kqueue" != xno; then
+    AC_DEFINE([USE_KQUEUE], 1, [Define to enable the kqueue engine])
+    ENGINE_C="engine_kqueue.c $ENGINE_C"
+fi
+
+dnl --disable-epoll check
+AC_MSG_CHECKING([whether to enable the epoll event engine])
+AC_ARG_ENABLE([epoll],
+[  --disable-epoll         Disable the epoll-based engine],
+[unet_cv_enable_epoll=$enable_epoll],
+[AC_CACHE_VAL(unet_cv_enable_epoll,
+[unet_cv_enable_epoll=yes])])
+
+if test x"$ac_cv_header_sys_epoll_h" = xno -o x"$ac_cv_func_epoll" = xno; then
+    unet_cv_enable_epoll=no
+fi
+
+AC_MSG_RESULT([$unet_cv_enable_epoll])
+
+dnl If we have the header and user has not refused epoll, we still need
+dnl to check whether the functions are properly defined.
+if test x"$unet_cv_enable_epoll" != xno; then
+    AC_MSG_CHECKING([whether epoll functions are properly defined])
+    AC_LINK_IFELSE([AC_LANG_PROGRAM([#include <sys/epoll.h>], [epoll_create(10);])],
+        [AC_MSG_RESULT([yes])],
+        [AC_MSG_RESULT([no])
+         AC_DEFINE([EPOLL_NEED_BODY], 1, [Define to implement epoll system calls])])
+    AC_DEFINE([USE_EPOLL], 1, [Define to enable the epoll engine])
+    ENGINE_C="engine_epoll.c $ENGINE_C"
+fi
+
+dnl How to copy one va_list to another?
+AC_CACHE_CHECK([for va_copy], unet_cv_c_va_copy, [AC_LINK_IFELSE(
+  [AC_LANG_PROGRAM([#include <stdarg.h>], [va_list ap1, ap2; va_copy(ap1, ap2);])],
+  [unet_cv_c_va_copy="yes"],
+  [unet_cv_c_va_copy="no"]
+)])
+if test "$unet_cv_c_va_copy" = "yes" ; then
+  AC_DEFINE(HAVE_VA_COPY, 1, [Define if we have va_copy])
+fi
+
+AC_CACHE_CHECK([for __va_copy], unet_cv_c___va_copy, [AC_LINK_IFELSE(
+  [AC_LANG_PROGRAM([#include <stdarg.h>], [va_list ap1, ap2; __va_copy(ap1, ap2);])],
+  [unet_cv_c___va_copy="yes"],
+  [unet_cv_c___va_copy="no"]
+)])
+if test "$unet_cv_c___va_copy" = "yes" ; then
+  AC_DEFINE(HAVE___VA_COPY, 1, [Define if we have __va_copy])
+fi
+
+dnl --with-symlink lets us set the name of the symlink; defaults to "ircd"
+AC_MSG_CHECKING([what name to give the symlink])
+AC_ARG_WITH([symlink],
+[  --with-symlink=name     Name to give the symlink; if name is "no," no
+                          symlink will be created.],
+[unet_cv_with_symlink=$with_symlink],
+[AC_CACHE_VAL(unet_cv_with_symlink,
+[unet_cv_with_symlink="ircd"])])
+
+if test x"$unet_cv_with_symlink" = xyes; then
+    unet_cv_with_symlink="ircd"
+fi
+
+AC_MSG_RESULT([$unet_cv_with_symlink])
+
+if test x"$unet_cv_with_symlink" = xno; then
+    INSTALL_RULE=install-no-symlink
+    SYMLINK=
+else
+    INSTALL_RULE=install-with-symlink
+    SYMLINK=$unet_cv_with_symlink
+fi
+AC_SUBST(INSTALL_RULE)
+AC_SUBST(SYMLINK)
+
+dnl --with-mode lets us set the permissions on the binary
+AC_MSG_CHECKING([what permissions to set on the installed binary])
+AC_ARG_WITH([mode],
+[  --with-mode=mode        Permissions (in octal) to give the binary],
+[unet_cv_with_mode=$with_mode],
+[AC_CACHE_VAL(unet_cv_with_mode,
+[unet_cv_with_mode=711])])
+
+if test x"$unet_cv_with_mode" = xyes -o x"$unet_cv_with_mode" = xno; then
+    unet_cv_with_mode=711
+fi
+
+AC_MSG_RESULT([$unet_cv_with_mode])
+
+IRCDMODE=$unet_cv_with_mode
+AC_SUBST(IRCDMODE)
+
+dnl --with-owner lets us set the owner of the binary
+changequote(,)dnl
+unet_uid=`id | sed -e 's/.*uid=[0-9]*(//' -e 's/).*//' 2> /dev/null`
+changequote([,])dnl
+AC_MSG_CHECKING([which user should own the installed binary])
+AC_ARG_WITH([owner],
+[  --with-owner=owner      Specify owner of the installed binary],
+[unet_cv_with_owner=$with_owner],
+[AC_CACHE_VAL(unet_cv_with_owner,
+[unet_cv_with_owner=$unet_uid])])
+
+if test x"$unet_cv_with_owner" = xyes -o x"$unet_cv_with_owner" = xno; then
+    unet_cv_with_owner=$unet_uid
+fi
+
+AC_MSG_RESULT([$unet_cv_with_owner])
+
+IRCDOWN=$unet_cv_with_owner
+AC_SUBST(IRCDOWN)
+
+dnl --with-group lets us set the group owner of the binary
+changequote(,)dnl
+unet_gid=`id | sed -e 's/.*gid=[0-9]*(//' -e 's/).*//' 2> /dev/null`
+changequote([,])dnl
+AC_MSG_CHECKING([which group should own the installed binary])
+AC_ARG_WITH([group],
+[  --with-group=group      Specify group owner of the installed binary],
+[unet_cv_with_group=$with_group],
+[AC_CACHE_VAL(unet_cv_with_group,
+[unet_cv_with_group=$unet_gid])])
+
+if test x"$unet_cv_with_group" = xyes -o x"$unet_cv_with_group" = xno; then
+    unet_cv_with_group=$unet_gid
+fi
+
+AC_MSG_RESULT([$unet_cv_with_group])
+
+IRCDGRP=$unet_cv_with_group
+AC_SUBST(IRCDGRP)
+
+dnl --with-domain lets us set the domain name for some statistics-gathering
+unet_domain=
+if test -f /etc/resolv.conf; then
+    unet_domain=`awk '/^domain/ { print $2; exit }' /etc/resolv.conf`
+    if test x"$unet_domain" = x; then
+       unet_domain=`awk '/^search/ { print $2; exit }' /etc/resolv.conf`
+    fi
+fi
+AC_MSG_CHECKING([for site domain name])
+AC_ARG_WITH([domain],
+[  --with-domain=domain    Domain name to use in local statistics gathering],
+[unet_cv_with_domain=$with_domain],
+[AC_CACHE_VAL(unet_cv_with_domain,
+[unet_cv_with_domain=$unet_domain])])
+
+if test x"$unet_cv_with_domain" = xyes -o x"$unet_cv_with_domain" = xno; then
+    unet_cv_with_domain=$unet_domain
+fi
+if test x"$unet_cv_with_domain" = xno; then
+    AC_MSG_ERROR([Unable to determine server DNS domain; use --with-domain to set it])
+fi
+
+AC_MSG_RESULT([$unet_cv_with_domain])
+
+AC_DEFINE_UNQUOTED(DOMAINNAME, "*$unet_cv_with_domain",
+[Domain name to be used for some statistics gathering])
+
+dnl --with-chroot lets us define a directory that we are going to be using
+dnl as the root of our filesystem
+AC_MSG_CHECKING([if chroot operation is desired])
+AC_ARG_WITH([chroot],
+[  --with-chroot=dir       Specify that the server will be operated under
+                          a different root directory given by dir.  See
+                          doc/readme.chroot for more information.],
+[unet_cv_with_chroot=$with_chroot],
+[AC_CACHE_VAL(unet_cv_with_chroot,
+[unet_cv_with_chroot=no])])
+
+if test x"$unet_cv_with_chroot" = xyes; then
+    AC_MSG_ERROR([--with-chroot given with no directory.  See doc/readme.chroot.])
+fi
+
+# Ensure there are no trailing /'s to mess us up
+unet_cv_with_chroot=`echo "$unet_cv_with_chroot" | sed 's%/*$%%'`
+
+AC_MSG_RESULT([$unet_cv_with_chroot])
+
+dnl Determine some default directory names
+dnl
+dnl HACK WARNING: We are referencing an autoconf internal variable.  This is
+dnl the only way to figure out what value $prefix will have when we go to do
+dnl the install--and the only way we can stick that value in our definitions
+dnl of SPATH, etc.
+# Deal with the annoying value "NONE" here
+unet_save_prefix=$prefix
+if test x"$prefix" = xNONE; then
+    prefix=$ac_default_prefix
+else
+    prefix=$prefix
+fi
+
+unet_save_exec_prefix=$exec_prefix
+if test x"$exec_prefix" = xNONE; then
+    exec_prefix=$prefix
+else
+    exec_prefix=$exec_prefix
+fi
+
+# Obtain the actual interesting directories
+unet_bindir=`eval echo "$bindir"`
+unet_libdir=`eval echo "$libdir"`
+
+# Restore the original settings of $prefix and $exec_prefix
+prefix=$unet_save_prefix
+exec_prefix=$unet_save_exec_prefix
+
+dnl Now compute the name of the binary and verify that it will work under
+dnl chroot operation
+AC_MSG_CHECKING([where the binary will be for /restart])
+if test x"$unet_cv_with_symlink" = xno; then
+    unet_spath="$unet_bindir/ircd"
+else
+    unet_spath="$unet_bindir/$unet_cv_with_symlink"
+fi
+AC_MSG_RESULT([$unet_spath])
+
+if test x"$unet_cv_with_chroot" != xno; then
+    if echo "$unet_spath" | grep "^$unet_cv_with_chroot" > /dev/null 2>&1; then
+       unet_spath=`echo "$unet_spath" | sed "s%^$unet_cv_with_chroot%%"`
+    else
+       AC_MSG_WARN([Binary $unet_spath not relative to root directory $unet_cv_with_chroot; restarts will probably fail])
+    fi
+fi
+
+AC_DEFINE_UNQUOTED(SPATH, "$unet_spath", [Path to executable for restarts])
+
+dnl --with-dpath sets the all-important DPATH
+AC_MSG_CHECKING([what the data directory should be])
+AC_ARG_WITH([dpath],
+[  --with-dpath=dir        Directory for all server data files],
+[unet_cv_with_dpath=$with_dpath],
+[AC_CACHE_VAL(unet_cv_with_dpath,
+[unet_cv_with_dpath=$unet_libdir])])
+
+if test x"$unet_cv_with_dpath" = xyes -o x"$unet_cv_with_dpath" = xno; then
+    unet_cv_with_dpath=$unet_libdir
+fi
+
+# Ensure there are no trailing /'s to mess us up
+unet_cv_with_dpath=`echo "$unet_cv_with_dpath" | sed 's%/*$%%'`
+
+AC_MSG_RESULT([$unet_cv_with_dpath])
+
+if test x"$unet_cv_with_chroot" != xno; then
+    if echo "$unet_cv_with_dpath" | grep "^$unet_cv_with_chroot" > /dev/null 2>&1; then
+       unet_dpath=`echo "$unet_cv_with_dpath" | sed "s%^$unet_cv_with_chroot%%"`
+    else
+       AC_MSG_ERROR([Data directory $unet_cv_with_dpath not relative to root directory $unet_cv_with_chroot])
+    fi
+else
+    unet_dpath=$unet_cv_with_dpath
+fi
+
+AC_DEFINE_UNQUOTED(DPATH, "$unet_dpath", [Path to data directory])
+
+DPATH=$unet_cv_with_dpath
+AC_SUBST(DPATH)
+
+dnl --with-cpath allows us to specify the configuration file
+AC_MSG_CHECKING([where the default configuration file resides])
+AC_ARG_WITH([cpath],
+[  --with-cpath=file       Set server configuration file],
+[unet_cv_with_cpath=$with_cpath],
+[AC_CACHE_VAL(unet_cv_with_cpath,
+[unet_cv_with_cpath="ircd.conf"])])
+
+if test x"$unet_cv_with_cpath" = xyes -o x"$unet_cv_with_cpath" = xno; then
+    unet_cv_with_cpath="ircd.conf"
+fi
+
+AC_MSG_RESULT([$unet_cv_with_cpath])
+
+if echo "$unet_cv_with_cpath" | grep '^/' > /dev/null 2>&1; then
+    # Absolute path; check against chroot stuff
+    if test x"$unet_cv_with_chroot" != xno; then
+       if echo "$unet_cv_with_cpath" | grep "^$unet_cv_with_chroot" > /dev/null 2>&1; then
+           unet_cpath=`echo "$unet_cv_with_cpath" | sed "s%^$unet_cv_with_chroot%%"`
+       else
+           AC_MSG_ERROR([Configuration file $unet_cv_with_cpath not relative to root directory $unet_cv_with_chroot])
+       fi
+    else
+       unet_cpath=$unet_cv_with_cpath
+    fi
+else
+    unet_cpath=$unet_cv_with_cpath
+fi
+
+AC_DEFINE_UNQUOTED(CPATH, "$unet_cpath", [Configuration file name])
+
+dnl --with-lpath allows us to specify the default debugging log file
+AC_MSG_CHECKING([where to put the debugging log if debugging enabled])
+AC_ARG_WITH([lpath],
+[  --with-lpath=file       Set the debugging log file],
+[unet_cv_with_lpath=$with_lpath],
+[AC_CACHE_VAL(unet_cv_with_lpath,
+[unet_cv_with_lpath="ircd.log"])])
+
+if test x"$unet_cv_with_lpath" = xyes -o x"$unet_cv_with_lpath" = xno; then
+    unet_cv_with_lpath="ircd.log"
+fi
+
+AC_MSG_RESULT([$unet_cv_with_lpath])
+
+if echo "$unet_cv_with_lpath" | grep '^/' > /dev/null 2>&1; then
+    # Absolute path; check against chroot stuff
+    if test x"$unet_cv_with_chroot" != xno; then
+       if echo "$unet_cv_with_lpath" | grep "^$unet_cv_with_chroot" > /dev/null 2>&1; then
+           unet_lpath=`echo "$unet_cv_with_lpath" | sed "s%^$unet_cv_with_chroot%%"`
+       else
+           AC_MSG_WARN([Log file $unet_cv_with_lpath not relative to root directory $unet_cv_with_chroot; using default ircd.log instead])
+           unet_cv_with_lpath="ircd.log"
+           unet_lpath="ircd.log"
+       fi
+    else
+       unet_lpath=$unet_cv_with_lpath
+    fi
+else
+    unet_lpath=$unet_cv_with_lpath
+fi
+
+AC_DEFINE_UNQUOTED(LPATH, "$unet_lpath", [Path to debugging log file])
+
+dnl --with-maxcon allows us to set the maximum connections
+unet_maxcon=`ulimit -Hn`
+if test x"$unet_maxcon" = xunlimited; then
+    unet_maxcon=`ulimit -Sn`
+fi
+unet_maxcon=`expr $unet_maxcon - 4`
+AC_MSG_CHECKING([max connections])
+AC_ARG_WITH([maxcon],
+[  --with-maxcon=maxcon    Maximum number of connections server will accept],
+[unet_cv_with_maxcon=$with_maxcon],
+[AC_CACHE_VAL(unet_cv_with_maxcon,
+[unet_cv_with_maxcon=$unet_maxcon])])
+
+if test x"$unet_cv_with_maxcon" = xyes -o x"$unet_cv_with_maxcon" = xno; then
+    if test "$unet_maxcon" -lt 32; then
+      AC_MSG_ERROR([Maximum connections (number of open files minus 4) must be at least 32.])
+    fi
+    unet_cv_with_maxcon=$unet_maxcon
+elif test "$unet_cv_with_maxcon" -lt 32; then
+    AC_MSG_ERROR([Maximum connections (--with-maxcon) must be at least 32.])
+fi
+
+AC_MSG_RESULT([$unet_cv_with_maxcon])
+
+AC_DEFINE_UNQUOTED(MAXCONNECTIONS, $unet_cv_with_maxcon,
+[Maximum number of network connections])
+
+dnl Old OGN ircu compatibility checks.
+unet_cv_enable_compat="yes"
+AC_MSG_CHECKING([whether to enable OGN-compat mode])
+AC_ARG_ENABLE([compat],
+  [  --enable-compat          Enables OGN-compat mode.],
+  [unet_cv_enable_compat=$enable_compat],
+)
+AC_MSG_RESULT([$unet_cv_enable_compat])
+
+if test $unet_cv_enable_compat = "no" ; then
+    # do nothing
+    unet_cv_enable_compat="no"
+else
+    AC_DEFINE([OLD_OGN_IRCU_COMPAT], 1, [Enable compatibility mode.])
+fi
+
+dnl Check whether to enable unstable features.
+unet_cv_enable_unstable="no"
+AC_MSG_CHECKING([whether to enable unstable features])
+AC_ARG_ENABLE([unstable],
+  [  --enable-unstable          Enables unstable features.],
+  [unet_cv_enable_unstable=$enable_unstable],
+)
+AC_MSG_RESULT([$unet_cv_enable_unstable])
+
+if test $unet_cv_enable_unstable = "yes" ; then
+    AC_DEFINE([WITH_UNSTABLE_FEAT], 1, [Enable unstable features.])
+fi
+
+
+unet_cv_enable_gnutls="no"
+unet_cv_enable_openssl="yes"
+
+AC_MSG_CHECKING([for GnuTLS])
+AC_ARG_ENABLE([gnutls],
+  [  --enable-gnutls          Enables GnuTLS ssl backend.],
+  [unet_cv_enable_gnutls=$enable_gnutls],
+)
+AC_MSG_RESULT([$unet_cv_enable_gnutls])
+
+AC_MSG_CHECKING([for OpenSSL])
+AC_ARG_ENABLE([openssl],
+  [  --enable-openssl          Enables OpenSSL ssl backend.],
+  [unet_cv_enable_openssl=$enable_openssl],
+)
+AC_MSG_RESULT([$unet_cv_enable_openssl])
+
+if test x"$unet_cv_enable_gnutls" = xyes; then
+  unet_cv_enable_gnutls="no";
+  AC_CHECK_LIB(gnutls, gnutls_init, [
+    AC_CHECK_HEADERS(gnutls/gnutls.h, [
+      unet_cv_enable_gnutls="yes";
+    ])
+  ])
+fi
+
+if test x"$unet_cv_enable_openssl" = xyes; then
+  unet_cv_enable_openssl="no";
+  AC_CHECK_LIB(ssl, SSL_read, [
+    AC_CHECK_LIB(crypto, X509_new, [
+      AC_CHECK_HEADERS(openssl/ssl.h openssl/err.h, [
+        unet_cv_enable_openssl="yes";
+      ])
+    ])
+  ])
+fi
+
+if test x"$unet_cv_enable_gnutls" = xyes; then
+    LIBS="$LIBS -lgnutls"
+    AC_DEFINE([HAVE_GNUTLS], 1, [Define if you are using GnuTLS])
+fi
+
+if test x"$unet_cv_enable_openssl" = xyes ; then
+    LIBS="$LIBS -lssl -lcrypto"
+    AC_DEFINE([HAVE_OPENSSL], 1, [Define if you are using OpenSSL])
+fi
+
+dnl Finally really generate all output files:
+AC_OUTPUT(Makefile ircd/Makefile doc/Makefile, [echo timestamp > stamp-h])
+
+dnl Report configuration
+AC_MSG_RESULT([
+ircu is now hopefully configured for your system.
+
+  Host system:         $host_os
+  Prefix:              $prefix
+  Asserts:             $unet_cv_enable_asserts
+  Warnings:            $unet_cv_enable_warnings
+  Debug:               $unet_cv_enable_debug
+  Profile:             $unet_cv_enable_profile
+  Owner/mode:          $unet_cv_with_owner.$unet_cv_with_group ($unet_cv_with_mode)
+  Chroot:              $unet_cv_with_chroot
+  OpenSSL:             $unet_cv_enable_openssl
+  GnuTLS:              $unet_cv_enable_gnutls
+  Compatibility mode:  $unet_cv_enable_compat
+  Unstable features:   $unet_cv_enable_unstable
+
+  Domain:              $unet_cv_with_domain
+  DPath:               $unet_cv_with_dpath
+  CPath:               $unet_cv_with_cpath
+  LPath:               $unet_cv_with_lpath
+  Maximum connections: $unet_cv_with_maxcon
+
+  poll() engine:       $unet_cv_enable_poll
+  kqueue() engine:     $unet_cv_enable_kqueue
+  /dev/poll engine:    $unet_cv_enable_devpoll
+  epoll() engine:      $unet_cv_enable_epoll
+])
diff --git a/doc/Authors b/doc/Authors
new file mode 100644 (file)
index 0000000..77ee121
--- /dev/null
@@ -0,0 +1,225 @@
+/************************************************************************
+ *   IRC - Internet Relay Chat, doc/AUTHORS
+ *   Copyright (C) 1990
+ *
+ * AUTHORS FILE:
+ *   This file attempts to remember all contributors to the IRC
+ *   developement. Names can be only added this file, no name
+ *   should never be removed. This file must be included into all
+ *   distributions of IRC and derived works.
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 1, or (at your option)
+ *   any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+IRC was conceived of and written by Jarkko Oikarinen <jto@tolsun.oulu.fi>.
+IRC was originally written in University of Oulu, Computing Center.
+Jan 1991 - IRC 2.6  jto@tolsun.oulu.fi
+       - Multiple Channels and protocol changes
+
+Contributions were made by a cast of dozens, including the following:
+
+Markku Jarvinen <mta@tut.fi>: Emacs-like editing facility for the client
+
+Kimmo Suominen <kim@kannel.lut.fi>: HP-UX port
+
+Jeff Trim <jtrim@orion.cair.du.edu>: enhancements and advice
+
+Vijay Subramaniam <vijay@lll-winken.llnl.gov>: advice and ruthless publicity
+
+Karl Kleinpaste <karl@cis.ohio-state.edu>: user's manual
+
+Greg Lindahl <gl8f@virginia.edu>: AUTOMATON code, the Wumpus GM automaton,
+myriad bug fixes
+
+Bill Wisner <wisner@hayes.fai.alaska.edu>: numerous bug fixes and code
+enhancements
+
+Tom Davis <conslt16@zeus.unl.edu> and Tim Russell <russell@zeus.unl.edu>:
+VMS modifications
+
+Markku Savela <msa@tel4.tel.vtt.fi>: advice, support, and being the
+incentive to do some of our *own* coding. :)
+
+Tom Hopkins <hoppie@buengf.bu.edu>: bug fixes, quarantine lines,
+consolidation of various patches.
+
+Christopher Davis <ckd@cs.bu.edu>: EFnet/Anet gateway coding,
+many automata ;), documentation fixing.
+
+Helen Rose <hrose@cs.bu.edu>: documentation updating, and fixing.
+
+Tom Hinds <rocker@bucsf.bu.edu>: emacs client updating.
+
+Tim Miller <cerebus@bu-pub.bu.edu>: various server and client-breaking
+features.
+
+Darren Reed <avalon@coombs.anu.edu.au>: various bug fixes and enhancements.
+Introduced nickname and channelname hash tables into the server.
+
+The version 2.2 release was coordinated by Mike Bolotski
+<mikeb@salmon.ee.ubc.ca>.
+
+The version 2.4 release was coordinated by Markku Savela and
+Chelsea Ashley Dyerman
+
+The version 2.5.2 release was coordinated by Christopher Davis, Helen Rose,
+and Tom Hopkins.
+
+The versions 2.6.2, 2.7 and 2.8 releases were coordinated by Darren Reed.
+
+Contributions for the 2.8 release from the following people:
+Matthew Green <phone@coombs.anu.edu.au>
+Chuck Kane <ckane@ece.uiuc.edu>
+Matt Lyle <matt@oc.com>
+Vesa Ruokonen <ruokonen@lut.fi>
+
+Markku Savela <Markku.Savela@vtt.fi> / April 1990
+Fixed various bugs in 2.2PL1 release server (2.2msa.4) and changed
+sockets to use non-blocking mode (2.2msa.9). [I have absolutely
+nothing to do with clients :-]
+
+Chelsea Ashley Dyerman <chelsea@earth.cchem.berkeley.edu> / April 1990
+Rewrote the Makefiles, restructuring of source tree. Added libIrcd.a to
+the Makefile macros, numerous reformatting of server text messages, and
+added mkversion.sh to keep track of compilation statistics. Numerous
+bug fixes and enhancements, and co-coordinator of the 2.4 release.
+
+Jarle Lyngaas (nmijl@alf.uib.no) added Note functions to ircd.
+
+Armin Gruner <gruner@informatik.tu-muenchen.de> / May, June 1990:
+* Patched KILL-line feature for ircd.conf, works now.
+  Enhancement:  Time intervals can be specified in passwd-field.
+  Result: KILL-Line is only active during these intervals
+* Patched PRIVMSG handling, now OPER can specify masks for sending
+  private messages, advantage: msg to all at a specified server or host.
+* Little tests on irc 2.5 alpha, fixed some little typos in client code.
+  Change: common/debug.c has been moved to ircd/s_debug.c, and a
+  irc/c_debug.c has been created, for the benefit that wrong server msg
+  are displayed if client does not recognize them. (strange, if a server
+  sends an 'unknown command', isn't it?)
+
+Tom Hopkins <hoppie@buengf.bu.edu> / September, October 1990:
+* Patched msa's K lines for servers (Q lines).
+* Consolidated several patches, including Stealth's logging patch. 
+* Fixed several minor bugs. 
+* Has done lots of other stuff that I can't seem to remember, but he
+  always works on code, so he has to have done alot more than three
+  lines worth. :) 
+
+Thanks go to those persons not mentioned here who have added their advice,
+opinions, and code to IRC.
+
+Various modifications, bugreports, cleanups and testing by:
+
+Hugo Calendar <hugo@ucscb.ucsc.edu>
+Bo Adler <adler@csvax.cs.caltech.edu>
+Michael Sandrof <ms5n+@andrew.cmu.edu>
+Jon Solomon <jsol@cs.bu.edu>
+Jan Peterson <jlp@hamblin.math.byu.edu>
+Nathan Glasser <nathan@brokaw.lcs.mit.edu>
+Helen Rose <hrose@eff.org>
+Mike Pelletier <stealth@caen.engin.umich.edu>
+Basalat Ali Raja <gwydion@tavi.rice.edu>
+Eric P. Scott <eps@toaster.sfsu.edu>
+Dan Goodwin <fornax@wpi.wpi.edu>
+Noah Friedman <friedman@ai.mit.edu>
+
+
+UNDERNET (1991 - 1999)
+--------
+
+The Undernet versions (TSpre8, u2.9 and u2.10) are based on ircd-2.8.10 and
+contain thousands of hours of work by Carlo Wood <carlo@alinoe.com>
+(Run on IRC). The number of protocol enhancements, changes and additions
+that have been added are too many to summarize.  All patches are kept in the
+cvs repository at http://coder-com.undernet.org/.  Discussions on this
+server code are currently on the mailing list coder-com@undernet.org, or in
+#coder-com on undernet.
+
+The current maintainer is Bleep.
+
+Various additions and bugfixes have been contributed by:
+
+Aaron <agifford@sci.dixie.edu>
+Bleep <tomh@inxpress.net>
+CaptJay <captjay@superlink.net>
+CapVideo <majdi@puck.nether.net>
+Chaos <simon@troll.elec.uow.edu.au>
+Cym <cym@acrux.net>
+Derrick <dirk@servtech.com>
+Ensor <dholmes@rahul.net>
+flux <cmlambertus@ucdavis.edu>
+Ghostwolf <foxxe@trms.com>
+Gte- <gte@atomicrevs.demon.co.uk>
+Isomer <isomer@coders.net>
+Jamey <woodjr@durrance.Colorado.EDU>
+Jarle <jarlel@II.UIB.NO>
+Kev <klmitch@mit.edu>
+Nemesi <cocito@tin.it>
+Niels <niels@holding.pi.net>
+Run <carlo@alinoe.com>
+record <jegelhof@cloud9.net>
+smg <smg@lm.com>
+SeKs <intru@step.polymtl.ca>
+Simon- <sim@peace.netnation.com>
+Starfox <starfox@quicklink.com>
+Trio <trio@b62897.STUDENT.CWRU.Edu>
+WildThang <dvmitche@antietam.nssl.uoknor.edu>
+Xorath <vorac@wheel.dcn.davis.ca.us>
+
+UNDERNET (2000 - 2004)
+--------
+
+The Undernet versions (P9, P10, u2.10.11 and u2.10.12) are based on
+ircu2.10.07 and contain many hours of work by Coder Commitee.
+The number of protocol enhancements, changes and additions
+that have been added are too many to summarize. All patches are kept in the
+cvs repository at http://coder-com.undernet.org/.  Discussions on this
+server code are currently on the mailing list coder-com@undernet.org, or in
+#coder-com on undernet.
+
+The current maintainer is Isomer.
+
+Various additions, testings and bugfixes have been contributed by:
+
+A1kmm <ircu_stuff@mware.virtualave.net>
+Bleep <tomh@inxpress.net>
+Gte- <gte@atomicrevs.demon.co.uk>
+Isomer <isomer@coders.net>
+Kev <klmitch@mit.edu>
+Delete <delete@cyberabuse.org>
+Ghostwolf <foxxe@wtfs.net>
+Braden <dbtem@yahoo.com>
+net <net@astrolink.org>
+Steven <steven@doyle.net>
+OmniDynmc <omni@dynmc.net>
+Dianora <db@db.net>
+Sengaia <sengaia@undernet.org>
+Cyberdude <Cyberdude@undernet.org>
+Maniac- <maniac@cetlink.net>
+Vampire- <vampire@p16.pub.ro>
+mbuna <mbuna@bugged.org>
+beware <steendijk@tomaatnet.nl>
+n3tguy <netguy@spidernet.net>
+reed <reed@reedloden.com>
+Math <math@rootservices.net>
+hikari <shadow@undernet.org>
+Bleep <tom.helvey@cox.net>
+froo <froo@quakenet.org>
+splidge <splidge@quakenet.org>
+Zarjazz <zarjazz@quakenet.org>
+Spike <ekips@pandora.be>
+Jeekay <jeekay@netgamers.org>
+Entrope <entrope@gamesurge.net>
diff --git a/doc/Makefile b/doc/Makefile
new file mode 100644 (file)
index 0000000..878a9f1
--- /dev/null
@@ -0,0 +1,52 @@
+# doc/Makefile for the Undernet IRC Daemon.
+# Copyright (C) 1997, Carlo Wood <carlo@runaway.xs4all.nl>
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+# 02111-1307, USA.
+
+#### Start of system configuration section. ####
+
+prefix = /var/run/ircd
+top_srcdir = ..
+srcdir = .
+
+INSTALL = /usr/bin/install -c
+SHELL = /bin/sh
+RM = /bin/rm
+
+
+DATAROOTDIR = ${prefix}/share
+DATADIR = ${datarootdir}
+MANDIR = ${datarootdir}/man
+
+#### End of system configuration section. ####
+
+all:
+
+build:
+
+clean:
+
+distclean:
+       ${RM} -f Makefile stamp-m
+
+maintainer-clean: distclean
+
+depend:
+
+install:
+
+uninstall:
+
diff --git a/doc/Makefile.in b/doc/Makefile.in
new file mode 100644 (file)
index 0000000..82f0f31
--- /dev/null
@@ -0,0 +1,52 @@
+# doc/Makefile for the Undernet IRC Daemon.
+# Copyright (C) 1997, Carlo Wood <carlo@runaway.xs4all.nl>
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+# 02111-1307, USA.
+
+#### Start of system configuration section. ####
+
+prefix = @prefix@
+top_srcdir = @top_srcdir@
+srcdir = @srcdir@
+VPATH = @srcdir@
+INSTALL = @INSTALL@
+SHELL = @SHPROG@
+RM = @RMPROG@
+@SET_MAKE@
+
+DATAROOTDIR = @datarootdir@
+DATADIR = @datadir@
+MANDIR = @mandir@
+
+#### End of system configuration section. ####
+
+all:
+
+build:
+
+clean:
+
+distclean:
+       ${RM} -f Makefile stamp-m
+
+maintainer-clean: distclean
+
+depend:
+
+install:
+
+uninstall:
+
diff --git a/doc/api/api.txt b/doc/api/api.txt
new file mode 100644 (file)
index 0000000..5dc9993
--- /dev/null
@@ -0,0 +1,105 @@
+This directory is intended for documents describing programming
+interfaces within ircu, including such things as modebuf's and the
+features interface.  Please write these documents as plain text; if we
+want HTML, we can write a script to convert the text versions into
+HTML versions.  Toward that end, I respectfully suggest everyone
+conform to a common format, which I will describe here:
+
+Every .txt file should begin with a couple of paragraphs giving an
+overview of the API, its purpose, and how to use it.  Paragraphs
+should be separated by blank lines, as shown here.  Paragraphs that do
+not end in some form of punctuation, such as a period, will be treated
+as section headings.  The introduction ends when the first API element
+appears.  API element documentation is introduced with "<" followed by
+the element type--"struct", "typedef", "function", "macro", or (heaven
+forbid) "global", followed by ">", all on a line by itself.  The next
+line should contain a declaration of the element as it would appear in
+a header file; this may spread across multiple lines and contain
+comments and blank lines.  The declaration ends for most elements when
+a ";" is encountered; for macros, the declaration ends on the last
+line not ending in "\".
+
+The documentation for the API element should immediately follow the
+declaration of that element, and should be separated from it by a
+single blank line.  This documentation should explain the purpose of
+the element and describe what each of its fields mean.  The
+documentation ends when the corresponding "</" tag is reached, just as
+in HTML or XML.  (I don't intend for the files to be either HTML or
+XML, I just want them to be easy to parse so they could be turned into
+either, as occasion warrants.)  An example follows:
+
+<struct>
+struct FooBar; /* a sample structure with no definition */
+
+The comment, since it's on the same line as the ";", is associated
+with the declaration for struct FooBar.
+</struct>
+
+<struct>
+struct FooBar {
+  long     fb_magic;   /* a magic number */
+  char    *fb_string;  /* a string of some sort */
+};
+
+The sequence "};" ends the struct declaration.
+</struct>
+
+<typedef>
+typedef FooBar_t;      /* a simple typedef */
+
+This element shows how to hide the inner workings of typedefs.
+</typedef>
+
+<typedef>
+typedef struct FooBar FooBar_t;        /* a more complex typedef */
+
+Here we show the full typedef declaration.
+</typedef>
+
+<global>
+extern int fooBarFreeList;     /* global variables should be avoided */
+
+You should avoid global variables, but if you must have one for alloc
+counts or whatever, here's how to specify documentation for them.
+</global>
+
+<macro>
+#define HAVE_FOOBAR            /* We have FOOBAR, whatever it may be */
+
+This could be used for boolean macros (macros used in #ifdef's, for
+instance) or for simple value macros where you're hiding the values.
+Since there are so many variations on macros, I'll only show one other
+variation below:
+</macro>
+
+<macro>
+#define FooBarVerify(foobar)   ((foobar) && \
+                                (foobar)->fb_magic == FOOBAR_STRUCT_MAGIC)
+
+This macro takes arguments.  Again, we could leave out the actual
+definition, or even treat the macro as a function rather than a
+macro.  This also shows how to do multi-line macros.
+</macro>
+
+<function>
+void *foobar(struct FooBar *blah, int flag);
+
+Since function definitions never appear in header files anyway, we
+don't have to worry about hiding information.  You should leave off
+"extern" in the function declaration, and please include names for the
+variables, so you can refer to them in the function documentation.
+</function>
+
+The API document may then end in some summary information, if you
+wish, or a ChangeLog of some form, such as follows.
+
+<authors>
+Kev <klmitch@mit.edu>
+</authors>
+
+<changelog>
+[2000-12-18 Kev] Initial definition of how API documents should look.
+Further entries in the changelog should *precede* this one and should
+be separated from it by a blank line.  Also specify your name, as
+listed in the "<authors>" section, so we know who to blame ;)
+</changelog>
diff --git a/doc/api/events.txt b/doc/api/events.txt
new file mode 100644 (file)
index 0000000..cadfa70
--- /dev/null
@@ -0,0 +1,816 @@
+The IRC server is built around an event loop.  Until the u2.10.11
+release, this event loop has been rather ad-hoc; timed events are
+hard-coded in, signals are handled inside the signal handler, etc.
+All of this has changed with u2.10.11.  A new subsystem, the events
+subsystem, has been introduced; the new subsystem contains a
+generalization of the concept of an event.  An event is a signal, the
+expiration of a timer, or some form of activity on a network socket.
+This new subsystem has the potential to vastly simplify the code that
+is arguably the core of any network program, and makes it much simpler
+to support more exotic forms of network activity monitoring than the
+conventional select() and poll() calls.
+
+The primary concepts that the events subsystem works with are the
+"event," represented by a struct Event, and the "generator."  There
+are three types of generators: sockets, represented by struct Socket;
+signals, represented by struct Signal; and timers, represented by
+struct Timer.  Each of these generators will be described in turn.
+
+Signals
+
+The signal is perhaps the simplest generator in the entire events
+subsystem.  Basically, instead of setting a signal handler, the
+function signal_add() is called, specifying a function to be called
+when a given signal is detected.  Most importantly, that call-back
+function is called _outside_ the context of a signal handler,
+permitting the call-back to use more exotic functions that are
+anathema within a signal handler, such as MyMalloc().  Once a
+call-back for a signal has been established, it cannot be deleted;
+this design decision was driven by the fact that ircd never changes
+its signal handlers.
+
+Whenever a signal is received, an event of type ET_SIGNAL is
+generated, and that event is passed to the event call-back function
+specified in the signal_add() call.
+
+Timers
+
+Execution of the call-back functions for a timer occur when that timer
+_expires_; when a timer expires depends on the type of timer and the
+expiration time that was used for that timer.  A TT_ABSOLUTE timer,
+for instance, expires at exactly the time given as the expiration
+time.  This time is a standard UNIX time_t value, measuring seconds
+since the UNIX epoch.  The TT_ABSOLUTE timer type is complemented by
+the TT_RELATIVE timer; the time passed as its expiration time is
+relative to the current time.  If a TT_RELATIVE timer is given an
+expiration time of 5, for instance, it will expire 5 seconds after the
+present time.  Internally, TT_RELATIVE timers are converted into
+TT_ABSOLUTE timers, with the expiration time adjusted by addition of
+the current time.
+
+Those two types of timers, TT_ABSOLUTE and TT_RELATIVE, are
+single-shot timers.  Once they expire, they are removed from the timer
+list unless re-added by the event call-back or through some other
+mechanism.  There is another type of timer, however, the TT_PERIODIC
+timer, that is not removed from the timer list.  TT_PERIODIC timers
+are similar to TT_RELATIVE timers, in that one passes in the expire
+time as a relative number of seconds, but when they expire, they are
+re-added to the timer list with the same relative expire time.  This
+means that a TT_PERIODIC timer with an expire time of 5 seconds that
+is set at 11:50:00 will have its call-back called at 11:50:05,
+11:50:10, 11:50:15, and so on.
+
+Timers have to be run by the event engines explicitly by calling
+timer_run() on the generator list passed to the engine event loop.
+In addition, engines may determine the next (absolute) time that a
+timer needs to be run by calling the timer_next() macro; this may be
+used to set a timeout on the engine's network activity monitoring
+function.  Engines are described in detail below.
+
+When a timer expires, an event of ET_EXPIRE is generated, and the
+call-back function is called.  When a timer is destroyed, either as
+the result of an expiration or as a result of an explicit timer_del()
+call, an event of ET_DESTROY is generated, notifying the call-back
+that the struct Timer can be deallocated.
+
+Sockets
+
+Perhaps the most complicated event generator in all of the event
+system is the socket, as described by struct Socket.  This single
+classification covers datagram sockets and stream sockets.  To
+differentiate the different kinds of sockets, there is a socket state
+associated with each socket.  The available states are SS_CONNECTING,
+which indicates that a particular socket is in the process of
+completing a non-blocking connect(); SS_LISTENING, which indicates
+that a particular socket is a listening socket; SS_CONNECTED, which is
+the state of every other stream socket; SS_DATAGRAM, which is an
+ordinary datagram socket, and SS_CONNECTDG, which describes a
+connected datagram socket.  (The SS_NOTSOCK state is for the internal
+use of the events system and will not be described here.)
+
+In addition to the socket states, there's also an event mask for each
+socket; this set of flags is used to tell the events subsystem what
+events the application is interested in for the socket.  For
+SS_CONNECTING and SS_LISTENING sockets, this events mask has no
+meaning, but on the other socket states, the event mask is used to
+determine if the application is interested in readable
+(SOCK_EVENT_READABLE) or writable (SOCK_EVENT_WRITABLE) indications.
+
+Most of the defined event types have to do with socket generators.
+When a socket turns up readable, for instance, an event of type
+ET_READ is generated.  Similarly, ET_WRITE is generated when a socket
+can be written to.  The ET_ACCEPT event is generated when a listening
+socket indicates that there is a connection to be accepted; ET_CONNECT
+is generated when a non-blocking connect is completed.  Finally, if an
+end-of-file indication is detected, ET_EOF is generated, whereas if an
+error has occurred on the socket, ET_ERROR is generated.  Of course,
+when a socket has been deleted by the socket_del() function, an event
+of ET_DESTROY is generated when it is safe for the memory used by the
+struct Socket to be reclaimed.
+
+Events
+
+An event, represented by a struct Event, describes in detail all of
+the particulars of an event.  Each event has a type, and an optional
+integer piece of data may be passed with some events--in particular,
+ET_SIGNAL events pass the signal number, and ET_ERROR events pass the
+errno value.  The struct Event also contains a pointer to the
+structure describing the generated event--although it should be noted
+that the only way to disambiguate which type of generator is contained
+within the struct Event is by which call-back function has been
+called.
+
+All generators have a void pointer which can be used to pass important
+information to the call-back, such as a pointer to a struct Client.
+Additionally, generators have a reference count, and a union of a void
+pointer and an integer that should only be utilized by the event
+engine.  Finally, there is also a field for flags, although the only
+flag of concern to the application (or the engine) is the active flag,
+which may be tested using the test macros described below.
+
+Whatever the generator, the call-back function is a function returning
+nothing (void) and taking as its sole argument a pointer to struct
+Event.  This call-back function may be implemented as a single switch
+statement that calls out to appropriate external functions as needed.
+
+Engines
+
+Engines implement the actual socket event loop, and may also have some
+means of receiving signal events.  Each engine has a name, which
+should describe what its core function is; for instance, the engine
+based on the standard select() function is named, simply, "select()."
+Each engine must implement several call-backs which are used to
+initialize the engine, notify the engine of sockets the application is
+interested in, etc.  All of this data is described by a single struct
+Engine, which should be the only non-static variable or function in
+the engine's source file.
+
+The engine's event loop, pointed to by the eng_loop field of the
+struct Engine, must consist of a single while loop predicated on the
+global variable _running_.  Additionally, this loop's final statement
+must be a call to timer_run(), to execute all timers that have become
+due.  Ideally, this construction should be pulled out of each engine's
+eng_loop and put in the event_loop() function of the events
+subsystem.
+
+Reference Counts
+
+As mentioned previously, all generators keep a reference count.
+Should timer_del() or socket_del() be called on a generator with a
+non-zero reference count, for whatever reason, the actual destruction
+of the generator will be delayed until the reference count again
+reaches zero.  This is used by the event loop to keep sockets that it
+is currently referencing from being deallocated before it is done
+checking all pending events on them.  To increment the reference count
+by one, call gen_ref_inc() on the generator; the corresponding macro
+gen_ref_dec() decrements the reference counts, and will automatically
+destroy the generator if the appropriate conditions are met.
+
+Debugging Functions
+
+It can be difficult to debug an engines if, say, a socket state can
+only be expressed as a meaningless number.  Therefore, when DEBUGMODE
+is #define'd, five number-to-name functions are also defined to make
+the debugging data more meaningful.  These functions must only be
+called when DEBUGMODE is #define'd.  Calling them from within Debug()
+macro calls is safe; calling them from log_write() calls is not.
+
+<typedef>
+typedef void (*EventCallBack)(struct Event*);
+
+The _EventCallBack_ type is used to simplify declaration of event
+call-back functions.  It is used in timer_add(), signal_add(), and
+socket_add().  The event call-back should process the event, taking
+whatever actions are necessary.  The function should be declared as
+returning void.
+</typedef>
+
+<typedef>
+typedef int (*EngineInit)(int);
+
+The _EngineInit_ function takes an integer specifying the maximum
+number of sockets the event system is expecting to handle.  This
+number may be used by the engine initialization function for memory
+allocation computations.  If initialization succeeds, this function
+must return 1.  If initialization fails, the function should clean up
+after itself and return 0.  The events subsystem has the ability to
+fall back upon another engine, should an engine initialization fail.
+Needless to say, the engines based upon poll() and select() should
+never fail in this way.
+</typedef>
+
+<typedef>
+typedef void (*EngineSignal)(struct Signal*);
+
+If an engine has the capability to directly detect signals, it should
+set the eng_signal field of struct Engine non-zero.  When the
+application indicates interest in a particular signal, the
+_EngineSignal_ function will be called with the filled-in struct
+Signal, in order to register interest in that signal with the engine.
+</typedef>
+
+<typedef>
+typedef int (*EngineAdd)(struct Socket*);
+
+All engines must define an _EngineAdd_ function, which is used to
+inform the engine of the application's interest in the socket.  If the
+new socket cannot be accommodated by the engine for whatever reason,
+this function must return 0.  Otherwise, the function must return 1,
+informing the events subsystem that the interest has been noted.
+</typedef>
+
+<typedef>
+typedef void (*EngineState)(struct Socket*, enum SocketState new_state);
+
+Sockets can change state.  SS_CONNECTING sockets, for instance, can
+become SS_CONNECTED.  Whenever a socket state changes, the engine is
+informed, since some states require different notification procedures
+than others.  This is accomplished by calling the _EngineState_
+function with the new state.  The struct Socket passed to the engine
+will still have the old state, if the engine must reference that.
+</typedef>
+
+<typedef>
+typedef void (*EngineEvents)(struct Socket*, unsigned int new_events);
+
+Applications may only be interested in given events on a socket for a
+limited time.  When the application's interest shifts, a new events
+mask is set for the socket.  The engine is informed of this change by
+a call to its _EngineEvents_ function.
+</typedef>
+
+<typedef>
+typedef void (*EngineDelete)(struct Socket*);
+
+Eventually, an application will close all the sockets it has opened.
+When a socket is closed, and the corresponding struct Socket deleted
+with a call to socket_del(), the _EngineDelete_ function will be
+called to notify the engine of the change.
+</typedef>
+
+<typedef>
+typedef void (*EngineLoop)(struct Generators*);
+
+The workhorse of the entire events subsystem is the event loop,
+implemented by each engine as the _EngineLoop_ function.  This
+function is called with a single argument that may be passed to
+timer_next() to calculate the next time a timer will expire.
+</typedef>
+
+<enum>
+enum SocketState {
+  SS_CONNECTING,       /* Connection in progress on socket */
+  SS_LISTENING,                /* Socket is a listening socket */
+  SS_CONNECTED,                /* Socket is a connected socket */
+  SS_DATAGRAM,         /* Socket is a datagram socket */
+  SS_CONNECTDG,                /* Socket is a connected datagram socket */
+  SS_NOTSOCK           /* Socket isn't a socket at all */
+};
+
+This enumeration contains a list of all possible states a socket can
+be in.  Applications should not use SS_NOTSOCK; engines should treat
+it as a special socket state for non-sockets.  The only event that
+should be watched for on a struct Socket in the SS_NOTSOCK state is
+readability.  This socket state is used to implement the fall-back
+signal event generation.
+</enum>
+
+<enum>
+enum TimerType {
+  TT_ABSOLUTE,         /* timer that runs at a specific time */
+  TT_RELATIVE,         /* timer that runs so many seconds in the future */
+  TT_PERIODIC          /* timer that runs periodically */
+};
+
+The three possible timer types are defined by the TimerType
+enumeration.  More details can be found in the "Timers" sub-section.
+</enum>
+
+<enum>
+enum EventType {
+  ET_READ,             /* Readable event detected */
+  ET_WRITE,            /* Writable event detected */
+  ET_ACCEPT,           /* Connection can be accepted */
+  ET_CONNECT,          /* Connection completed */
+  ET_EOF,              /* End-of-file on connection */
+  ET_ERROR,            /* Error condition detected */
+  ET_SIGNAL,           /* A signal was received */
+  ET_EXPIRE,           /* A timer expired */
+  ET_DESTROY           /* The generator is being destroyed */
+};
+
+This enumeration contains all the types of events that can be
+generated by the events subsystem.  The first 6 are generated by
+socket generators, the next by signal generators, and the next by
+timer generators.  ET_DESTROY is generated by both socket and timer
+generators when the events subsystem is finished with the memory
+allocated by both.
+</enum>
+
+<struct>
+struct Socket;
+
+This structure describes everything the events subsystem knows about a
+given socket.  All of its fields may be accessed through the s_*
+macros described below.
+</struct>
+
+<struct>
+struct Timer;
+
+The struct Timer structure describes everything the events subsystem
+knows about a given timer.  Again, all of its fields may be accessed
+through the t_* macros described below.
+</struct>
+
+<struct>
+struct Signal;
+
+Signal generators are described by a struct Signal.  All of the fields
+of a struct Signal may be accessed by the sig_* macros described
+below.
+</struct>
+
+<struct>
+struct Event;
+
+Each event is described by a struct Event.  Its fields may be examined
+using the ev_* macros described below.
+</struct>
+
+<struct>
+struct Generators;
+
+Each engine is passed a list of all generators when the engine's
+_EngineLoop_ function is called.  The only valid way to access this
+structure is via the timer_next() function described below.
+</struct>
+
+<struct>
+struct Engine {
+  const char*  eng_name;       /* a name for the engine */
+  EngineInit   eng_init;       /* initialize engine */
+  EngineSignal eng_signal;     /* express interest in a signal */
+  EngineAdd    eng_add;        /* express interest in a socket */
+  EngineState  eng_state;      /* mention a change in state to engine */
+  EngineEvents eng_events;     /* express interest in socket events */
+  EngineDelete eng_closing;    /* socket is being closed */
+  EngineLoop   eng_loop;       /* actual event loop */
+};
+
+Each engine is described by the struct Engine structure.  Each engine
+must define all of the functions described above except for the
+_EngineSignal_ function, which is optional.
+</struct>
+
+<macro>
+#define SOCK_EVENT_READABLE    0x0001  /* interested in readable */
+
+The SOCK_EVENT_READABLE flag indicates to the engine that the
+application is interested in readability on this particular socket.
+</macro>
+
+<macro>
+#define SOCK_EVENT_WRITABLE    0x0002  /* interested in writable */
+
+The SOCK_EVENT_WRITABLE flag indicates to the engine that the
+application is interested in this socket being writable.
+</macro>
+
+<macro>
+#define SOCK_EVENT_MASK                (SOCK_EVENT_READABLE | SOCK_EVENT_WRITABLE)
+
+SOCK_EVENT_MASK may be used to extract only the event interest flags
+from an event interest set.
+</macro>
+
+<macro>
+#define SOCK_ACTION_SET                0x0000  /* set interest set as follows */
+
+When socket_events() is called with a set of event interest flags and
+SOCK_ACTION_SET, the socket's event interest flags are set to those
+passed into socket_events().
+</macro>
+
+<macro>
+#define SOCK_ACTION_ADD                0x1000  /* add to interest set */
+
+When SOCK_ACTION_ADD is used in a call to socket_events(), the event
+interest flags passed in are added to the existing event interest
+flags for the socket.
+</macro>
+
+<macro>
+#define SOCK_ACTION_DEL                0x2000  /* remove from interest set */
+
+When SOCK_ACTION_DEL is used in a call to socket_events(), the event
+interest flags passed in are removed from the existing event interest
+flags for the socket.
+</macro>
+
+<macro>
+#define SOCK_ACTION_MASK       0x3000  /* mask out the actions */
+
+SOCK_ACTION_MASK is used to isolate the socket action desired.
+</macro>
+
+<function>
+enum SocketState s_state(struct Socket* sock);
+
+This macro returns the state of the given socket.
+</function>
+
+<function>
+unsigned int s_events(struct Socket* sock);
+
+This macro returns the current event interest mask for a given
+socket.  Note that if the socket is in the SS_CONNECTING or
+SS_LISTENING states, this mask has no meaning.
+</function>
+
+<function>
+int s_fd(struct Socket* sock);
+
+This macro simply returns the file descriptor for the given socket.
+</function>
+
+<function>
+void* s_data(struct Socket* sock);
+
+When a struct Socket is initialized, data that the call-back function
+may find useful, such as a pointer to a struct Connection, is stored
+in the struct Socket.  This macro returns that pointer.
+</function>
+
+<function>
+int s_ed_int(struct Socket* sock);
+
+Engines may find it convenient to associate an integer with a struct
+Socket.  This macro may be used to retrieve that integer or, when used
+as an lvalue, to assign a value to it.  Engine data must be either an
+int or a void*; use of both is prohibited.
+</function>
+
+<function>
+void* s_ed_ptr(struct Socket* sock);
+
+Engines may find it convenient to associate a void* pointer with a
+struct Socket.  This macro may be used to retrieve that pointer or,
+when used as an lvalue, to assign a value to it.  Engine data must be
+either an int or a void*; use of both is prohibited.
+</function>
+
+<function>
+int s_active(struct Socket* sock);
+
+A socket's active flag is set when initialized by socket_add(), and is
+cleared immediately prior to generating an event of type ET_DESTROY.
+This may be used by the application to determine whether or not the
+socket is still in use by the events subsystem.  If it is, s_active()
+returns a non-zero value; otherwise, its value is 0.
+</function>
+
+<function>
+int socket_add(struct Socket* sock, EventCallBack call, void* data,
+              enum SocketState state, unsigned int events, int fd);
+
+This function is called to add a socket to the list of sockets to be
+monitored.  The _sock_ parameter is a pointer to a struct Socket that
+is allocated by the application.  The _call_ parameter is a pointer to
+a function to process any events on the socket.  The _data_ parameter
+is for use of the socket call-back and may be zero.  The _state_
+parameter must be one of the valid socket states.  The _events_
+parameter must be a valid events interest mask--0, or the binary OR of
+SOCK_EVENT_READABLE or SOCK_EVENT_WRITABLE.  Finally, the _fd_
+parameter specifies the socket's file descriptor.  This function
+returns 1 if successful or 0 otherwise.
+</function>
+
+<function>
+void socket_del(struct Socket* sock);
+
+When the application is no longer interested in a particular socket,
+it should call the socket_del() function.  This function must be
+called no later than when the socket has been closed, to avoid
+attempting to call select() or similar functions on closed sockets.
+</function>
+
+<function>
+void socket_state(struct Socket* sock, enum SocketState state);
+
+Occasionally, a socket's state will change.  This function is used to
+inform the events subsystem of that change.  Only certain state
+transitions are valid--a socket in the SS_LISTENING or SS_CONNECTED
+states cannot change states, nor can an SS_CONNECTING socket change to
+some state other than SS_CONNECTED.  Of course, SS_DATAGRAM sockets
+may change state only to SS_CONNECTDG, and SS_CONNECTDG sockets may
+only change states to SS_DATAGRAM.
+</function>
+
+<function>
+void socket_events(struct Socket* sock, unsigned int events);
+
+When the application changes the events it is interested in, it uses
+socket_events() to notify the events subsystem of that change.  The
+_events_ parameter is the binary OR of one of SOCK_ACTION_SET,
+SOCK_ACTION_ADD, or SOCK_ACTION_DEL with an events mask.  See the
+documentation for the SOCK_* macros for more information.
+</function>
+
+<function>
+const char* state_to_name(enum SocketState state);
+
+This function is defined only when DEBUGMODE is #define'd.  It takes
+the given _state_ and returns a string giving that state's name.  This
+function may safely be called from Debug() macros.
+</function>
+
+<function>
+const char* sock_flags(unsigned int flags);
+
+This function is defined only when DEBUGMODE is #define'd.  It takes
+the given event interest flags and returns a string naming each of
+those flags.  This function may safely be called from Debug() macros,
+but may only be called once, since it uses function static storage to
+store the flag strings.
+</function>
+
+<function>
+int sig_signal(struct Signal* sig);
+
+This macro returns the signal number for the given struct Signal.
+</function>
+
+<function>
+void* sig_data(struct Signal* sig);
+
+When a struct Signal is initialized, data that the call-back function
+may find useful is stored in the struct Signal.  This macro returns
+that pointer.
+</function>
+
+<function>
+int sig_ed_int(struct Signal* sig);
+
+Engines may find it convenient to associate an integer with a struct
+Signal.  This macro may be used to retrieve that integer or, when used
+as an lvalue, to assign a value to it.  Engine data must be either an
+int or a void*; use of both is prohibited.
+</function>
+
+<function>
+void* sig_ed_ptr(struct Signal* sig);
+
+Engines may find it convenient to associate a void* pointer with a
+struct Signal.  This macro may be used to retrieve that pointer or,
+when used as an lvalue, to assign a value to it.  Engine data must be
+either an int or a void*; use of both is prohibited.
+</function>
+
+<function>
+int sig_active(struct Signal* sig);
+
+A signal's active flag is set when initialized by signal_add().  This
+may be used by the application to determine whether or not the signal
+has been initialized yet.  If it is, sig_active() returns a non-zero
+value; otherwise, its value is 0.
+</function>
+
+<function>
+void signal_add(struct Signal* signal, EventCallBack call, void* data,
+               int sig);
+
+This function is called to add a signal to the list of signals to be
+monitored.  The _signal_ parameter is a pointer is a pointer to a
+struct Signal that is allocated by the application.  The _call_
+parameter is a pointer to a function to process any signal events.
+The _data_ parameter is for use of the signal call-back and may be
+zero.  The _sig_ parameter is the integer value of the signal to be
+monitored.
+</function>
+
+<function>
+enum TimerType t_type(struct Timer* tim);
+
+This macro returns the type of the given timer.
+</function>
+
+<function>
+time_t t_value(struct Timer* tim);
+
+This macro returns the value that was used when the given timer was
+initialized by the events subsystem.  It will contain an absolute time
+if the timer type is TT_ABSOLUTE, and a relative time otherwise.
+</function>
+
+<function>
+time_t t_expire(struct Timer* tim);
+
+This macro returns the absolute time at which the timer will next
+expire.
+</function>
+
+<function>
+void* t_data(struct Timer* tim);
+
+When a struct Timer is initialized, data that the call-back function
+may find useful is stored in the struct Socket.  This macro returns
+that pointer.
+</function>
+
+<function>
+int t_ed_int(struct Timer *tim);
+
+Engines may find it convenient to associate an integer with a struct
+Timer.  This macro may be used to retrieve that integer or, when used
+as an lvalue, to assign a value to it.  Engine data must be either an
+int or a void*; use of both is prohibited.
+</function>
+
+<function>
+void* t_ed_ptr(struct Timer *tim);
+
+Engines may find it convenient to associate a void* pointer with a
+struct Timer.  This macro may be used to retrieve that pointer or,
+when used as an lvalue, to assign a value to it.  Engine data must be
+either an int or a void*; use of both is prohibited.
+</function>
+
+<function>
+int t_active(struct Timer *tim);
+
+A timer's active flag is set when initialized by timer_add(), and is
+cleared immediately prior to generating an event of type ET_DESTROY.
+This may be used by the application to determine whether or not the
+timer is still in use by the events subsystem.  If it is, s_active()
+returns a non-zero value; otherwise, its value is 0.
+</function>
+
+<function>
+void timer_add(struct Timer* timer, EventCallBack call, void* data,
+              enum TimerType type, time_t value);
+
+This function is called to initialize and queue a timer.  The _timer_
+parameter is a pointer to a struct Timer that is allocated by the
+application.  The _call_ parameter is a pointer to a function to
+process the timer's expiration.  The _data_ parameter is for use of
+the timer call-back and may be zero.  The _type_ parameter must be one
+of the valid timer types--TT_ABSOLUTE, TT_RELATIVE, or TT_PERIODIC.
+Finally, _value_ is the value for the timer's expiration.
+</function>
+
+<function>
+void timer_del(struct Timer* timer);
+
+When the application no longer needs a TT_PERIODIC timer, or when it
+wishes to stop a TT_ABSOLUTE or TT_RELATIVE timer before its
+expiration, it should call the timer_del() function.
+</function>
+
+<function>
+void timer_chg(struct Timer* timer, enum TimerType type, time_t value);
+
+Occasionally, an application may wish to delay an existing TT_ABSOLUTE
+or TT_RELATIVE timer; this may be done with the timer_chg() function.
+The _type_ parameter must be one of TT_ABSOLUTE or
+TT_RELATIVE--changing the values of TT_PERIODIC timers is not
+supported.  The _value_ parameter is the same as would be given to
+timer_add() for that particular type of timer.
+</function>
+
+<function>
+void timer_run(void);
+
+When an engine has finished processing the results of its socket and
+signal checks--just before it loops around to test for more events--it
+should call the timer_run() function to expire any waiting timers.
+</function>
+
+<function>
+time_t timer_next(struct Generators* gen);
+
+Most engines will use a blocking call with a timeout to check for
+socket activity.  To determine when the next timer needs to be run,
+and thus to calculate how long the call should block, the engine
+should call timer_next() with the _gen_ parameter passed to the
+_EngineLoop_ function.  The timer_next() function returns an absolute
+time, which may have to be massaged into a relative time before the
+engine may use it.
+</function>
+
+<function>
+const char* timer_to_name(enum TimerType type);
+
+This function is defined only when DEBUGMODE is #define'd.  It takes
+the given _type_ and returns a string giving that type's name.  This
+function may safely be called from Debug() macros.
+</function>
+
+<function>
+enum EventType ev_type(struct Event* ev);
+
+This macro simply returns the type of the event _ev_.
+</function>
+
+<function>
+int ev_data(struct Event* ev);
+
+When an event is generated, a single integer can be passed along as a
+piece of extra information.  This can be used, for instance, to carry
+an errno value when an ET_ERROR is generated.  This macro simply
+returns that integer.
+</function>
+
+<function>
+struct Socket* ev_socket(struct Event* ev);
+
+If the event was generated by a socket, this macro returns a pointer
+to the struct Socket that generated the event.  The results are
+undefined if the event was not generated by a socket.
+</function>
+
+<function>
+struct Signal* ev_signal(struct Event* ev);
+
+If the event was generated by a signal, this macro returns a pointer
+to the struct Signal that generated the event.  The results are
+undefined if the event was not generated by a signal.
+</function>
+
+<function>
+struct Timer* ev_timer(struct Event* ev);
+
+If the event was generated by a timer, this macro returns a pointer to
+the struct Timer that generated the event.  The results are undefined
+if the event was not generated by a timer.
+</function>
+
+<function>
+void event_init(int max_sockets);
+
+Before any of the functions or macros described here can be called,
+the events subsystem must be initialized by calling event_init().  The
+_max_sockets_ parameter specifies to the events subsystem how many
+sockets it must be able to support; this figure may be used for memory
+allocation by the engines.
+</function>
+
+<function>
+void event_loop(void);
+
+Once the initial sockets are open, signals added, and timers queued,
+the application must call the event_loop() function in order to
+actually begin monitoring those sockets, signals, and timers.
+</function>
+
+<function>
+void event_generate(enum EventType type, void* arg, int data);
+
+This is the function called by the events subsystem to generate
+particular events.  The _type_ parameter specifies the type of event
+to generate, and the _arg_ parameter must be a pointer to the event's
+generator.  The _data_ parameter may be used for passing such things
+as signal numbers or errno values.
+</function>
+
+<function>
+const char* event_to_name(enum EventType type);
+
+This function is defined only when DEBUGMODE is #define'd.  It takes
+the given _type_ and returns a string giving that event type's name.
+This function may safely be called from Debug() macros.
+</function>
+
+<function>
+const char* engine_name(void);
+
+This function is used to retrieve the name of the engine presently
+being used by the events subsystem.
+</function>
+
+<function>
+void gen_ref_inc(void* gen);
+
+This macro increments the reference count of the generator _gen_,
+preventing it from simply disappearing without warning.
+</function>
+
+<function>
+void gen_ref_dec(void* gen);
+
+This macro decrements the reference count of the generator _gen_, and
+releases the memory associated with it by generating at ET_DESTROY
+event if the reference count falls to zero and the generator is marked
+for destruction.  No references should be made to the generator after
+calling this macro.
+</function>
+
+<authors>
+Kev <klmitch@mit.edu>
+</authors>
+
+<changelog>
+[2001-6-14 Kev] Finished initial description of the events subsystem.
+
+[2001-6-13 Kev] Initial description of the events subsystem.
+</changelog>
diff --git a/doc/api/features.txt b/doc/api/features.txt
new file mode 100644 (file)
index 0000000..f7288ee
--- /dev/null
@@ -0,0 +1,230 @@
+As of u2.10.11, most of the compile-time configuration options present
+in previous versions of ircu have been provided via the configuration
+file as "features."  This document is intended not only to give an
+explanation of how to use the features subsystem in new code, but also
+how to define new features.
+
+In the ircd_features.h header file is an enum Feature that lists all
+the features known to the features subsystem.  The order of entries in
+this list must match precisely the order of features as listed in the
+features[] table in ircd_features.c.  There are four kinds of
+features, seven different flags that can be set for features, and
+seven different call-backs for more complex features.
+
+Types of Features
+
+There are at present four different types of features: NONE, INT,
+BOOL, and STR.  Features of type "NONE" are complex features, such as
+the logging subsystem, that have complicated behavior that's managed
+through the use of call-backs.  The call-backs available are set,
+which is called to set the value of the feature; reset, which is
+called to reset the value of the feature back to its default; get,
+which is called to send the user a RPL_FEATURE to describe the feature
+setting; unmark, which is called prior to reading the configuration
+file; mark, which is called after reading the configuration file; and
+report, which is used to send a user a list of RPL_STATSFLINE
+replies.
+
+In comparison to type "NONE," the other types are very simple.  Type
+"INT" is used for features that take an integer value; "BOOL" is for
+those features that are boolean types; and "STR" is for those features
+that take simple string values.  The values for these feature types
+are handled directly by the features subsystem, and can be examined
+from code with the feature_int(), feature_bool(), and feature_str()
+functions, described below.  These features have a notify callback,
+which is used to warn subsystems that use the values of particular
+features that the value has changed.
+
+Feature Flags
+
+There are seven feature flags, one of which is used internally by the
+feature subsystem.  Three of these flags, FEAT_OPER, FEAT_MYOPER, and
+FEAT_NODISP, are used to select who can see the settings of those
+features; FEAT_OPER permits any operator anywhere on the network to
+examine the settings of a particular feature, whereas FEAT_MYOPER only
+permits operators local to a server to examine feature values, and
+FEAT_NODISP prohibits display of the feature value altogether.  If
+none of these three flags are specified, then any user may examine
+that feature's value.
+
+Two other flags only have any meaning for string values; they are
+FEAT_NULL, which is used to specify that a feature of type "STR" may
+have a NULL value, and FEAT_CASE, which specifies that the feature is
+case sensitive--this may be used on file names, for example.  Note
+that if you give "0" as the default value for a feature, you must also
+set the FEAT_NULL flag.
+
+The remaining non-internal flag is FEAT_READ, which simply sets the
+feature to be read-only; a feature so marked may only be changed
+through the configuration file.
+
+Marking Features
+
+When the configuration file is read, there must be some way to
+determine if a particular Feature entry has been removed since the
+last time the configuration file was read.  The way this is done in
+the features subsystem is to have a "mark" for each feature.  Prior to
+reading the configuration file, all marks are cleared for all features
+(and all "unmark" call-backs are called).  As each Feature entry is
+encountered and processed, that feature's mark is set.  Finally, when
+the configuration file has been fully read, all remaining unmarked
+features are reset to their default values (and all "mark" call-backs
+are called).
+
+Adding New Features
+
+To add a new feature, first determine the feature's name (which must
+begin with the string "FEAT_") and its type ("NONE," "INT," "BOOL," or
+"STR").  Then add the feature to the enum Feature in an appropriate
+place (i.e., it's good to group all features affecting operators
+separate from those features affecting networking code), and a
+corresponding entry in the features[] table in ircd_features.c.  It
+will be best to use one of the F_?() macros, which are documented
+below.  Then, whenever you need to refer to the value of a specific
+feature, call the appropriate feature_<type>() function, as documented
+below.
+
+<enum>
+enum Feature;
+
+The "Feature" enum lists all of the features known to the feature
+subsystem.  Each feature name *must* begin with "FEAT_"; the portion
+of the name following "FEAT_" will be what you use to set the feature
+from the configuration file or with the "set" or "reset" commands.
+</enum>
+
+<function>
+int feature_set(struct Client* from, const char* const* fields, int count);
+
+The feature_set() function takes an array of strings and a count of
+the number of strings in the array.  The first string is a feature
+name, and, for most features, the second string will be that feature's
+value.  The _from_ parameter is the struct Client describing the user
+that issued the "set" command.  This parameter may be NULL if
+feature_set() is being called from the configuration file subsystem.
+</function>
+
+<function>
+int feature_reset(struct Client* from, const char* const* fields, int count);
+
+The feature_reset() function is very similar in arguments to the
+feature_set() function, except that it may not be called from the
+configuration file subsystem.  It resets the named feature to its
+default value.
+</function>
+
+<function>
+int feature_get(struct Client* from, const char* const* fields, int count);
+
+Again, feature_get() is very similar in arguments to the feature_set()
+function, except that again it may not be called from the
+configuration file subsystem.  It reports the value of the named
+feature to the user that issued the "get" command.
+</function>
+
+<function>
+void feature_unmark(void);
+
+This function is used to unmark all feature values, as described in
+the subsection "Marking Features."  It takes no arguments and returns
+nothing.
+</function>
+
+<function>
+void feature_mark(void);
+
+The complement to feature_unmark(), feature_mark() resets all
+unchanged feature settings to their defaults.  See the subsection on
+"Marking Features."
+</function>
+
+<function>
+void feature_init(void);
+
+This function initializes the feature interface by setting the default
+values for all features correctly.
+</function>
+
+<function>
+void feature_report(struct Client* to);
+
+Reports all Feature entries to a user using RPL_STATSFLINE, except
+those which the user is not permitted to see due to flag settings.
+</function>
+
+<function>
+int feature_int(enum Feature feat);
+
+To retrieve the values of integer features, call this function.
+Calling this function on a different type of feature, such as a "BOOL"
+feature, will result in an assertion failure.
+</function>
+
+<function>
+int feature_bool(enum Feature feat);
+
+This function is the complement of feature_int() for features of type
+"BOOL."
+</function>
+
+<function>
+const char *feature_str(enum Feature feat);
+
+Use this function to retrieve strings values for features of type
+"STR"; you may not modify nor free the string value.
+</function>
+
+<macro>
+#define F_N(type, flags, set, reset, get, notify, unmark, mark, report)
+
+This macro is used in the features[] table to simplify defining a
+feature of type "NONE."  The _type_ parameter is the name of the
+feature excluding the "FEAT_" prefix, and MUST NOT be in
+double-quotes.  The _flags_ parameter may be 0, FEAT_OPER, or
+FEAT_MYOPER--the bitwise OR of these two flags is permissible but
+would not make sense.  The rest of the arguments are pointers to
+functions implementing the named call-back.
+</macro>
+
+<macro>
+#define F_I(type, flags, v_int, notify)
+
+To define integer features, use the F_I() macro.  The _type_ and
+_flags_ parameters are as for F_N(), and the _v_int_ parameter
+specifies the default value of the feature.  The _notify_ parameter,
+if non-zero, will be called whenever the value of the feature changes.
+</macro>
+
+<macro>
+#define F_B(type, flags, v_int, notify)
+
+This macro is used for defining features of type "BOOL"; it is very
+similar to F_I(), but _v_int_ should either 0 (for a "FALSE" value) or
+1 (for a "TRUE" value).  The _notify_ parameter, if non-zero, will be
+called whenever the value of the feature changes.
+</macro>
+
+<macro>
+#define F_S(type, flags, v_str, notify)
+
+Also similar to F_I(), F_S() defines features of type "STR."  The
+_flags_ argument may be the bitwise OR of one of FEAT_OPER or
+FEAT_MYOPER with the special string flags FEAT_NULL and FEAT_CASE,
+which are described above in the section "Feature Flags."  The
+_notify_ parameter, if non-zero, will be called whenever the value of
+the feature changes.  Note that FEAT_NULL *must* be set if the default
+string _v_str_ is set to NULL.
+</macro>
+
+<authors>
+Kev <klmitch@mit.edu>
+</authors>
+
+<changelog>
+[2001-06-13 Kev] Mention notify with the other callbacks
+
+[2001-01-02 Kev] Add documentation for new flags and for the notify
+mechanism
+
+[2000-12-18 Kev] Document the features API
+</changelog>
diff --git a/doc/api/gline.txt b/doc/api/gline.txt
new file mode 100644 (file)
index 0000000..4da9eb5
--- /dev/null
@@ -0,0 +1,283 @@
+Some users can be very annoying, as any IRC operator can attest.  Some
+can in fact be downright abusive.  Sometimes the best way of dealing
+with these users is to ban them from the entire network.  The G-line
+system permits this.
+
+G-lines are fairly complicated.  A G-line can be active or inactive,
+either locally or globally.  It can be a purely local G-line, or
+global.  It could be based on IP address or on host name.  In short,
+there are many variations on the basic G-line.  Worse, there is also
+the concept of a "bad channel," or BADCHAN, that has been tacked onto
+the G-line subsystem, when it should have been a separate command in
+the first place.
+
+Different types of G-lines are differentiated from each other through
+the use of various flags.  Some of these flags are maintained solely
+by the G-line subsystem, where as others are passed to various
+functions in the API.
+
+<macro>
+#define GLINE_MAX_EXPIRE 604800        /* max expire: 7 days */
+
+This macro lists the maximum expire time a G-line is permitted to
+have.  This value is limited to 7 days to prevent abuse of the system.
+</macro>
+
+<macro>
+#define GLINE_ACTIVE   0x0001
+
+This flag is used to indicate that a given G-line is globally active.
+</macro>
+
+<macro>
+#define GLINE_IPMASK   0x0002
+
+This flag is used to indicate that a given G-line is an IP mask.  This
+flag is maintained internally by the G-line subsystem.
+</macro>
+
+<macro>
+#define GLINE_BADCHAN  0x0004
+
+This flag is used to indicate that a given G-line specifies a BADCHAN,
+a channel that users are not permitted to join.  This flag is
+maintained internally, but is also used in gline_find() to search for
+a BADCHAN for a particular channel.
+</macro>
+
+<macro>
+#define GLINE_LOCAL    0x0008
+
+This flag is used to indicate that a given G-line is a local G-line.
+Local G-lines do not affect users on other servers.
+</macro>
+
+<macro>
+#define GLINE_ANY      0x0010
+
+This flag is passed to gline_find() to signal that function to return
+any G-line or BADCHAN that matches the passed mask string.  It is
+never set on a real G-line.
+</macro>
+
+<macro>
+#define GLINE_FORCE    0x0020
+
+This flag is passed to gline_add() to force the server to accept an
+expire time that might be out of bounds.  It is never set on a real
+G-line.
+</macro>
+
+<macro>
+#define GLINE_EXACT    0x0040
+
+This flag is passed to gline_find() to signal that function to return
+only G-lines that exactly match the passed mask string.  That is, the
+ircd_strcmp() function is called to compare the G-line to the mask,
+rather than the match() function.  This flag is never set on a real
+G-line.
+</macro>
+
+<macro>
+#define GLINE_LDEACT   0x0080  /* locally deactivated */
+
+This flag is set on global G-lines that have been locally
+deactivated.  This flag is maintained internally by the G-line
+subsystem.
+</macro>
+
+<macro>
+#define GLINE_GLOBAL   0x0100  /* find only global glines */
+
+This flag is passed to gline_find() or gline_lookup() to specify that
+the caller is only interested in global G-lines.  This flag is never
+set on a real G-line.
+</macro>
+
+<macro>
+#define GLINE_LASTMOD  0x0200  /* find only glines with non-zero lastmod */
+
+This flag is passed to gline_find() or gline_lookup() to specify that
+the caller is only interested in G-lines with a non-zero lastmod time,
+that is, G-lines that were not set by a U-lined service.  This flag is
+never set on a real G-line.
+</macro>
+
+<struct>
+struct Gline;
+
+The struct Gline describes everything about a given G-line.  None of
+its fields may be directly accessed by the application; use the
+functions and macros described below instead.
+</struct>
+
+<function>
+int GlineIsActive(struct Gline* g);
+
+This macro returns a non-zero value if the G-line is active, or 0
+otherwise.  If a G-line is locally deactivated, this macro will always
+return 0.
+</function>
+
+<function>
+int GlineIsRemActive(struct Gline* g);
+
+This macro returns a non-zero value if the G-line is active, ignoring
+whether or not it is locally deactivated.
+</function>
+
+<function>
+int GlineIsIpMask(struct Gline* g);
+
+This macro returns a non-zero value if the G-line is an IP mask.
+</function>
+
+<function>
+int GlineIsBadChan(struct Gline* g);
+
+This macro returns a non-zero value if a G-line actually represents a
+BADCHAN.
+</function>
+
+<function>
+int GlineIsLocal(struct Gline* g);
+
+This macro returns a non-zero value if a G-line is local only.
+</function>
+
+<function>
+char* GlineUser(struct Gline* g);
+
+This macro returns the user name associated with the G-line.  If the
+G-line represents a BADCHAN, this will contain the channel name.
+</function>
+
+<function>
+char* GlineHost(struct Gline* g);
+
+This macro returns the host name associated with the G-line.  If the
+G-line represents a BADCHAN, this will be a NULL pointer.
+</function>
+
+<function>
+char* GlineReason(struct Gline* g);
+
+This macro returns the reason that was given when the G-line was set.
+</function>
+
+<function>
+time_t GlineLastMod(struct Gline* g);
+
+G-lines that were not set by a U-lined service have a modification
+time that must be monotonically increasing.  This macro simply returns
+that modification time.
+</function>
+
+<function>
+int gline_propagate(struct Client *cptr, struct Client *sptr,
+                   struct Gline *gline);
+
+When a global G-line is set or modified, all other servers must be
+notified of the new G-line.  This function takes care of propagating
+the G-line specified by _gline_, originated by the client _sptr_, to
+all servers except _cptr_ (which may be a NULL pointer).
+</function>
+
+<function>
+int gline_add(struct Client *cptr, struct Client *sptr, char *userhost,
+             char *reason, time_t expire, time_t lastmod, unsigned int flags);
+
+This function simply adds a G-line, set by _sptr_ and with a
+_userhost_, _reason_, _expire_, and _lastmod_ as specified.  The
+_flags_ parameter is a bit mask consisting of the binary OR of
+GLINE_FORCE, GLINE_LOCAL, or GLINE_ACTIVE, as appropriate.  The
+gline_add() function also calls gline_propagate() to propagate the
+G-line, and kills off any local users matching the G-line if it is
+active.
+</function>
+
+<function>
+int gline_activate(struct Client *cptr, struct Client *sptr,
+                  struct Gline *gline, time_t lastmod, unsigned int flags);
+
+This function activates the G-line specified by _gline_, setting its
+_lastmod_ time as specified.  If _flags_ is GLINE_LOCAL and if the
+G-line is locally deactivated, this function will turn off the local
+deactivation flag, but will not modify _lastmod_.  If the G-line is
+globally deactivated, passing this function the GLINE_LOCAL flag will
+have no effect.
+</function>
+
+<function>
+int gline_deactivate(struct Client *cptr, struct Client *sptr,
+                    struct Gline *gline, time_t lastmod, unsigned int flags);
+
+This function is similar to gline_activate() except that it
+deactivates the G-line.  If the given G-line is local, or if it was
+set by a U-lined service (and GLINE_LOCAL was not passed via _flags_),
+then the G-line is deleted from memory.  In all other cases, the
+G-line is simply deactivated, either locally (if GLINE_LOCAL was
+passed via _flags_) or globally.  Global deactivation will update the
+_lastmod_ time.
+</function>
+
+<function>
+struct Gline *gline_find(char *userhost, unsigned int flags);
+
+This function looks up a G-line matching the given _userhost_ value,
+under control of the _flags_ parameter.  Valid _flags_ that may be
+passed are: GLINE_BADCHAN, GLINE_ANY, GLINE_GLOBAL, GLINE_LASTMOD, or
+GLINE_EXACT, each described above.
+</function>
+
+<function>
+struct Gline *gline_lookup(struct Client *cptr, unsigned int flags);
+
+This function looks up a G-line matching the given client, specified
+by _cptr_, under the control of the _flags_.  Valid values for _flags_
+are GLINE_GLOBAL and GLINE_LASTMOD, as described above.
+</function>
+
+<function>
+void gline_free(struct Gline *gline);
+
+This function releases all storage associated with a given G-line.
+</function>
+
+<function>
+void gline_burst(struct Client *cptr);
+
+This function generates a burst of all existing global G-lines and
+BADCHANs and sends them to the server specified by _cptr_.
+</function>
+
+<function>
+int gline_resend(struct Client *cptr, struct Gline *gline);
+
+This function resends the _gline_ to a server specified by _cptr_.
+This may be used if, for instance, it is discovered that a server is
+not synchronized with respect to a particular G-line.
+</function>
+
+<function>
+int gline_list(struct Client *sptr, char *userhost);
+
+This function sends the information about a G-line matching _userhost_
+to the client specified by _sptr_.  If _userhost_ is a NULL pointer, a
+list of all G-lines is sent.
+</function>
+
+<function>
+void gline_stats(struct Client *sptr);
+
+This function generates a list of all G-lines, sending them to the
+user _sptr_ by a /STATS G response.
+</function>
+
+<authors>
+Kev <klmitch@mit.edu>
+</authors>
+
+<changelog>
+[2001-6-15 Kev] Initial documentation for the G-line API.
+</changelog>
diff --git a/doc/api/ircd_snprintf.txt b/doc/api/ircd_snprintf.txt
new file mode 100644 (file)
index 0000000..ee9b7f2
--- /dev/null
@@ -0,0 +1,268 @@
+These functions are intended to be a complete replacement for sprintf
+and sprintf_irc.  They are a (nearly) complete reimplementation, and
+of course they're snprintf clones, making it more difficult for
+accidental buffer overflows to crop up.
+
+First off, what's missing?  These functions support all ANSI C
+conversion specifiers and selected ones from ISO 9x, with the
+exception of all floating-point conversions.  The floating-point
+conversions are tricky, and will likely be dependent on the
+representation of a floating-point number on a particular
+architecture.  While that representation is likely to conform to some
+standard, it is not currently used in ircu, so seemed like a good
+thing to omit, given the difficulty of implementing it.
+
+There are two more things missing from this implementation that would
+be required by ANSI; the first is support for multibyte character
+strings, and the second is support for locales, neither of which have
+any relevance for ircu, so again omission seemed to be a good policy.
+Additionally, %#x always causes '0x' (or '0X') to be printed, even if
+the number is zero.
+
+These functions also have some extensions not seen in a
+standards-compliant implementation; technically, the ISO 9x extensions
+fall into this category, for instance.  The ISO 9x extensions
+supported are type extensions--%ju, %tu, and %zu, for instance; %qu
+and %hhu are also supported.  The extensions added for use in ircu are
+%Tu, which takes a time_t, and the new %C conversion, which inserts
+either a numeric or a nick, dependent on the <dest> parameter.  The
+GNU %m extension, which inserts the strerror() string corresponding to
+the current value of errno, is also supported, as is a special %v
+extension, which essentially does a recursive call to ircd_snprintf.
+
+The following description is descended from the Linux man page for the
+printf family of functions.
+
+The format string is composed of zero or more directives: ordinary
+characters (not %), which are copied unchanged to the output stream;
+and conversion specifications, each of which results in fetching zero
+or more subsequent arguments.  Each conversion specification is
+introduced by the character %.  The arguments must correspond properly
+(after type promotion) with the conversion specifier.  After the %,
+the following appear in sequence:
+
+* Zero or more of the following flags:
+
+  #    specifying that the value should be converted to an "alternate
+       form."  For c, d, i, n, p, s, and u conversions, this option
+       has no effect.  For o conversions, the precision of the number
+       is increased to force the first character of the output string
+       to a zero (except if a zero value is printed with an explicit
+       precision of zero).  For x and X conversions, the string '0x'
+       (or '0X' for X conversions) is prepended to it.  For e, E, f,
+       g, and G conversions, the result will always contain a decimal
+       point, even if no digits follow it (normally, a decimal point
+       appears in the results of those conversions only if a digit
+       follows).  For g and G conversions, trailing zeros are not
+       removed from the result as they would otherwise be.  For C
+       conversions, if the destination is local and the origin is a
+       user, the nick!user@host form is used.
+
+  0    specifying zero padding.  For all conversions except n, the
+       converted value is padded on the left with zeros rather than
+       blanks.  If a precision is given with a numeric conversion (d,
+       i, o, u, i, x, and X), the 0 flag is ignored.
+
+  -    (a negative field width flag) indicates the converted value is
+       to be left adjusted on the field boundary.  Except for n
+       conversions, the converted value is padded on the right with
+       blanks, rather than on the left with blanks or zeros.  A -
+       overrides a 0 if both are given.
+
+ ' '   (a space) specifying that a blank should be left before a
+       positive number produced by a signed conversion (d, e, E, f,
+       g, G, or i).
+
+  +    specifying that a sign always be placed before a number
+       produced by a signed conversion.  A + overrides a space if
+       both are used.
+
+  :    specifying that a struct Client name should be preceded by a
+       ':' character if the destination is a user
+
+* An optional decimal digit string specifying a minimum field width.
+  If the converted value has fewer characters than the field width, it
+  will be padded with spaces on the left (or right, if the
+  left-adjustment flag has been given) to fill out the field width.
+
+* An optional precision, in the form of a period (`.') followed by an
+  optional digit string.  If the digit string is omitted, the
+  precision is taken as zero.  This gives the minimum number of digits
+  to appear for d, i, o, u, x, and X conversions, the number of digits
+  to appear after the decimal-point for e, E, and f conversions, the
+  maximum number of significant digits for g and G conversions, or the
+  maximum number of characters to be printed from a string for s
+  conversions.
+
+* The optional character h, specifying that a following d, i, o, u, x,
+  or X conversion corresponds to a short int or unsigned short int
+  argument, or that a following n conversion corresponds to a pointer
+  to a short int argument.  If the h character is given again, char is
+  used instead of short int.
+
+* The optional character l (ell) specifying that a following d, i, o,
+  u, x, or X conversion applies to a pointer to a long int or unsigned
+  long int argument, or that a following n conversion corresponds to a
+  pointer to a long int argument.
+
+* The character L specifying that a following e, E, f, g, or G
+  conversion corresponds to a long double argument, or a following d,
+  i, o, u, x, or X conversion corresponds to a long long argument.
+  Note that long long is not specified in ANSI C and therefore not
+  portable to all architectures.
+
+* The optional character q.  This is equivalent to L.
+
+* A j character specifying that the following integer (d, i, o, u, x,
+  or X) conversion corresponds to an intmax_t argument.
+
+* A t character specifying that the following integer (d, i, o, u, x,
+  or X) conversion corresponds to a ptrdiff_t argument.
+
+* A z character specifying that the following integer (d, i, o, u, x,
+  or X) conversion corresponds to a size_t argument.
+
+* A T character specifying that the following integer (d, i, o, u, x,
+  or X) conversion corresponds to a time_t argument.
+
+* A character that specifies the type of conversion to be applied.
+
+A field width or precision, or both, may be indicated by an asterisk
+`*' instead of a digit string.  In this case, an int argument supplies
+the field width or precision.  A negative field width is treated as a
+left adjustment flag followed by a positive field width; a negative
+precision is treated as though it were missing.
+
+The conversion specifiers and their meanings are:
+
+  diouxX       The int (or appropriate variant) argument is converted
+               to signed decimal (d and i), unsigned octal (o),
+               unsigned decimal (u), or unsigned hexadecimal (x and
+               X) notation.  The letters abcdef are used for x
+               conversions; the letters ABCDEF are used for X
+               conversions.  The precision, if any, gives the minimum
+               number of digits that must appear; if the converted
+               value requires fewer digits, it is padded on the left
+               with zeros.
+
+  eE           [NOT IMPLEMENTED] The double argument is rounded and
+               converted in the style [-]d.dddedd where there is one
+               digit before the decimal-point character and the
+               number of digits after it is equal to the precision;
+               if the precision is missing, it is taken as 6; if the
+               precision is zero, no decimal-point character
+               appears.  An E conversion uses the letter E (rather
+               than e) to introduce the exponent.  The exponent
+               always contains at least two digits; if the value is
+               zero, the exponent is 00.
+
+  f            [NOT IMPLEMENTED] The double argument is rounded and
+               converted to  decimal notation in the style
+               [-]ddd.ddd, where the number of digits after the
+               decimal-point character is equal to the precision
+               specification.  If the precision is missing, it is
+               taken as 6; if the precision is explicitly zero, no
+               decimal-point character appears.  If a decimal point
+               appears, at least one digit appears before it.
+
+  g            [NOT IMPLEMENTED] The double argument is converted in
+               style f or e (or E for G conversions).  The precision
+               specifies the number of significant digits.  If the
+               precision is missing, 6 digits are given; if the
+               precision is zero, it is treated as 1.  Style e is
+               used if the exponent from its conversion is less than
+               -4 or greater than or equal to the precision.
+               Trailing zeros are removed from the fractional part of
+               the result; a decimal point appears only if it is
+               followed by at least one digit.
+
+  c            The int argument is converted to an unsigned char, and
+               the resulting character is written.
+
+  s            The "char *" argument is expected to be a pointer to
+               an array of character type (pointer to a string).
+               Characters from the array are written up to (but not
+               including) a terminating NUL character; if a precision
+               is specified, no more than the number specified are
+               written.  If a precision is given, no null character
+               need be present; if the precision is not specified, or
+               is greater than the size of the array, the array must
+               contain a terminating NUL character.
+
+  p            The "void *" pointer argument is printed in
+               hexadecimal (as if by %#x or %#lx).
+
+  n            The number of characters written so far is stored into
+               the integer indicated by the ``int *'' (or variant)
+               pointer argument.  No argument is converted.
+
+  m            The error message associated with the current value of
+               errno is printed as if by %s.
+
+  C            The client argument identifier is printed under the
+               control of the <dest> argument; if <dest> is NULL or
+               is a user, the client's name (nickname or server name)
+               is printed; otherwise, the client's network numeric is
+               printed.
+
+  H            The channel argument identifier (channel name) is
+               printed.
+
+  v            The argument given must be a pointer to a struct
+               VarData with vd_format and vd_args must be initialized
+               appropriately.  On return, vd_chars will contain the
+               number of characters added to the buffer, and
+               vd_overflow will contain the number of characters that
+               could not be added due to buffer overflow or due to a
+               precision.
+
+  %            A `%' is written.  No argument is converted.  The
+               complete conversion specification is `%%'.
+
+In no case does a non-existent or small field width cause truncation
+of a field; if the result of a conversion is wider than the field
+width, the field is expanded to contain the conversion result.
+
+<struct>
+struct VarData {
+  size_t       vd_chars;       /* number of characters inserted */
+  size_t       vd_overflow;    /* number of characters that couldn't be */
+  const char   *vd_format;     /* format string */
+  va_list      vd_args;        /* arguments for %v */
+};
+
+This structure is used by the %v conversion specification.  The
+_vd_format_ element must contain a format string, and the _vd_args_
+element must be a variable argument list.  Upon return from
+ircd_snprintf() or ircd_vsnprintf(), the _vd_chars_ element will
+contain the number of characters that were able to be inserted, and
+the _vd_overflow_ element will contain the number of characters that
+could not be inserted.
+</struct>
+
+<function>
+int ircd_snprintf(struct Client *dest, char *buf, size_t buf_len,
+                 const char *format, ...);
+
+This formats the argument list, under control of the _format_, into
+the buffer specified by _buf_, the size of which is specified by
+_buf_len_.  The _dest_ parameter is used to determine whether to use a
+numeric or a nickname for %C conversions.
+</function>
+
+<function>
+int ircd_vsnprintf(struct Client *dest, char *buf, size_t buf_len,
+                  const char *format, va_list args);
+
+This function is identical to the ircd_snprintf() function except for
+the variable argument list given by _args_.
+</function>
+
+<authors>
+Kev <klmitch@mit.edu>
+</authors>
+
+<changelog>
+[2001-6-15 Kev] Initial documentation of the ircd_snprintf family of
+functions.
+</changelog>
diff --git a/doc/api/joinbuf.txt b/doc/api/joinbuf.txt
new file mode 100644 (file)
index 0000000..6eb7680
--- /dev/null
@@ -0,0 +1,92 @@
+IRC wouldn't be of much interest without the ability for users to join
+channels.  Of course, they must also be able to leave those channels
+when they get bored of the conversation there.  Users can join or
+leave multiple channels at once.  Sometimes these JOIN and PART
+messages can be ganged together into a single message.  This is
+facilitated by the JoinBuf system.
+
+<struct>
+struct JoinBuf;
+
+This structure is used to accumulate and describe several channel
+joins or parts.  None of its fields are directly or indirectly
+accessible to the application; a struct JoinBuf is only suitable for
+passing to the joinbuf_*() suite of functions.  JoinBuf structures
+must be allocated by the caller.
+</struct>
+
+<macro>
+#define JOINBUF_TYPE_JOIN      0       /* send JOINs */
+
+This macro tells joinbuf_init() that the JoinBuf is being used to
+generate several channel joins.
+</macro>
+
+<macro>
+#define JOINBUF_TYPE_CREATE    1       /* send CREATEs */
+
+This macro tells joinbuf_init() that the JoinBuf is being used to
+generate several channel creations.
+</macro>
+
+<macro>
+#define JOINBUF_TYPE_PART      2       /* send PARTs */
+
+This macro tells joinbuf_init() that the JoinBuf is being used to
+generate several channel parts.
+</macro>
+
+<macro>
+#define JOINBUF_TYPE_PARTALL   3       /* send local PARTs, but not remote */
+
+This macro tells joinbuf_init() that the JoinBuf is being used to
+record PARTs for all the user's channels.  That fact is communicated
+to servers through a more efficient means than sending several PARTs,
+but local clients can only be made aware of it with standard PART
+messages.
+</macro>
+
+<function>
+void joinbuf_init(struct JoinBuf *jbuf, struct Client *source,
+                 struct Client *connect, unsigned int type, char *comment,
+                 time_t create);
+
+This function is used to initialize a caller allocated JoinBuf,
+specified by _jbuf_.  The originating user is specified by _source_;
+the connection on which the message was received is specified by
+_connect_; the type (one of the JOINBUF_TYPE_* macros described above)
+is specified by _type_.  PART messages may have an optional comment,
+which is passed through the _comment_ parameter.  JOIN and CREATE
+messages require a timestamp, passed through the _create_ parameter.
+</function>
+
+<function>
+void joinbuf_join(struct JoinBuf *jbuf, struct Channel *chan,
+                 unsigned int flags);
+
+This function adds a channel to the JoinBuf.  The _chan_ parameter
+specifies the channel, and may only be NULL if the JoinBuf type is
+JOINBUF_TYPE_JOIN--this will cause a "JOIN 0" message to be sent to
+all servers.  The _flags_ parameter is used to specify the user's
+current channel flags.  For JOINBUF_TYPE_PART and JOINBUF_TYPE_PARTALL
+JoinBufs, passing CHFL_ZOMBIE will inhibit sending the PART to all
+channel users, and CHFL_BANNED will inhibit sending the user's
+specified PART comment.  For JOINBUF_TYPE_JOIN or JOINBUF_TYPE_CREATE
+JoinBufs, the _flags_ parameter is used to set the initial channel
+modes for the user.
+</function>
+
+<function>
+int joinbuf_flush(struct JoinBuf *jbuf);
+
+This function simply flushes the contents of the struct JoinBuf to the
+appropriate destinations.
+</function>
+
+<authors>
+Kev <klmitch@mit.edu>
+</authors>
+
+<changelog>
+[2001-6-15 Kev] Initial documentation of the JoinBuf subsystem.
+</changelog>
diff --git a/doc/api/jupe.txt b/doc/api/jupe.txt
new file mode 100644 (file)
index 0000000..c776a17
--- /dev/null
@@ -0,0 +1,161 @@
+Occasionally, a server will become incorrectly configured or will
+start behaving incorrectly.  Even more rarely, a server will be
+compromised, and a modified version of the server put in place to
+cause problems.  These cases are the reason for the _jupe_, a
+temporary server ban.  This is similar to the G-line, which is a
+temporary user ban, and indeed, the jupe API is very similar to the
+G-line API.
+
+<macro>
+#define JUPE_MAX_EXPIRE        604800  /* max expire: 7 days */
+
+This macro lists the maximum expire time a jupe is permitted to have.
+This value is limited to 7 days to prevent abuse of the system.
+</macro>
+
+<macro>
+#define JUPE_ACTIVE    0x0001
+
+This flag is used to indicate that a given jupe is globally active.
+</macro>
+
+<macro>
+#define JUPE_LOCAL     0x0002
+
+This flag is used to indicate that a given jupe is a local one.  Local
+jupes do not affect users on other servers.
+</macro>
+
+<macro>
+#define JUPE_LDEACT    0x0004  /* locally deactivated */
+
+This flag is set on global jupes that have been locally deactivated.
+This flag is maintained internally by the jupe subsystem.
+</macro>
+
+<struct>
+struct Jupe;
+
+The struct Jupe describes everything about a given jupe.  None of its
+fields may be directly accessed by the application; use the functions
+and macros described below instead.
+</struct>
+
+<function>
+int JupeIsActive(struct Jupe* j);
+
+This macro returns a non-zero value if the jupe is active, or 0
+otherwise.  If a jupe is locally deactivated, this macro will always
+return 0.
+</function>
+
+<function>
+int JupeIsRemActive(struct Jupe* j);
+
+This macro returns a non-zero value if the jupe is active, ignoring
+whether or not it is locally deactivated.
+</function>
+
+<function>
+int JupeIsLocal(struct Jupe* j);
+
+This macro returns a non-zero value if the jupe is local only.
+</function>
+
+<function>
+char* JupeServer(struct Jupe* j);
+
+This macro returns the server name associated with the jupe.
+</function>
+
+<function>
+char* JupeReason(struct Jupe* j);
+
+This macro returns the reason that was given when the jupe was set.
+</function>
+
+<function>
+time_t JupeLastMod(struct Jupe* j);
+
+Jupes have a modification time that must be monotonically increasing.
+This macro simply returns that modification time.
+</function>
+
+<function>
+int jupe_add(struct Client *cptr, struct Client *sptr, char *server,
+            char *reason, time_t expire, time_t lastmod, unsigned int flags);
+
+This function simply adds a jupe, set by _sptr_ and with a _server_,
+_reason_, _expire_, and _lastmod_ as specified.  The _flags_ parameter
+is a bit mask consisting of the binary OR of JUPE_LOCAL and
+JUPE_ACTIVE, as appropriate.  The jupe_add() function will propagate
+the jupe to all servers (assuming JUPE_LOCAL was not passed), and will
+break its link to the server specified by _server_ (assuming that the
+JUPE_ACTIVE flag _was_ passed).
+</function>
+
+<function>
+int jupe_activate(struct Client *cptr, struct Client *sptr, struct Jupe *jupe,
+                 time_t lastmod, unsigned int flags);
+
+This function activates the jupe specified by _jupe_, setting its
+_lastmod_ time as specified.  If _flags_ is JUPE_LOCAL and if the jupe
+is locally deactivated, this function will turn off the local
+deactivation flag, but will not modify _lastmod_.  If the jupe is
+globally deactivated, passing this function the JUPE_LOCAL flag will
+have no effect.
+</function>
+
+<function>
+int jupe_deactivate(struct Client *cptr, struct Client *sptr,
+                   struct Jupe *jupe, time_t lastmod, unsigned int flags);
+
+This function is similar to jupe_activate() except that it deactivates
+the jupe.  If the given jupe is local, then the jupe is deleted from
+memory.  In all other cases, the jupe is simply deactivated, either
+locally (if JUPE_LOCAL was passed via _flags_) or globally.  Global
+deactivation will update the _lastmod_ time.
+</function>
+
+<function>
+struct Jupe* jupe_find(char *server);
+
+This function searches for a jupe matching the given _server_.
+</function>
+
+<function>
+void jupe_free(struct Jupe *jupe);
+
+This function releases all storage associated with a given jupe.
+</function>
+
+<function>
+void jupe_burst(struct Client *cptr);
+
+This function generates a burst of all existing global jupes and sends
+them to the server specified by _cptr_.
+</function>
+
+<function>
+int jupe_resend(struct Client *cptr, struct Jupe *jupe);
+
+This function resends the _jupe_ to a server specified by _cptr_.
+This may be used if, for instance, it is discovered that a server is
+not synchronized with respect to a particular jupe.
+</function>
+
+<function>
+int jupe_list(struct Client *sptr, char *server);
+
+This function sends the information about a jupe matching _server_ to
+the client specified by _sptr_.  If _server_ is a NULL pointer, a list
+of all jupes is sent.
+</function>
+
+<authors>
+Kev <klmitch@mit.edu>
+</authors>
+
+<changelog>
+[2001-6-15 Kev] Initial documentation of the jupe API.
+</changelog>
diff --git a/doc/api/log.txt b/doc/api/log.txt
new file mode 100644 (file)
index 0000000..f7ac6c7
--- /dev/null
@@ -0,0 +1,240 @@
+Old versions of ircu did not have very good means of dealing with
+logging.  In u2.10.11, an entirely new logging subsystem was written,
+allowing a server administrator much more power in determining what
+actions are to be logged where.  The new logging subsystem permits log
+messages to go to syslog, to a file, and to server operators via
+server notices, simultaneously (though having output to multiple log
+files is not presently supported).
+
+All log messages have two values that are passed in with them: the
+logging level, which must be one of the values in enum LogLevel, and a
+logging subsystem, which must be one of the values in enum LogSys;
+these values are used as indexes into arrays within ircd_log.c, so be
+careful should you change them.
+
+In addition to the LogLevel and LogSys, there is also a set of three
+flags that may be passed to the log_write() logging function; these
+flags may be used to suppress certain types of logging that may be
+undesirable.  For instance, when a server links, a log may be written
+containing the server's IP address; to prevent this IP address from
+ever showing up in a server notice, that invocation of log_write() is
+passed the LOG_NOSNOTICE flag.
+
+<enum>
+enum LogLevel {
+  L_CRIT,
+  L_ERROR,
+  L_WARNING,
+  L_NOTICE,
+  L_TRACE,
+  L_INFO,
+  L_DEBUG,
+  L_LAST_LEVEL
+};
+
+This enum describes the severity levels of a log message.  The
+severity decreases as you proceed downwards in the list, so L_DEBUG is
+less severe than L_INFO, and L_CRIT in the most severe of all.  The
+special value L_LAST_LEVEL should never be used; it merely marks the
+end of the list.
+</enum>
+
+<enum>
+enum LogSys {
+  LS_SYSTEM, LS_CONFIG, LS_OPERMODE, LS_GLINE, LS_JUPE, LS_WHO, LS_NETWORK,
+  LS_OPERKILL, LS_SERVKILL, LS_USER, LS_OPER, LS_RESOLVER, LS_SOCKET,
+  LS_DEBUG, LS_OLDLOG,
+  LS_LAST_SYSTEM
+};
+
+These are the various logging subsystems recognized by the logging
+subsystem.  Again, order is important, and again, LS_LAST_SYSTEM
+should never be used.
+</enum>
+
+<function>
+void log_debug_init(int usetty);
+
+This initializes the special-purpose debug logging code in the
+server.  If the _usetty_ parameter is non-zero, then all debugging
+output will go to the terminal regardless of file settings for the
+LS_DEBUG subsystem.  This function is not defined unless the server is
+compiled with -DDEBUGMODE.
+</function>
+
+<function>
+void log_init(const char *process_name);
+
+This initializes the entire logging subsystem, including special
+things such as storing the process name and opening syslog with the
+open_log() function.  It may only be called once.
+</function>
+
+<function>
+void log_reopen(void);
+
+All log files are persistently open, in order to avoid the overhead of
+re-opening the log file each time.  This function is used to close all
+the log files and to close and reopen syslog.  (Log files are opened
+again only when there is something to write to them.)
+</function>
+
+<function>
+void log_close(void);
+
+This closes all log files and the syslog prior to the server
+terminating.  Should logs need to be reopened after calling this
+function, call log_reopen() instead of log_init().
+</function>
+
+<function>
+void log_write(enum LogSys subsys, enum LogLevel severity,
+              unsigned int flags, const char *fmt, ...);
+
+This is the actual logging function.  The _flags_ parameter is 0 or
+the bitwise OR of LOG_NOSYSLOG (suppresses syslogging), LOG_NOFILELOG
+(suppresses logging to a file) and LOG_NOSNOTICE (suppresses logging
+via server notices).  The _fmt_ parameter is a format string
+acceptable to ircd_snprintf(), which is the function called to
+actually format the log message.
+</function>
+
+<function>
+void log_vwrite(enum LogSys subsys, enum LogLevel severity,
+               unsigned int flags, const char *fmt, va_list vl);
+
+This is similar to log_write() except that it takes a va_list
+parameter.
+</function>
+
+<function>
+char *log_cannon(const char *subsys);
+
+This returns the canonical name for logging subsystem.  This probably
+should not be exposed here, but it is needed in ircd_features.c at
+present.
+</function>
+
+<function>
+int log_set_file(const char *subsys, const char *filename);
+
+This sets the file name for the specified logging subsystem to
+_filename_; returns 2 if the subsystem was undefined, 1 if the value
+of _filename_ was not understood, or 0 if there was no error.
+</function>
+
+<function>
+char *log_get_file(const char *subsys);
+
+This returns the current log file name for the given subsystem.
+</function>
+
+<function>
+int log_set_facility(const char *subsys, const char *facility);
+
+This sets the syslog facility for the specified logging subsystem to
+_facility_; returns 2 if the subsystem was undefined, 1 if the value
+of _facility_ was not understood, or 0 if there was no error.  Two
+special facility names may be given; "NONE" specifies that no
+syslogging should be performed, and "DEFAULT" specifies that ircd's
+default syslog facility should be used.
+</function>
+
+<function>
+char *log_get_facility(const char *subsys);
+
+This returns the current syslog facility for the given subsystem.  See
+the documentation for log_set_facility() for a description of the
+special facility names "NONE" and "DEFAULT."
+</function>
+
+<function>
+int log_set_snomask(const char *subsys, const char *snomask);
+
+This sets the server notice type for the specified logging subsystem
+to _snomask_; returns 2 if the subsystem was undefined, 1 if the value
+of _snomask_ was not understood, or 0 if there was no error.  The
+special server notice type "NONE" indicates that no server notices
+should be generated.  The other valid values for _snomask_ are:
+"OLDSNO," "SERVKILL," "OPERKILL," "HACK2," "HACK3," "UNAUTH,"
+"TCPCOMMON," "TOOMANY," "HACK4," "GLINE," "NETWORK," "IPMISMATCH,"
+"THROTTLE," "OLDREALOP," "CONNEXIT," and "DEBUG."
+</function>
+
+<function>
+char *log_get_snomask(const char *subsys);
+
+This returns the current server notice type for the given subsystem.
+See the documentation for log_set_snomask() for a description of the
+return values.
+</function>
+
+<function>
+int log_set_level(const char *subsys, const char *level);
+
+This function is used to set the minimum log level for a particular
+subsystem; returns 2 if the subsystem was undefined, 1 if the value of
+_level_ was not understood, or 0 if there was no error.  Any log
+notices generated with lower severity than that set with this function
+will not be logged.  Valid values are "CRIT," "ERROR," "WARNING,"
+"NOTICE," "TRACE," "INFO," and "DEBUG."
+</function>
+
+<function>
+char *log_get_level(const char *subsys);
+
+This returns the current minimum log level for the given subsystem.
+See the documentation for log_set_level() for a description of the
+return values.
+</function>
+
+<function>
+int log_set_default(const char *facility);
+
+This function sets the default syslog facility for all of ircd.  Valid
+values for _facility_ are as described for log_set_facility() with the
+exclusion of the "NONE" and "DEFAULT" facilities; returns 1 if the
+facility name was unrecognized (or proscribed) or 0 if there was no
+error.
+</function>
+
+<function>
+char *log_get_default(void);
+
+This simply returns ircd's default syslog facility.
+</function>
+
+<function>
+void log_feature_unmark(void);
+
+This function is called by the ircd_features.c subsystem and should
+not be called by any other part of ircd.  See the features API
+documentation for notes on what this function does.
+</function>
+
+<function>
+void log_feature_mark(int flag);
+
+This function is called by the ircd_features.c subsystem and should
+not be called by any other part of ircd.  See the features API
+documentation for notes on what this function does.
+</function>
+
+<function>
+void log_feature_report(struct Client *to, int flag);
+
+This function is called by the ircd_features.c subsystem and should
+not be called by any other part of ircd.  See the features API
+documentation for notes on what this function does.
+</function>
+
+<authors>
+Kev <klmitch@mit.edu>
+</authors>
+
+<changelog>
+[2001-06-13 Kev] Fix a minor typo.
+
+[2000-12-18 Kev] Wrote some documentation on how to use the logging
+subsystem.
+</changelog>
diff --git a/doc/api/modebuf.txt b/doc/api/modebuf.txt
new file mode 100644 (file)
index 0000000..87568cb
--- /dev/null
@@ -0,0 +1,282 @@
+Generating and parsing channel mode strings is often a very
+complicated process.  The ModeBuf interface, along with the associated
+mode parsing functions, attempt to make this much more programmatic.
+The interface to the functions in this suite is itself very
+complicated, unfortunately, though most of the complication is in the
+effects of various flags on the operation of the functions.
+
+<struct>
+struct ModeBuf;
+
+This structure is used to accumulate and describe several mode
+changes.  None of its fields are directly or indirectly accessible to
+the application; a struct ModeBuf is only suitable for passing to the
+modebuf_*() suite of functions.  ModeBuf structures must be allocated
+by the caller.
+</struct>
+
+<function>
+void modebuf_init(struct ModeBuf *mbuf, struct Client *source,
+                 struct Client *connect, struct Channel *chan,
+                 unsigned int dest);
+
+This function initializes a caller-allocated ModeBuf, _mbuf_, with the
+given parameters.  If the mode should not be sent to a particular
+server, perhaps because it was received from that server, that server
+should be specified by the _connect_ parameter.  The channel the mode
+change will take place on is given by the _chan_ parameter, and the
+disposition of the mode is given by the _dest_ parameter, which is the
+binary OR of the MODEBUF_DEST_* flags described below.
+</function>
+
+<macro>
+#define MODEBUF_DEST_CHANNEL   0x0001  /* Mode is flushed to channel */
+
+This flag, when set in a call to modebuf_init(), causes the accumulated
+mode change to be sent to the channel (in client<->server protocol, of
+course).
+</macro>
+
+<macro>
+#define MODEBUF_DEST_SERVER    0x0002  /* Mode is flushed to server */
+
+If other servers should be made aware of the mode change, this flag
+should be passed to modebuf_init().  One time when the mode change may
+not be passed is when processing the mode in a BURST message.
+</macro>
+
+<macro>
+#define MODEBUF_DEST_OPMODE    0x0100  /* Send server mode as OPMODE */
+
+This flag is used to tell the modebuf_*() suite to send an OPMODE
+message to other servers, rather than an ordinary MODE message.
+</macro>
+
+<macro>
+#define MODEBUF_DEST_DEOP      0x0200  /* Deop the offender */
+
+When bouncing a mode change, giving this flag to modebuf_init() causes
+the originating user to be deopped on the channel as part of the mode
+bounce.
+</macro>
+
+<macro>
+#define MODEBUF_DEST_BOUNCE    0x0400  /* Bounce the modes */
+
+When a mode change is illegitimate, that is, when it originates from a
+user that is not (as far as this server knows) a channel operator, the
+mode change should be bounced.  This involves reversing the sense of
+the mode and sending it back to the originating server.  This flag is
+used to tell the modebuf_*() suite to do just that.
+</macro>
+
+<macro>
+#define MODEBUF_DEST_LOG       0x0800  /* Log the mode changes to OPATH */
+
+The OPMODE command is reserved for IRC operators.  When it is used,
+the server should log the command for accountability purposes.  This
+flag, given to modebuf_init(), will cause the ModeBuf system to log
+the exact mode change to a log file.
+</macro>
+
+<macro>
+#define MODEBUF_DEST_HACK2     0x2000  /* Send a HACK(2) notice, reverse */
+
+When a remote user that this server does not think is a channel
+operator proceeds to change a channel mode, that mode must be
+bounced.  In addition, in order to provide some debugging capability,
+a server notice may be sent, called a "HACK(2)" notice.  Passing
+modebuf_init() this flag causes that notice to be sent.
+</macro>
+
+<macro>
+#define MODEBUF_DEST_HACK3     0x4000  /* Send a HACK(3) notice, TS == 0 */
+
+When the origin of a mode change is a server, we should always accept
+the mode change.  To provide accountability, however, a server notice
+should be sent.  This flag will cause the server to generate a
+"HACK(3)" notice.
+</macro>
+
+<macro>
+#define MODEBUF_DEST_HACK4     0x8000  /* Send a HACK(4) notice, TS == 0 */
+
+Some servers are special.  When a server that has a Uworld entry
+issues a mode change, we send a "HACK(4)" message to differentiate it
+from an ordinary server changing a channel mode.  This is the flag
+that must be passed to modebuf_init() to cause that behavior.
+</macro>
+
+<function>
+void modebuf_mode(struct ModeBuf *mbuf, unsigned int mode);
+
+Certain channel modes take no arguments.  Those mode changes can be
+fed to the ModeBuf system using modebuf_mode().  The _mode_ parameter
+is a bit mask of the mode changes, and must have one of MODE_ADD or
+MODE_DEL set.
+</function>
+
+<function>
+void modebuf_mode_uint(struct ModeBuf *mbuf, unsigned int mode,
+                      unsigned int uint);
+
+One channel mode, the "limit" mode ("+l"), takes a single integer
+argument.  This limit can be fed to the ModeBuf system with the
+modebuf_mode_uint() function.  The _mode_ parameter must be the binary
+OR of one of MODE_ADD or MODE_DEL with the MODE_LIMIT flag.  The
+_uint_ parameter specifies the limit.
+</function>
+
+<function>
+void modebuf_mode_string(struct ModeBuf *mbuf, unsigned int mode,
+                        char *string, int free);
+
+Some channel modes take a string parameter.  These can be fed to
+ModeBuf with modebuf_mode_string().  The _mode_ parameter should be
+the binary OR of one of MODE_ADD or MODE_DEL with the flag for the
+mode.  The _string_ parameter specifies the string, and the _free_
+parameter indicates whether the ModeBuf system should call MyFree() on
+the string once it is done with it.
+</function>
+
+<function>
+void modebuf_mode_client(struct ModeBuf *mbuf, unsigned int mode,
+                        struct Client *client);
+
+The remaining channel modes take a parameter specifying a client.
+These can be fed to ModeBuf with modebuf_mode_client().  The _mode_
+parameter should be the binary OR of one of MODE_ADD or MODE_DEL with
+the flag for the mode.  The _client_ parameter should be a pointer to
+a struct Client specifying which client the mode is supposed to act
+upon.
+</function>
+
+<function>
+int modebuf_flush(struct ModeBuf *mbuf);
+
+This function simply flushes the contents of the struct ModeBuf
+specified by _mbuf_ to the appropriate destinations, as was specified
+by the _dest_ parameter in the call to modebuf_init().  This function
+returns 0 for the convenience of callers that must return an integer.
+</function>
+
+<function>
+void modebuf_extract(struct ModeBuf *mbuf, char *buf);
+
+One use of the ModeBuf within ircd requires the ability to pull a
+simple mode string out of the struct ModeBuf for use elsewhere.  This
+can be accomplished with this function.  The _buf_ parameter should be
+large enough to accommodate the simple mode string.
+</function>
+
+<function>
+void mode_ban_invalidate(struct Channel *chan);
+
+Looking up bans affecting a particular user can be a fairly expensive
+operation, so the server caches the result of the lookup.  Should the
+ban list for a channel change, all the cached results must be
+invalidated to force rechecking.  This may be done with the
+mode_ban_invalidate() function, which acts upon the channel given by
+_chan_.
+</function>
+
+<function>
+void mode_invite_clear(struct Channel *chan);
+
+When a channel that was invite-only has the "+i" channel mode removed,
+the invite list that the server keeps is no longer necessary.  The
+mode_invite_clear() function flushes that invite list for the channel
+given by _chan_, reclaiming the memory used by the invite list.
+</function>
+
+<function>
+int mode_parse(struct ModeBuf *mbuf, struct Client *cptr, struct Client *sptr,
+              struct Channel *chptr, int parc, char *parv[],
+              unsigned int flags);
+
+This function parses a mode change command, given by the contents of
+_parv[]_, and under the control of _flags_.  The channel being modified
+is given by _chptr_, the source of the change is given by _sptr_, and
+the connection the change was received from is given by _cptr_.  The
+_parc_ parameter gives the count of the number of elements in the
+_parv[]_ array.  The ModeBuf must have already been initialized by a
+call to modebuf_init(), described above.  For more information on
+_flags_, see the MODE_PARSE_* macros described below.  This function
+returns an integer indicating the number of elements of _parv[]_ it
+used.  The modebuf_flush() function must be called upon return from
+mode_parse() to flush the mode changes to the channel.
+</function>
+
+<macro>
+#define MODE_PARSE_SET         0x01    /* actually set channel modes */
+
+When this flag is passed to mode_parse(), the channel mode being
+parsed will actually be effected on the channel.
+</macro>
+
+<macro>
+#define MODE_PARSE_STRICT      0x02    /* +m +n +t style not supported */
+
+Users are permitted to send complicated mode commands like "MODE #foo
++m +n +t +k foo +i"; servers are not.  Passing this flag to
+mode_parse() causes it to strictly enforce this restriction.
+</macro>
+
+<macro>
+#define MODE_PARSE_FORCE       0x04    /* force the mode to be applied */
+
+Some mode changes are not permitted under normal circumstances.  When
+this flag is passed to mode_parse(), these mode changes will be
+accepted.
+</macro>
+
+<macro>
+#define MODE_PARSE_BOUNCE      0x08    /* we will be bouncing the modes */
+
+This flag warns mode_parse() that the mode is to be bounced.  This
+will cause it to systematically feed each mode into ModeBuf in order
+for that interface to generate the proper bounce messages.
+</macro>
+
+<macro>
+#define MODE_PARSE_NOTOPER     0x10    /* send "not chanop" to user */
+
+This flag is used to warn mode_parse() that the user generating the
+mode change is not a channel operator.  If the user attempts to change
+a mode, an appropriate error message will be sent to the user (once).
+</macro>
+
+<macro>
+#define MODE_PARSE_NOTMEMBER   0x20    /* send "not member" to user */
+
+This flag is used to warn mode_parse() that the user generating the
+mode change is not even on the channel.  If the user attempts to
+change a mode, an appropriate error message will be sent to the user
+(once).
+</macro>
+
+<macro>
+#define MODE_PARSE_WIPEOUT     0x40    /* wipe out +k and +l during burst */
+
+When this flag is passed to mode_parse(), the channel key and limit
+will be reversed if the mode string doesn't update them.  This is used
+for processing BURST messages.
+</macro>
+
+<macro>
+#define MODE_PARSE_BURST       0x80    /* be even more strict w/extra args */
+
+The BURST message is even more strict than a standard MODE message.
+Processing *must* stop after reading the mode string itself, or
+mode_parse() could gobble up arguments not intended for it.  This flag
+tells mode_parse() about this restriction.
+</macro>
+
+<authors>
+Kev <klmitch@mit.edu>
+</authors>
+
+<changelog>
+[2001-6-15 Kev] Initial documentation of the ModeBuf and mode parsing
+subsystems.
+</changelog>
diff --git a/doc/api/motd.txt b/doc/api/motd.txt
new file mode 100644 (file)
index 0000000..d491162
--- /dev/null
@@ -0,0 +1,73 @@
+The server has a Message of the Day (MOTD) which is often used for
+describing the Acceptable Usage Policy, where to get help if you have
+problems, and so on.  Older versions of ircd had a lot of duplicated
+code, as well as some inefficiencies, all related to sending the
+MOTD.  As of u2.10.11, there is an API specifically for MOTDs.  This
+API caches the MOTDs in memory for efficiency.  Sending a MOTD to a
+client is as simple as calling a single function.
+
+<function>
+void motd_init(void);
+
+This function initializes the MOTD subsystem.  It will also read in
+the default MOTD (usually ircd.motd) and the remote MOTD (usually
+remote.motd) files.
+</function>
+
+<function>
+int motd_send(struct Client* cptr);
+
+This function sends an appropriate MOTD to the client specified by
+_cptr_.  If _cptr_ is not a local client, the remote MOTD will be
+sent; otherwise, an attempt will be made to find a Motd entry in the
+configuration file that matches the client.  If no Motd entry can be
+found, the default MOTD will be sent to the client.  This function
+returns 0 for the convenience of other functions that must have an
+integer return value.  </function>
+
+<function>
+void motd_signon(struct Client* cptr);
+
+This function is similar to motd_send(), described above, except that
+it will only send a message to the client indicating when the MOTD was
+last modified if the FEAT_NODEFAULTMOTD feature is set to TRUE.
+</function>
+
+<function>
+void motd_recache(void);
+
+The MOTD system will not automatically detect when MOTD files have
+been modified.  This function causes the MOTD system to clear the MOTD
+cache and re-read the files.
+</function>
+
+<function>
+void motd_add(const char *hostmask, const char *path);
+
+This function is used to add a MOTD to be sent to clients possessing a
+given _hostmask_.  If _hostmask_ is a numerical string, it is
+interpreted as a connection class.
+</function>
+
+<function>
+void motd_clear(void);
+
+This function clears the list of special MOTDs.  Only the default MOTD
+and remote MOTD are not affected by this function.
+</function>
+
+<function>
+void motd_report(struct Client *to);
+
+The motd_report() function sends a list of the Motd entries stored in
+memory to the client specified by _to_.  Access control should be
+handled by the caller.
+</function>
+
+<authors>
+Kev <klmitch@mit.edu>
+</authors>
+
+<changelog>
+[2001-6-15 Kev] Initial documentation of the MOTD interface.
+</changelog>
diff --git a/doc/api/msgq.txt b/doc/api/msgq.txt
new file mode 100644 (file)
index 0000000..cfa6ef6
--- /dev/null
@@ -0,0 +1,195 @@
+Many messages generated by an IRC server are sent to multiple
+recipients.  Previous versions of ircd used DBuf to store these
+messages until they could actually be sent.  The problem with using a
+DBuf for this, though, is that there are multiple copies of the same
+message hanging around.  Another problem is that there is at least one
+strcpy() or equivalent call for each destination the message is sent
+to.  A simple solution to this problem is to use messages queues.
+This file documents the MsgQ interface for ircd.
+
+The MsgQ interface is loosely based on the API for DBuf.  Although the
+structures are vastly different, most calls, including several of the
+macros, are similar to certain pieces of the DBuf API.  This made
+retrofitting ircd with MsgQ support much simpler.
+
+<struct>
+struct MsgCounts {
+  int alloc;
+  int used;
+};
+
+The MsgCounts structure may be used for determining how much memory is
+in use by the MsgQ system.  The _alloc_ element is a count of the
+total number of structures (of whatever type) that have been
+allocated; the _used_ element is a count of how many are actually in
+use.  MsgQ never releases any of its allocated memory; instead, it
+places unused structures onto a free list.
+</struct>
+
+<struct>
+struct MsgBuf;
+
+The MsgBuf structure contains the actual message, along with a
+reference count and the message's length.  None of its fields are
+directly accessible by the application.
+</struct>
+
+<struct>
+struct MsgQ;
+
+The MsgQ structure is a structure allocated by the application that is
+used by the MsgQ system to describe an entire message queue, including
+both normal and priority queues.  None of its fields are directly
+accessible by the application.
+</struct>
+
+<global>
+struct MsgCounts msgBufCounts; /* resource count for struct MsgBuf */
+
+This global variable counts the number of MsgBuf structures that have
+been allocated.  This may be used to determine how much memory is in
+use by the MsgQ system.
+</global>
+
+<global>
+struct MsgCounts msgCounts;    /* resource count for struct Msg */
+
+This global variable counts the number of Msg structures that have
+been allocated.  The Msg structure describes the link between a queue
+and a message.  It is not accessible to the application, and so not
+further documented here.
+</global>
+
+<function>
+unsigned int MsgQLength(struct MsgQ* mq);
+
+This macro returns the number of bytes in a particular user's message
+queue.
+</function>
+
+<function>
+unsigned int MsgQCount(struct MsgQ* mq);
+
+This macro returns the number of messages in a particular user's
+message queue.
+</function>
+
+<function>
+void MsgQClear(struct MsgQ* mq);
+
+This macro simply clears the content of a particular message queue.
+NOTE: This macro evaluates its argument twice.
+</function>
+
+<function>
+void msgq_init(struct MsgQ *mq);
+
+This function initializes a caller-allocated message queue to be
+empty.  Calling this function on a message queue with messages in it
+WILL RESULT IN A MEMORY LEAK.
+</function>
+
+<function>
+void msgq_delete(struct MsgQ *mq, unsigned int length);
+
+This function removes the given number of bytes from the message
+queue.  If entire messages have been sent, they will be unlinked from
+the queue.  The _length_ parameter does not need to correspond to a
+given message's length; the MsgQ system is able to deal with messages
+that have only partially been sent.
+</function>
+
+<function>
+int msgq_mapiov(const struct MsgQ *mq, struct iovec *iov, int count,
+               unsigned int *len);
+
+The msgq_mapiov() function takes a struct MsgQ (specified by the _mq_
+parameter) and a caller allocated struct iovec array (specified by the
+_iov_ parameter) and maps the contents of the message into the struct
+iovec array.  The _count_ parameter must indicate the total number of
+elements available for msgq_mapiov() to use.  The _len_ parameter must
+be a pointer to an unsigned int, and upon return from the function
+will contain the total number of bytes that have been mapped into the
+struct iovec array.  This function returns the number of struct iovec
+elements that have been filled.  For more information about the
+purpose of struct iovec, see your system's man page for the writev()
+function.
+</function>
+
+<function>
+struct MsgBuf *msgq_make(struct Client *dest, const char *format, ...);
+
+This function allocates a struct MsgBuf and calls ircd_vsnprintf()
+with the _dest_ and _format_ parameters to fill it in.  Most callers
+should use the send_buffer() function (declared in send.h) to attach
+the struct MsgBuf to a client's message queue.
+</function>
+
+<function>
+struct MsgBuf *msgq_vmake(struct Client *dest, const char *format, va_list vl);
+
+This function is identical to msgq_make() except that it takes a
+va_list (given by the _vl_ parameter) and calls ircd_vsnprintf() to
+format the message.
+</function>
+
+<function>
+void msgq_append(struct Client *dest, struct MsgBuf *mb, const char *format,
+                ...);
+
+Occasionally a caller is not able to completely compute a message
+before calling msgq_make().  When this happens, the msgq_append()
+function may be called to append more text onto the struct MsgBuf
+specified by the _mb_ parameter.  As with msgq_make(), the _dest_ and
+_format_ parameters are passed to ircd_vsnprintf(), along with the
+additional arguments.
+</function>
+
+<function>
+void msgq_clean(struct MsgBuf *mb);
+
+As mentioned above, struct MsgBuf includes a reference count.  When
+that reference count reaches zero, the structure is released.  The
+reference count is set to 1 by msgq_make() and msgq_vmake().  Once a
+given message has been attached to all the queues it needs to be, the
+caller should call the msgq_clean() function to decrement this
+reference count.  This function will place the struct MsgBuf back onto
+the free list if it did not get attached to any message queues.  The
+msgq_delete() function calls msgq_clean() internally, so the
+application need not call msgq_clean() explicitly afterwards.
+</function>
+
+<function>
+void msgq_add(struct MsgQ *mq, struct MsgBuf *mb, int prio);
+
+This function is used to attach a given struct MsgBuf, as specified by
+the _mb_ parameter, to a given message queue.  The _prio_ parameter,
+if non-zero, specifies that the message should be placed on the
+priority queue.  This function is called by send_buffer(), defined in
+send.h; most applications should call that function, rather than this
+one.
+</function>
+
+<function>
+void msgq_count_memory(size_t *msg_alloc, size_t *msg_used,
+                      size_t *msgbuf_alloc, size_t *msgbuf_used);
+
+This function simply takes the counts kept in msgBufCounts and
+msgCounts and multiplies them by the appropriate structure sizes,
+storing the resulting sizes into its parameters.
+</function>
+
+<function>
+unsigned int msgq_bufleft(struct MsgBuf *mb);
+
+This function is for use in conjunction with msgq_append().  It
+returns the total number of bytes of free storage in the given _mb_.
+</function>
+
+<authors>
+Kev <klmitch@mit.edu>
+</authors>
+
+<changelog>
+[2001-6-15 Kev] Initial documentation for the MsgQ functions.
+</changelog>
diff --git a/doc/api/privileges.txt b/doc/api/privileges.txt
new file mode 100644 (file)
index 0000000..dd8697a
--- /dev/null
@@ -0,0 +1,91 @@
+Access control becomes more of a problem as you have more and more
+users that need to access certain features.  As it stands, ircu has
+only 3 access levels: ordinary user, local operator, and global
+operator.  This is hardly enough control, especially over some of the
+more advanced and powerful features, such as G-lines.
+
+Since u2.10.11, ircu includes the concept of privileges.  Privileges
+are basically an arbitrarily long bit string.  Access to particular
+features is governed by the value of a particular bit of that bit
+string--in other words, privileges are a form of Access Control List.
+This document covers the basic structures and macros used by the
+privileges system.
+
+<struct>
+struct Privs;
+
+The Privs structure stores a privileges bit string and represents a
+user's entire privilege set.  This is implemented as a structure,
+rather than as an array of integers, in order to leverage C's
+structure copy.
+</struct>
+
+<function>
+void PrivSet(struct Privs pset, int priv);
+
+This macro sets the privilege specified by _priv_ in the privileges
+structure.  This macro evaluates the _priv_ argument twice.
+</function>
+
+<function>
+void PrivClr(struct Privs pset, int priv);
+
+This macro clears the privilege specified by _priv_ in the privileges
+structure.  This macro evaluates the _priv_ argument twice.
+</function>
+
+<function>
+int PrivHas(struct Privs pset, int priv);
+
+This macro tests whether the privilege specified by _priv_ is set in
+the privileges structure, returning non-zero if it is.  This macro
+evaluates the _priv_ argument twice.
+</function>
+
+<function>
+void GrantPriv(struct Client* cli, int priv);
+
+This macro grants a particular client, specified by _cli_, the
+privilege specified by _priv_.  This macro evaluates the _priv_
+argument twice.
+</function>
+
+<function>
+void RevokePriv(struct Client* cli, int priv);
+
+This macro revokes the privilege specified by _priv_ from the client.
+This macro evaluates the _priv_ argument twice.
+</function>
+
+<function>
+int HasPriv(struct Client* cli, int priv);
+
+This macro tests whether the client specified by _cli_ has the
+privilege specified by _priv_, returning non-zero if so.  This macro
+evaluates the _priv_ argument twice.
+</function>
+
+<function>
+void client_set_privs(struct Client* client);
+
+The ircu configuration file does not yet support privileges.  This
+function thus sets the appropriate privileges for an operator, based
+upon various feature settings.  It should be called whenever there is
+a change in a user's IRC operator status.
+</function>
+
+<function>
+int client_report_privs(struct Client *to, struct Client *client);
+
+This function sends the client specified by _to_ a list of the
+privileges that another client has.  It returns a value of 0 for the
+convenience of other functions that must return an integer value.
+</function>
+
+<authors>
+Kev <klmitch@mit.edu>
+</authors>
+
+<changelog>
+[2001-6-15 Kev] Initial documentation of the privileges system.
+</changelog>
diff --git a/doc/api/send.txt b/doc/api/send.txt
new file mode 100644 (file)
index 0000000..ebf09e8
--- /dev/null
@@ -0,0 +1,231 @@
+The send functions are perhaps the most important API in all of ircd;
+without them, communications would not be possible.  Most of these
+functions are pretty much stand-alone, although one or two are
+intended for use in conjunction with the MsgQ interface.  The send
+functions use the MsgQ interface internally, but for the most part,
+this fact is hidden from the caller.
+
+Command tokenization provides the greatest complication.  The
+functions do use ircd_snprintf() internally, so the use of numerics
+doesn't increase that complication.  The tokenization issue is dealt
+with by making each function accept two char* pointers, _cmd_ and
+_tok_, in that order, and then defining a CMD_* macro in msg.h that
+contains the message string and the token string in that order.  When
+one of these functions is called, it determines whether the
+destination will be a server or a user, then selects the correct one,
+either _cmd_ or _tok_, for that message.
+
+The MsgQ interface provides the concept of a priority queue; messages
+which must be sent as soon as possible, regardless of what other
+messages may already be in the queue.  The sendcmdto_prio_one() and
+sendcmdto_flag_butone() functions make use of this priority queue.
+The function send_buffer() also takes a _prio_ argument that should be
+non-zero if the message passed to it should be placed in the priority
+queue.
+
+<macro>
+#define SKIP_DEAF      0x01    /* skip users that are +d */
+
+This flag may be passed to sendcmdto_channel_butone() to cause a
+message passed by that function to skip users that are +d.  See the
+documentation for sendcmdto_channel_butone() for more information.
+</macro>
+
+<macro>
+#define SKIP_BURST     0x02    /* skip users that are bursting */
+
+This is another flag that may be passed to
+sendcmdto_channel_butone().  Its purpose is to cause the server to not
+send the message across a link that is still in the "burst" stage of
+network junction.  See the documentation for
+sendcmdto_channel_butone() for more information.
+</macro>
+
+<macro>
+#define SKIP_NONOPS    0x04    /* skip users that aren't chanops */
+
+Some messages may need to be passed only to channel operators.  This
+flag is passed to sendcmdto_channel_butone() when that is the case.
+See the documentation for sendcmdto_channel_butone() for more
+information.
+</macro>
+
+<function>
+void send_buffer(struct Client* to, struct MsgBuf* buf, int prio);
+
+Some applications may need to build a message piece by piece, directly
+utilizing the MsgQ interface.  The function send_buffer() is used when
+that message has been completed to place the message on a client's
+queue.  See the documentation for the MsgQ interface for more
+information about struct MsgBuf and the _buf_ parameter.
+</function>
+
+<function>
+void flush_connections(struct Client* cptr);
+
+This function attempts to send all queued data to a client specified
+by _cptr_.  If _cptr_ is 0, all clients with non-empty send queues
+will have their queues flushed.
+</function>
+
+<function>
+void send_queued(struct Client *to);
+
+This function attempts to send all queued data to a client specified
+by _to_.  The _to_ parameter is not permitted to be 0.  This is the
+function called by flush_connections().
+</function>
+
+<function>
+void sendrawto_one(struct Client *to, const char *pattern, ...);
+
+Most of the actual send functions in this API send their data with a
+prefix--the numeric of the origin.  This function is used when a
+message should be sent _without_ that prefix.  The caller must specify
+the complete message, including the exact command, with the _pattern_
+argument and the variable argument list following it.
+</function>
+
+<function>
+void sendcmdto_one(struct Client *from, const char *cmd, const char *tok,
+                  struct Client *to, const char *pattern, ...);
+
+This function is used for sending messages to specific clients.  The
+origin of the message is specified using the _from_ parameter; this
+will be used to formulate the origin.  As mentioned above, _cmd_ and
+_tok_ are used to determine the command and token to be used.  The
+_to_ parameter specifies which client the message should be sent to.
+The origin and command will be formatted and followed by a space; the
+given _pattern_ and the following arguments are passed to
+ircd_snprintf() for formatting.
+</function>
+
+<function>
+void sendcmdto_prio_one(struct Client *from, const char *cmd, const char *tok,
+                       struct Client *to, const char *pattern, ...);
+
+This function is identical to sendcmdto_one() except that messages
+formatted using it will be placed onto the priority queue.
+</function>
+
+<function>
+void sendcmdto_serv_butone(struct Client *from, const char *cmd,
+                          const char *tok, struct Client *one,
+                          const char *pattern, ...);
+
+This function treats its arguments similar to sendcmdto_one() does.
+Messages passed created with this function are sent to all directly
+linked servers except for the _one_ passed.  If _one_ is 0, the
+message is sent to all linked servers.
+</function>
+
+<function>
+void sendcmdto_common_channels(struct Client *from, const char *cmd,
+                              const char *tok, const char *pattern, ...);
+
+When a user quits IRC, all of the other users on the channels that the
+user is on must receive a single QUIT message.  This function formats
+the message, under control of _from_ (for the origin prefix), _cmd_
+and _tok_, and _pattern_ and the variable argument list, and sends
+that message to all local users on the same channels as the user
+specified by _from_.  This function does not send any messages across
+server<->server links.
+</function>
+
+<function>
+void sendcmdto_channel_butserv(struct Client *from, const char *cmd,
+                              const char *tok, struct Channel *to,
+                              const char *pattern, ...);
+
+This function is used to send a command to every local user on a
+particular channel, specified by _to_.  No messages are sent across
+the server<->server links.
+</function>
+
+<function>
+void sendcmdto_channel_butone(struct Client *from, const char *cmd,
+                             const char *tok, struct Channel *to,
+                             struct Client *one, unsigned int skip,
+                             const char *pattern, ...);
+
+This function is used mostly for sending PRIVMSG commands to
+particular channels.  The users that receive the message are under the
+control of the _skip_ parameter, which is a binary OR of the
+SKIP_DEAF, SKIP_BURST, and SKIP_NONOPS flags, depending on what
+channel users should see the message.  This function sends messages
+across both client<->server and server<->server links, as needed.  The
+client specified by _one_ will not receive a copy of the message.
+</function>
+
+<function>
+void sendcmdto_flag_butone(struct Client *from, const char *cmd,
+                          const char *tok, struct Client *one,
+                          unsigned int flag, const char *pattern, ...);
+
+This function is used for sending messages to clients with specific
+user modes set (specified by the _flag_ parameter).  Three flags make
+sense for this function: FLAGS_WALLOP (user mode +w), FLAGS_DEBUG
+(user mode +g), and FLAGS_OPER.  FLAGS_OPER has a special meaning that
+further restricts distribution of the message only to IRC operators.
+For the purposes of this function, no distinction is made between
+global operators and local operators.
+</function>
+
+<function>
+void sendcmdto_match_butone(struct Client *from, const char *cmd,
+                           const char *tok, const char *to,
+                           struct Client *one, unsigned int who,
+                           const char *pattern, ...);
+
+Certain kinds of global messages may be sent by IRC operators.  This
+function implements those global messages.  The _to_ parameter is used
+to specify a pattern by which to filter users, while _who_ specifies
+whether that pattern is to be applied to the user's server name or to
+the user's host name.  The _who_ parameter may be one of MATCH_SERVER
+or MATCH_HOST; these two macros are defined in s_user.h.  The _one_
+parameter will not receive a copy of the message.
+</function>
+
+<function>
+void sendto_opmask_butone(struct Client *one, unsigned int mask,
+                         const char *pattern, ...);
+
+The sendto_opmask_butone() function sends a server notice to all
+subscribing users except for _one_.  The _mask_ parameter is one of
+the SNO_* values defined in client.h and is used for selection of
+subscribing users.
+</function>
+
+<function>
+void vsendto_opmask_butone(struct Client *one, unsigned int mask,
+                          const char *pattern, va_list vl);
+
+The vsendto_opmask_butone() function is identical to the
+sendto_opmask_butone() function except that instead of a variable
+argument list, it takes a va_list, specified by _vl_.
+</function>
+
+<macro>
+#define SND_EXPLICIT   0x40000000      /* first arg is a pattern to use */
+
+When this flag, defined in ircd_reply.h, is combined with the _reply_
+argument to the send_reply() function, the format string send_reply()
+uses is obtained from the first argument in the variable argument list
+passed to that function, rather than from the table of replies.
+</macro>
+
+<function>
+int send_reply(struct Client* to, int reply, ...);
+
+The send_reply() function, declared in ircd_reply.h, is used to send
+clients numeric replies.  Unless SND_EXPLICIT is used, the pattern
+will be extracted from a table of replies.
+</function>
+
+<authors>
+Kev <klmitch@mit.edu>
+</authors>
+
+<changelog>
+[2001-6-15 Kev] Initial documentation for the send functions.
+</changelog>
diff --git a/doc/debug_memleak_gc.patch b/doc/debug_memleak_gc.patch
new file mode 100644 (file)
index 0000000..aeae128
--- /dev/null
@@ -0,0 +1,54 @@
+diff -rbud gc6.5/include/gc.h gc6.5.patched/include/gc.h
+--- gc6.5/include/gc.h Sat May 21 05:50:58 2005
++++ gc6.5.patched/include/gc.h Sat Jun 25 00:11:18 2005
+@@ -779,6 +779,11 @@
+ GC_API GC_PTR GC_call_with_alloc_lock
+               GC_PROTO((GC_fn_type fn, GC_PTR client_data));
++GC_API GC_warn_proc GC_set_warn_proc GC_PROTO((GC_warn_proc p));
++
++/* Sets the leak handler to be called when an object is leaked. */
++GC_API void GC_set_leak_handler(void (*lh)(void*, int));
++
+ /* The following routines are primarily intended for use with a       */
+ /* preprocessor which inserts calls to check C pointer arithmetic.    */
+ /* They indicate failure by invoking the corresponding _print_proc.   */
+diff -rbud gc6.5/reclaim.c gc6.5.patched/reclaim.c
+--- gc6.5/reclaim.c    Tue Nov 23 06:58:18 2004
++++ gc6.5.patched/reclaim.c    Sat Jun 25 00:52:18 2005
+@@ -36,6 +36,14 @@
+ GC_bool GC_have_errors = FALSE;
++static void (*leak_handler)(void*, int);
++
++void
++GC_set_leak_handler(void (*lh)(void*, int))
++{
++    leak_handler = lh;
++}
++
+ void GC_add_leaked(leaked)
+ ptr_t leaked;
+ {
+@@ -64,6 +72,12 @@
+     if (GC_debugging_started) GC_print_all_smashed();
+     for (i = 0; i < GC_n_leaked; ++i) {
+       ptr_t p = GC_leaked[i];
++        if (leak_handler)
++        {
++            leak_handler(GC_base(p), GC_size(GC_base(p)));
++        }
++        else
++        {
+       if (HDR(p) -> hb_obj_kind == PTRFREE) {
+           GC_err_printf0("Leaked atomic object at ");
+       } else {
+@@ -71,6 +85,7 @@
+       }
+       GC_print_heap_obj(p);
+       GC_err_printf0("\n");
++        }
+       GC_free(p);
+       GC_leaked[i] = 0;
+     }
diff --git a/doc/example.conf b/doc/example.conf
new file mode 100644 (file)
index 0000000..524b16e
--- /dev/null
@@ -0,0 +1,953 @@
+# ircd.conf - configuration file for ircd version ircu2.10
+#
+# Last Updated:  20, March 2002.
+#
+# Written by Niels <niels@undernet.org>, based on the original example.conf,
+# server code and some real-life (ahem) experience.
+#
+# Updated and heavily modified by Braden <dbtem@yahoo.com>.
+#
+# Rewritten by A1kmm(Andrew Miller)<a1kmm@mware.virtualave.net> to support
+# the new flex/bison configuration parser.
+#
+# Thanks and credits to: Run, Trillian, Cym, Morrissey, Chaos, Flynn,
+#                        Xorath, WildThang, Mmmm, SeKs, Ghostwolf and
+#                        all other Undernet IRC Admins and Operators,
+#                        and programmers working on the Undernet ircd.
+#
+# This is an example of the configuration file used by the Undernet ircd.
+#
+# This document is based on a (fictious) server in Europe with a
+# connection to the Undernet IRC network. It is primarily a leaf server,
+# but if all the other hubs in Europe aren't in service, it can connect
+# to one in the US by itself.
+#
+# The configuration format consists of a number of blocks in the format
+#  BlockName { setting = number; setting2 = "string"; setting3 = yes; };
+# Note that comments start from a #(hash) and go to the end of the line.
+# Whitespace(space, tab, or carriage return/linefeed) are ignored and may
+# be used to make the configuration file more readable.
+#
+# Please note that when ircd puts the configuration lines into practice,
+# it parses them exactly the other way round than they are listed here.
+# It uses the blocks in reverse order.
+#
+# This means that you should start your Client blocks with the
+# "fall through", most vanilla one, and end with the most detailed.
+#
+# There is a difference between the "hostname" and the "server name"
+# of the machine that the server is run on. For example, the host can
+# have "veer.cs.vu.nl" as FQDN, and "Amsterdam.NL.EU.undernet.org" as
+# server name.
+# A "server mask" is something like "*.EU.UnderNet.org", which is
+# matched by "Amsterdam.NL.EU.undernet.org" but not by
+# "Manhattan.KS.US.undernet.org".
+#
+# Please do NOT just rename the example.conf to ircd.conf and expect
+# it to work.
+
+
+# [General]
+#
+# First some information about the server.
+# General {
+#         name = "servername";
+#         vhost = "ipv4vhost";
+#         vhost = "ipv6vhost";
+#         description = "description";
+#         numeric = numericnumber;
+#         dns vhost = "ipv4vhost";
+#         dns vhost = "ipv6vhost";
+#         dns server = "ipaddress";
+#         dns server = "ipaddress2";
+# };
+#
+# If present, <virtual host> must contain a valid address in dotted
+# quad or IPv6 numeric notation (127.0.0.1 or ::1).  The address MUST
+# be the address of a physical interface on the host.  This address is
+# used for outgoing connections if the Connect{} block does not
+# override it.  See Port{} for listener virtual hosting.  If in doubt,
+# leave it out -- or use "*", which has the same meaning as no vhost.
+#
+# You may specify both an IPv4 virtual host and an IPv6 virtual host,
+# to indicate which address should be used for outbound connections
+# of the respective type.
+#
+# Note that <server numeric> has to be unique on the network your server
+# is running on, must be between 0 and 4095, and is not updated on a rehash.
+#
+# The two DNS lines allow you to specify the local IP address to use
+# for DNS lookups ("dns vhost") and one or more DNS server addresses
+# to use.  If the vhost is ambiguous for some reason, you may list
+# IPV4 and/or IPV6 between the equals sign and the address string.
+# The default DNS vhost is to let the operating system assign the
+# address, and the default DNS servers are read from /etc/resolv.conf.
+# In most cases, you do not need to specify either the dns vhost or
+# the dns server.
+General {
+         name = "London.UK.Eu.UnderNet.org";
+         description = "University of London, England";
+         numeric = 1;
+};
+
+# [Admin]
+#
+# This sets information that can be retrieved with the /ADMIN command.
+# It should contain at least an admin Email contact address.
+Admin {
+  # At most two location lines are allowed...
+  Location = "The University of London";
+  Location = "Undernet IRC server";
+  Contact = "IRC Admins <irc@london.ac.uk>";
+};
+
+# [Classes]
+#
+# All connections to the server are associated with a certain "connection
+# class", be they incoming or outgoing (initiated by the server), be they
+# clients or servers.
+#
+# Class {
+#  name = "<class>";
+#  pingfreq = time;
+#  connectfreq = time;
+#  maxlinks = number;
+#  sendq = size;
+#  usermode = "+i";
+# };
+#
+# For connection classes used on server links, maxlinks should be set
+# to either 0 (for hubs) or 1 (for leaf servers).  Client connection
+# classes may use maxlinks between 0 and approximately 4,000,000,000.
+# maxlinks = 0 means there is no limit on the number of connections
+# using the class.
+# 
+# <connect freq> applies only to servers, and specifies the frequency 
+# that the server tries to autoconnect. setting this to 0 will cause
+# the server to attempt to connect repeatedly with no delay until the 
+# <maximum links> condition is satisfied. This is a Bad Thing(tm).
+# Note that times can be specified as a number, or by giving something
+# like: 1 minutes 20 seconds, or 1*60+20.
+#
+# Recommended server classes:
+# All your server uplinks you are not a hub for.
+Class {
+ name = "Server";
+ pingfreq = 1 minutes 30 seconds;
+ connectfreq = 5 minutes;
+ maxlinks = 1;
+ sendq = 9000000;
+};
+# All the leaf servers you hub for.
+Class {
+ name = "LeafServer";
+ pingfreq = 1 minutes 30 seconds;
+ connectfreq = 5 minutes;
+ maxlinks = 0;
+ sendq = 9000000;
+};
+
+# Client {
+#  username = "ident";
+#  host = "host";
+#  ip = "127.0.0.0/8";
+#  password = "password";
+#  class = "classname";
+#  maxlinks = 3;
+# };
+#
+# Everything in a Client block is optional.  If a username mask is
+# given, it must match the client's username from the IDENT protocol.
+# If a host mask is given, the client's hostname must resolve and
+# match the host mask.  If a CIDR-style IP mask is given, the client
+# must have an IP matching that range.  If maxlinks is given, it is
+# limits the number of matching clients allowed from a particular IP
+# address.
+#
+# Take the following class blocks only as a guide.
+Class {
+ name = "Local";
+ pingfreq = 1 minutes 30 seconds;
+ sendq = 160000;
+ maxlinks = 100;
+ usermode = "+iw";
+};
+Class {
+ name = "America";
+ pingfreq = 1 minutes 30 seconds;
+ sendq = 80000;
+ maxlinks = 5;
+};
+Class {
+ name = "Other";
+ pingfreq = 1 minutes 30 seconds;
+ sendq = 160000;
+ maxlinks = 400;
+};
+Class {
+ name = "Opers";
+ pingfreq = 1 minutes 30 seconds;
+ sendq = 160000;
+ maxlinks = 10;
+
+ # For connection classes intended for operator use, you can specify
+ # privileges used when the Operator block (see below) names this
+ # class.  The local (aka globally_opered) privilege MUST be defined
+ # by either the Class or Operator block.  The following privileges
+ # exist:
+ #
+ # local (or propagate, with the opposite sense)
+ # whox  (log oper's use of x flag with /WHO)
+ # display (oper status visible to lusers)
+ # chan_limit (can join local channels when in
+ #                              MAXCHANNELSPERUSER channels)
+ # mode_lchan (can /MODE &channel without chanops)
+ # deop_lchan (cannot be deopped or kicked on local channels)
+ # walk_lchan (can forcibly /JOIN &channel OVERRIDE)
+ # show_invis (see +i users in /WHO x)
+ # show_all_invis (see +i users in /WHO x)
+ # unlimit_query (show more results from /WHO)
+ # local_kill (can kill clients on this server)
+ # rehash (can use /REHASH)
+ # restart (can use /RESTART)
+ # die (can use /DIE)
+ # local_jupe (not used)
+ # set (can use /SET)
+ # local_gline (can set a G-line for this server only)
+ # local_badchan (can set a Gchan for this server only)
+ # see_chan (can see users in +s channels in /WHO)
+ # list_chan (can see +s channels with /LIST S, or modes with /LIST M)
+ # wide_gline (can use ! to force a wide G-line)
+ # see_opers (can see opers without DISPLAY privilege)
+ # local_opmode (can use OPMODE/CLEARMODE on local channels)
+ # force_local_opmode (can use OPMODE/CLEARMODE on quarantined local channels)
+ # kill (can kill clients on other servers)
+ # gline (can issue G-lines to other servers)
+ # jupe_server (not used)
+ # opmode (can use /OPMODE)
+ # badchan (can issue Gchans to other servers)
+ # force_opmode (can use OPMODE/CLEARMODE on quarantined global channels)
+ # apass_opmode (can use OPMODE/CLEARMODE on +A and +U keys)
+ # umode_nochan (can set usermode +n to hide channels)
+ # umode_noidle (can set usermode +I to hide idle time)
+ # umode_chserv (can set umode +k)
+ # umode_xtraop (can set umode +X)
+ # umode_netserv (can set umode +S)
+ # umode_overridecc (Allow to set umode +c which overrides cmodes +cC)
+ # see_idletime (can see idletime of local +I users)
+ # hide_idletime (hides idle time also from users with see_idletime, unless they are on the same server and have this priv too)
+ # more_flood (has less throttling)
+ # unlimited_flood (no more excess floods)
+ # unlimited_targets (allow unlimited target changes)
+ # noamsg_override (can override cmode +M)
+ #
+ # For global opers (with propagate = yes or local = no), the default
+ # is to grant all of the above privileges EXCEPT walk_lchan,
+ # umode_chserv, umode_xtraop, umode_service,
+ # unlimit_query, set, badchan, local_badchan and apass_opmode.
+ # For local opers, the default is to grant ONLY the following
+ # privileges:
+ #  chan_limit, mode_lchan, show_invis, show_all_invis, local_kill,
+ #  rehash, local_gline, local_jupe, local_opmode, whox, display,
+ #  force_local_opmode, see_idletime, hide_channels, hide_idletime,
+ #  more_flood
+ # Any privileges listed in a Class block override the defaults.
+
+ local = no;
+};
+# [Client]
+#
+# To allow clients to connect, they need authorization. This can be
+# done based on hostmask, address mask, and/or with a password.
+# With intelligent use of classes and the maxconnections field in the
+# Client blocks, you can let in a specific domain, but get rid of all other
+# domains in the same toplevel, thus setting up some sort of "reverse
+# Kill block".
+# Client {
+#  host = "user@host";
+#  ip = "user@ip";
+#  password = "password";
+#  class = "classname";
+# };
+#
+# Technical description (for examples, see below):
+# For every connecting client, the IP address is known.  A reverse lookup
+# on this IP-number is done to get the (/all) hostname(s).
+# Each hostname that belongs to this IP-number is matched to <hostmask>,
+# and the Client {} is used when any matches; the client will then show
+# with this particular hostname.  If none of the hostnames match, then
+# the IP-number is matched against the <IP mask ...> field, if this matches
+# then the Client{} is used nevertheless and the client will show with the
+# first (main) hostname if any; if the IP-number did not resolve then the
+# client will show with the dot notation of the IP-number.
+# There is a special case for the UNIX domain sockets and localhost connections
+# though; in this case the <IP mask ...> field is compared with the
+# name of the server (thus not with any IP-number representation). The name
+# of the server is the one returned in the numeric 002 reply, for example:
+# 002 Your host is 2.undernet.org[jolan.ppro], running version ...
+# Then the "jolan.ppro" is the name used for matching.
+# Therefore, unix domain sockets, and connections to localhost would
+# match this block:
+# host = "*@jolan.ppro";
+#
+# This is the "fallback" entry. All .uk, .nl, and all unresolved are
+# in these two lines.
+# By using two different lines, multiple connections from a single IP
+# are only allowed from hostnames which have both valid forward and
+# reverse DNS mappings.
+Client
+{
+ class = "Other";
+ ip = "*@*";
+ maxlinks = 2;
+};
+
+
+Client
+{
+ class = "Other";
+ host = "*@*";
+ maxlinks = 2;
+};
+# If you don't want unresolved dudes to be able to connect to your
+# server, do not specify any "ip = " settings.
+#
+# Here, take care of all American ISPs.
+Client
+{
+ host = "*@*.com";
+ class = "America";
+ maxlinks = 2;
+};
+
+Client
+{
+ host = "*@*.net";
+ class = "America";
+ maxlinks = 2;
+};
+# Now list all the .com / .net domains that you wish to have access...
+# actually it's less work to do it this way than to do it the other
+# way around - K-lining every single ISP in the US.
+# I wish people in Holland just got a .nl domain, and not try to be
+# cool and use .com...
+Client { host = "*@*.wirehub.net"; class = "Other"; maxlinks=2; };
+Client { host = "*@*.planete.net"; class = "Other"; maxlinks=2; };
+Client { host = "*@*.ivg.com"; class = "Other"; maxlinks=2; };
+Client { host = "*@*.ib.com"; class = "Other"; maxlinks=2; };
+Client { host = "*@*.ibm.net"; class = "Other"; maxlinks=2; };
+Client { host = "*@*.hydro.com"; class = "Other"; maxlinks=2; };
+Client { host = "*@*.nl.net"; class = "Local"; maxlinks=2; };
+
+# You can request a more complete listing, including the "list of standard
+# Kill blocks" from the Routing Committee; it will also be sent to you if
+# you apply for a server and get accepted.
+#
+# Ourselves - this makes sure that we can get in, no matter how full
+# the server is (hopefully).
+Client
+{
+ host = "*@*.london.ac.uk";
+ ip = "*@193.37.*";
+ class = "Local";
+ # A maxlinks of over 5 will automatically be glined by euworld on Undernet
+ maxlinks = 5;
+};
+
+# You can put an expression in the maxlinks value, which will make ircd
+# only accept a client when the total number of connections to the network
+# from the same IP number doesn't exceed this number.
+# The following example would accept at most one connection per IP number
+# from "*.swipnet.se" and at most two connections from dial up accounts
+# that have "dial??.*" as host mask:
+# Client {
+#  host = "*@*.swipnet.se";
+#  maxlinks = 1;
+#  class = "Other";
+# };
+# Client {
+#  host = "*@dial??.*";
+#  maxlinks = 2;
+#  class = "Other";
+# };
+#
+# If you are not worried about who connects, this line will allow everyone
+# to connect.
+Client {
+ host = "*@*";
+ ip = "*@*";
+ class = "Other";
+ maxlinks = 2;
+};
+
+
+# [motd]
+#
+# It is possible to show a different Message of the Day to a connecting
+# client depending on its origin.
+# motd {
+#  # Note: host can also be a classname.
+#  host = "Other";
+#  file = "path/to/motd/file";
+# };
+#
+# More than one host = "mask"; entry may be present in one block; this
+# has the same effect as one Motd block for each host entry, but makes
+# it easier to update the messages's filename.
+#
+# DPATH/net_com.motd contains a special MOTD where users are encouraged
+# to register their domains and get their own client{} lines if they're in
+# Europe, or move to US.UnderNet.org if they're in the USA.
+motd {
+ host = "*.net";
+ file = "net_com.motd";
+};
+motd {
+ host = "*.com";
+ file = "net_com.motd";
+};
+motd {
+ host = "America";
+ file = "net_com.motd";
+};
+
+# A different MOTD for ourselves, where we point out that the helpdesk
+# better not be bothered with questions regarding irc...
+motd {
+ host = "*.london.ac.uk";
+ file = "london.motd";
+};
+
+# [UWorld]
+#
+# One of the many nice features of Undernet is "Uworld", a program
+# connected to the net as a server. This allows it to broadcast any mode
+# change, thus allowing opers to, for example, "unlock" a channel that
+# has been taken over.
+# There is only one slight problem: the TimeStamp protocol prevents this.
+# So there is a configuration option to allow them anyway from a certain
+# server.
+# UWorld {
+#  # The servername or wildcard mask for it that this applies to.
+#  name = "relservername";
+# };
+#
+# You may have have more than one name listed in each block.
+#
+# Note: (1) These lines are agreed on by every server admin on Undernet;
+# (2) These lines must be the same on every single server, or results
+# will be disasterous; (3) This is a useful feature, not something that
+# is a liability and abused regularly (well... :-)
+# If you're on Undernet, you MUST have these lines. I cannnot stress
+# this enough.  If all of the servers don't have the same lines, the
+# servers will try to undo the mode hacks that Uworld does.  Make SURE that
+# all of the servers have the EXACT same UWorld blocks.
+#
+# If your server starts on a bit larger network, you'll probably get
+# assigned one or two uplinks to which your server can connect.
+# If your uplink(s) also connect to other servers than yours (which is
+# probable), you need to define your uplink as being allowed to "hub".
+# See the Connect block documentation for details on how to do that.
+
+UWorld {
+ name = "uworld.eu.undernet.org";
+ name = "uworld2.undernet.org";
+ name = "uworld.undernet.org";
+ name = "channels.undernet.org";
+ name = "channels2.undernet.org";
+ name = "channels3.undernet.org";
+ name = "channels4.undernet.org";
+ name = "channels5.undernet.org";
+ name = "channels6.undernet.org";
+};
+
+# As of ircu2.10.05 is it possible to Jupe nicks. As per CFV-0095 and
+# CFV-0255, the following nicks must be juped, it is not allowed to
+# jupe others as well.
+Jupe {
+ nick = "A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,{,|,},~,-,_,`";
+ nick = "EuWorld,UWorld,UWorld2";
+ nick = "login,undernet,protocol,pass,newpass,org";
+ nick = "StatServ,NoteServ";
+ nick = "ChanSvr,ChanSaver,ChanServ";
+ nick = "NickSvr,NickSaver,NickServ";
+ nick = "LPT1,LPT2,COM1,COM2,COM3,COM4,AUX";
+};
+
+# [Kill]
+#
+# While running your server, you will most probably encounter individuals
+# or groups of persons that you do not wish to have access to your server.
+#
+# For this purpose, the ircd understands "kill blocks". These are also
+# known as K-lines, by virtue of the former config file format.
+# Kill
+# {
+#   host = "user@host";
+#   reason = "The reason the user will see";
+# };
+# It is possible to ban on the basis of the real name.
+# It is also possible to use a file as comment for the ban, using
+# file = "file":
+# Kill
+# {
+#   realname = "realnametoban";
+#   file = "path/to/file/with/reason/to/show";
+# };
+#
+#
+# The default reason is: "You are banned from this server"
+# Note that Kill blocks are local to the server; if you ban a person or a
+# whole domain from your server, they can get on IRC via any other server
+# that doesn't have them Killed (yet).
+#
+# With a simple comment, using quotes:
+Kill { host = "*.au"; reason = "Please use a nearer server"; };
+Kill { host = "*.edu"; reason = "Please use a nearer server"; };
+
+# You can also kill based on username.
+Kill { username = "sub7"; realname = "s*7*"; reason = "You are infected with a Trojan"; };
+
+# The file can contain for example, a reason, a link to the
+# server rules and a contact address.  Note the combination
+# of username and host in the host field.
+Kill
+{
+ host = "*luser@unixbox.flooder.co.uk";
+ file = "kline/youflooded.txt";
+};
+
+# IP-based kill lines apply to all hosts, even if an IP address has a
+# properly resolving host name.
+Kill
+{
+ host = "192.168.*";
+ file = "klines/martians";
+};
+
+# The realname field lets you ban by realname...
+Kill
+{
+ realname = "*sub7*";
+ reason = "You are infected with a Trojan";
+};
+
+# [Connect]
+#
+# You probably want your server connected to other servers, so your users
+# have other users to chat with.
+# IRC servers connect to other servers forming a network with a star or
+# tree topology. Loops are not allowed.
+# In this network, two servers can be distinguished: "hub" and "leaf"
+# servers. Leaf servers connect to hubs; hubs connect to each other.
+# Of course, many servers can't be directly classified in one of these
+# categories. Both a fixed and a rule-based decision making system for
+# server links is provided for ircd to decide what links to allow, what
+# to let humans do themselves, and what links to (forcefully) disallow.
+#
+# The Connect blocks
+# define what servers the server connect to, and which servers are
+# allowed to connect.
+# Connect {
+#  name = "servername";
+#  host = "hostnameORip";
+#  vhost = "localIP";
+#  password = "passwd";
+#  port = portno;
+#  class = "classname";
+#  maxhops = 2;
+#  hub = "*.eu.undernet.org";
+#  autoconnect = no;
+# };
+#
+# The "port" field defines the default port the server tries to connect
+# to if an operator uses /connect without specifying a port. This is also
+# the port used when the server attempts to auto-connect to the remote
+# server. (See Class blocks for more informationa about auto-connects).
+# You may tell ircu to not automatically connect to a server by adding
+# "autoconnect = no;"; the default is to autoconnect.
+#
+# If the vhost field is present, the server will use that IP as the
+# local end of connections that it initiates to this server.  This
+# overrides the vhost value from the General block.
+#
+# The maxhops field causes an SQUIT if a hub tries to introduce
+# servers farther away than that; the element 'leaf;' is an alias for
+# 'maxhops = 0;'.  The hub field limits the names of servers that may
+# be introduced by a hub; the element 'hub;' is an alias for
+# 'hub = "*";'.
+#
+# Our primary uplink.
+Connect {
+ name = "Amsterdam.NL.Eu.UnderNet.org";
+ host = "1.2.3.4";
+ password = "passwd";
+ port = 4400;
+ class = "Server";
+ hub;
+};
+
+# [crule]
+#
+# For an advanced, real-time rule-based routing decision making system
+# you can use crule blocks. For more information, see doc/readme.crules.
+# If more than one server mask is present in a single crule, the rule
+# applies to all servers.
+# CRULE
+# {
+#  server = "servermask";
+#  rule = "connectrule";
+#  # Setting all to yes makes the rule always apply. Otherwise it only
+#  # applies to autoconnects.
+#  all = yes;
+# };
+CRULE
+{
+ server = "*.US.UnderNet.org";
+ rule = "connected(*.US.UnderNet.org)";
+};
+CRULE
+{
+ server = "*.EU.UnderNet.org";
+ rule = "connected(Amsterdam.NL.EU.*)";
+};
+
+# The following block is recommended for leaf servers:
+CRULE
+{
+ server = "*";
+ rule = "directcon(*)";
+};
+
+# [Operator]
+#
+# Inevitably, you have reached the part about "IRC Operators". Oper status
+# grants some special privileges to a user, like the power to make the
+# server break or (try to) establish a connection with another server,
+# and to "kill" users off IRC.
+# I can write many pages about this; I will restrict myself to saying that
+# if you want to appoint somebody as IRC Operator on your server, that
+# person should be aware of his/her responsibilities, and that you, being
+# the admin, will be held accountable for their actions.
+#
+# There are two sorts of IRC Operators: "local" and "global". Local opers
+# can squit, connect and kill - but only locally: their +o user mode
+# is not not passed along to other servers. On Undernet, this prevents
+# them from using Uworld as well.
+#
+# More than one host = "mask"; entry may be present in one block; this
+# has the same effect as one Operator block for each host entry, but
+# makes it easier to update operator nicks, passwords, classes, and
+# privileges.
+#
+# Operator {
+#  host = "host/IP mask";
+#  name = "opername";
+#  password = "encryptedpass";
+#  class = "classname";
+#  # You can also set any operator privilege; see the Class block
+#  # documentation for details.  A privilege defined for a single
+#  # Operator will override the privilege settings for the Class
+#  # and the default setting.
+# };
+#
+# By default, the password is hashed using the system's native crypt()
+# function.  Other password mechanisms are available; the umkpasswd
+# utility from the ircd directory can hash passwords using those
+# mechanisms.  If you use a password format that is NOT generated by
+# umkpasswd, ircu will not recognize the oper's password.
+#
+# All privileges are shown with their default values; if you wish to
+# override defaults, you should set only those privileges for the
+# operator.  Listing defaulted privileges just makes things harder to
+# find.
+Operator {
+ local = no;
+ host = "*@*.cs.vu.nl";
+ password = "VRKLKuGKn0jLt";
+ name = "Niels";
+ class = "Local";
+};
+Operator {
+ host = "*@*.uu.net";
+ password = "$PLAIN$notencryptedpass";
+ name = "Niels";
+ class = "Opers";
+};
+
+# Note that the <connection class> is optional, but leaving it away
+# puts the opers in class "default", which usually only accepts one
+# connection at a time.  If you want users to Oper up more then once per
+# block, then use a connection class that allows more then one connection,
+# for example (using class Local as in the example above):
+#
+# Once you OPER your connection class changes no matter where you are or
+# your previous connection classes.  If the defined connection class is
+# Local for the operator block, then your new connection class is Local.
+
+# [Port]
+# When your server gets more full, you will notice delays when trying to
+# connect to your server's primary listening port. It is possible via the
+# Port lines to specify additional ports for the ircd to listen to.
+# De facto ports are: 6667 - standard; 6660-6669 - additional client
+# ports;
+# Undernet uses 4400 for server listener ports.
+# These are just hints, they are in no way official IANA or IETF policies.
+# IANA says we should use port 194, but that requires us to run as root,
+# so we don't do that.
+#
+#
+# Port {
+#  port = [ipv4] [ipv6] number;
+#  mask = "ipmask";
+#  # Use this to control the interface you bind to.
+#  vhost = [ipv4] [ipv6] "virtualhostip";
+#  # You can specify both virtual host and port number in one entry.
+#  vhost = [ipv4] [ipv6] "virtualhostip" number;
+#  # Setting to yes makes this server only.
+#  server = yes;
+#  # Setting to yes makes the port "hidden" from stats.
+#  hidden = yes;
+# };
+#
+# The port and vhost lines allow you to specify one or both of "ipv4"
+# and "ipv6" as address families to use for the port.  The default is
+# to listen on both IPv4 and IPv6.
+#
+# The mask setting allows you to specify a range of IP addresses that
+# you will allow connections from. This should only contain IP addresses
+# and '*' if used. This field only uses IP addresses. This does not use
+# DNS in any way so you can't use it to allow *.nl or *.uk. Attempting
+# to specify anything other than numbers, dots and stars [0-9.*] will result
+# in the port allowing connections from anyone.
+#
+# The interface setting allows multiply homed hosts to specify which
+# interface to use on a port by port basis, if an interface is not specified
+# the default interface will be used. The interface MUST be the complete
+# IP address for a real hardware interface on the machine running ircd.
+# If you want to use virtual hosting *YOU* *MUST* *USE* *THIS* otherwise it
+# WILL bind to all interfaces - not what most people seem to expect.
+#
+Port {
+ server = yes;
+ port = 4400;
+};
+
+# This is an IPv4-only Server port that is Hidden
+Port {
+ server = yes;
+ hidden = yes;
+ port = ipv4 4401;
+};
+
+# The following are normal client ports
+Port { port = 6667; };
+Port { port = 6668; };
+Port {
+ # This only accepts clients with IPs like 192.168.*.
+ mask = "192.168.*";
+ port = 6666;
+};
+
+# This is a hidden client port, listening on 168.8.21.107.
+Port {
+ vhost = "168.8.21.107";
+ hidden = yes;
+ port = 7000;
+};
+
+# More than one vhost may be present in a single Port block; in this case,
+# we recommend listing the port number on the vhost line for clarity.
+Port {
+ vhost = "172.16.0.1" 6667;
+ vhost = "172.16.3.1" 6668;
+ hidden = no;
+};
+
+# Quarantine blocks disallow operators from using OPMODE and CLEARMODE
+# on certain channels.  Opers with the force_opmode (for local
+# channels, force_local_opmode) privilege may override the quarantine
+# by prefixing the channel name with an exclamation point ('!').
+# Wildcards are NOT supported; the channel name must match exactly.
+Quarantine {
+  "#shells" = "Thou shalt not support the h4><0rz";
+  "&kiddies" = "They can take care of themselves";
+};
+
+# This is a server-implemented alias to send a message to a service.
+# The string after Pseudo is the command name; the name entry inside
+# is the service name, used for error messages.  More than one nick
+# entry can be provided; the last one listed has highest priority.
+# If the server behind the '@' is not valid or if the nick is not
+# on this server, the servername is interpreted as an accountname
+# and the nick must have this accountname set and +S as umode to get
+# the message relayed.
+Pseudo "CHANSERV" {
+ name = "X";
+ nick = "X@channels.undernet.org";
+};
+
+# You can also prepend text before the user's message.
+Pseudo "LOGIN" {
+ name = "X";
+ prepend = "LOGIN ";
+ nick = "X@channels.undernet.org";
+};
+
+# You can ask a separate server whether to allow users to connect.
+# Uncomment this ONLY if you have an iauth helper program.
+# If required is set to yes, then all clients are rejected when
+# the iauth helper program could not be started/queried/timed-out.
+# IAuth {
+#  program = "../path/to/iauth" "-n" "options go here";
+#  required = no;
+# };
+
+# [features]
+# IRC servers have a large number of options and features.  Most of these
+# are set at compile time through the use of #define's--see "make config"
+# for more details--but we are working to move many of these into the
+# configuration file.  Features let you configure these at runtime.
+# You only need one feature block in which you use
+# "featurename" = "value1" , "value2", ..., "valuen-1", "valuen";
+#
+# The entire purpose of F:lines are so that you do not have to recompile
+# the IRCD everytime you want to change a feature.  All of the features
+# are listed below, and at the bottom is how to set logging.
+#
+# A Special Thanks to Kev for writing the documentation of F:lines.  It can
+# be found at doc/readme.features and the logging documentation can be
+# found at doc/readme.log.  The defaults used by the Undernet network are
+# below.
+#
+features
+{
+# These log features are the only way to get certain error messages
+# (such as when the server dies from being out of memory).  For more
+# explanation of how they work, see doc/readme.log.
+ "LOG" = "SYSTEM" "FILE" "ircd.log";
+ "LOG" = "SYSTEM" "LEVEL" "CRIT";
+#  "DOMAINNAME"="<obtained from /etc/resolv.conf by ./configure>";
+#  "RELIABLE_CLOCK"="FALSE";
+#  "BUFFERPOOL"="27000000";
+#  "HAS_FERGUSON_FLUSHER"="FALSE";
+#  "CLIENT_FLOOD"="1024";
+#  "SERVER_PORT"="4400";
+#  "NODEFAULTMOTD"="TRUE";
+#  "MOTD_BANNER"="TRUE";
+#  "KILL_IPMISMATCH"="FALSE";
+#  "IDLE_FROM_MSG"="TRUE";
+#  "HUB"="FALSE";
+#  "WALLOPS_OPER_ONLY"="FALSE";
+#  "NODNS"="FALSE";
+#  "RANDOM_SEED"="<you should set one explicitly>";
+#  "DEFAULT_LIST_PARAM"="TRUE";
+#  "NICKNAMEHISTORYLENGTH"="800";
+#  "NETWORK"="UnderNet";
+#  "HOST_HIDING"="FALSE";
+#  "HIDDEN_HOST"="users.undernet.org";
+#  "HIDDEN_IP"="127.0.0.1";
+#  "KILLCHASETIMELIMIT"="30";
+#  "MAXCHANNELSPERUSER"="10";
+#  "NICKLEN" = "12";
+#  "AVBANLEN"="40";
+#  "MAXBANS"="30";
+#  "MAXSILES"="15";
+#  "HANGONGOODLINK"="300";
+# "HANGONRETRYDELAY" = "10";
+# "CONNECTTIMEOUT" = "90";
+# "MAXIMUM_LINKS" = "1";
+# "PINGFREQUENCY" = "120";
+# "CONNECTFREQUENCY" = "600";
+# "DEFAULTMAXSENDQLENGTH" = "40000";
+# "GLINEMAXUSERCOUNT" = "20";
+# "MPATH" = "ircd.motd";
+# "RPATH" = "remote.motd";
+# "PPATH" = "ircd.pid";
+# "TOS_SERVER" = "0x08";
+# "TOS_CLIENT" = "0x08";
+# "POLLS_PER_LOOP" = "200";
+# "IRCD_RES_TIMEOUT" = "4";
+# "IRCD_RES_RETRIES" = "2";
+# "AUTH_TIMEOUT" = "9";
+# "IPCHECK_CLONE_LIMIT" = "4";
+# "IPCHECK_CLONE_PERIOD" = "40";
+# "IPCHECK_CLONE_DELAY" = "600";
+# "CHANNELLEN" = "200";
+# "CONFIG_OPERCMDS" = "FALSE";
+# "OPLEVELS" = "TRUE";
+# "ZANNELS" = "TRUE";
+# "LOCAL_CHANNELS" = "TRUE";
+# "ANNOUNCE_INVITES" = "FALSE";
+#  These were introduced by Undernet CFV-165 to add "Head-In-Sand" (HIS)
+#  behavior to hide most network topology from users.
+#  "HIS_SNOTICES" = "TRUE";
+#  "HIS_SNOTICES_OPER_ONLY" = "TRUE";
+#  "HIS_DEBUG_OPER_ONLY" = "TRUE";
+#  "HIS_WALLOPS" = "TRUE";
+#  "HIS_MAP" = "TRUE";
+#  "HIS_LINKS" = "TRUE";
+#  "HIS_TRACE" = "TRUE";
+#  "HIS_STATS_a" = "TRUE";
+#  "HIS_STATS_c" = "TRUE";
+#  "HIS_STATS_d" = "TRUE";
+#  "HIS_STATS_e" = "TRUE";
+#  "HIS_STATS_f" = "TRUE";
+#  "HIS_STATS_g" = "TRUE";
+#  "HIS_STATS_i" = "TRUE";
+#  "HIS_STATS_j" = "TRUE";
+#  "HIS_STATS_J" = "TRUE";
+#  "HIS_STATS_k" = "TRUE";
+#  "HIS_STATS_l" = "TRUE";
+#  "HIS_STATS_L" = "TRUE";
+#  "HIS_STATS_m" = "TRUE";
+#  "HIS_STATS_M" = "TRUE";
+#  "HIS_STATS_o" = "TRUE";
+#  "HIS_STATS_p" = "TRUE";
+#  "HIS_STATS_q" = "TRUE";
+#  "HIS_STATS_r" = "TRUE";
+#  "HIS_STATS_R" = "TRUE";
+#  "HIS_STATS_t" = "TRUE";
+#  "HIS_STATS_T" = "TRUE";
+#  "HIS_STATS_u" = "FALSE";
+#  "HIS_STATS_U" = "TRUE";
+#  "HIS_STATS_v" = "TRUE";
+#  "HIS_STATS_w" = "TRUE";
+#  "HIS_STATS_x" = "TRUE";
+#  "HIS_STATS_y" = "TRUE";
+#  "HIS_STATS_z" = "TRUE";
+#  "HIS_STATS_IAUTH" = "TRUE";
+#  "HIS_WHOIS_SERVERNAME" = "TRUE";
+#  "HIS_WHOIS_IDLETIME" = "TRUE";
+#  "HIS_WHOIS_LOCALCHAN" = "TRUE";
+#  "HIS_WHO_SERVERNAME" = "TRUE";
+#  "HIS_WHO_HOPCOUNT" = "TRUE";
+#  "HIS_MODEWHO" = "TRUE";
+#  "HIS_BANWHO" = "TRUE";
+#  "HIS_KILLWHO" = "TRUE";
+#  "HIS_REWRITE" = "TRUE";
+#  "HIS_REMOTE" = "TRUE";
+#  "HIS_NETSPLIT" = "TRUE";
+#  "HIS_SERVERNAME" = "*.undernet.org";
+#  "HIS_SERVERINFO" = "The Undernet Underworld";
+#  "HIS_URLSERVERS" = "http://www.undernet.org/servers.php";
+#  "URLREG" = "http://cservice.undernet.org/live/";
+#  "LOC_ENABLE" = "FALSE";
+#  "LOC_TARGET" = "somenick";
+#  "EXCEPT_ENABLE" = "TRUE";
+#  "NOAMSG_TIME" = "0";
+#  "NOAMSG_NUM" = "1";
+};
+
+# Well, you have now reached the end of this sample configuration
+# file. If you have any questions, feel free to mail
+# <coder-com@undernet.org>.  If you are interested in linking your
+# server to the Undernet IRC network visit
+# http://www.routing-com.undernet.org/, and if there are any
+# problems then contact <routing-com@undernet.org> asking for
+# information. Upgrades of the Undernet ircd can be found on
+# http://coder-com.undernet.org/.
+#
+# For the rest:  Good Luck!
+#
+#      -- Niels.
diff --git a/doc/fda.txt b/doc/fda.txt
new file mode 100644 (file)
index 0000000..d993ae5
--- /dev/null
@@ -0,0 +1,151 @@
+fdaman.txt - brief usage information for FDA (Free Debug Allocator)
+
+Copyright (C) 1998 Thomas Helvey <tomh@inxpress.net>
+
+1. Base Functionality
+Basic use of the fda tools is as simple as including the header
+and source file with your source defining DEBUG and using capitalized
+versions of malloc(), calloc(), realloc(), and free().
+The fda allocation functions verify all your arguments and will call
+assert() if something is wrong. FDA trashes all allocated memory
+in a predictable manner and applies prefix and postfix bounds checking
+signatures to every allocation. When a pointer is freed it's validated,
+and checked for overflows and underflows. The fda Realloc function
+does not allow malloc or free through realloc and forces reallocation
+if the required memory is larger than the current allocation.
+
+In both the DEBUG and non-debug versions of fda, if a memory allocation
+fails once, a low memory callback function is called to allow you to
+release some memory and allow malloc to succeed, the default version
+prints a warning message to stderr. If the low memory callback returns
+the allocation is attempted again, if the second allocation fails a
+no memory callback function is called to allow you to clean up before
+terminating the application, if you allow the no memory callback to
+return the results are undefined. (a NULL ptr will be returned from the
+allocation call) The default no memory handler prints an error message
+to stderr and calls abort(). The DEBUG version will assert if you allow
+the no memory function to return.
+Both the low memory and no memory callbacks have the signature of:
+void handler(void)
+
+The debug version of fda will not allow you to do the following:
+Allocate a zero length chunk of memory.
+Free a non-allocated pointer.
+Free a pointer twice.
+Free a pointer at the wrong offset.
+Use realloc to free memory. (realloc(p, 0))
+Use realloc to malloc memory. (realloc(0, s))
+Overwrite the bounds of the memory you allocated. (checked on free)
+
+The base functions for fda are:
+void* malloc(size_t)
+void* realloc(void*, size_t)
+void* calloc(size_t, size_t)
+void  free(void*)
+char* strdup(const char*)
+void  set_lowmem_handler(void (*fn)(void))
+void  set_nomem_handler(void (*fn)(void))
+
+FDA uses a hash table to lookup pointers. The size of the hash table can
+be changed at compile time by using -DFDA_HASH_TABLE_SIZE <prime>
+where prime is a prime number somewhere around the number of allocations
+expected. The default hash table size is 16339 which should be large enough
+to hold most medium sized applications. FDA allocates memory for it's
+debugging records so if your application uses a lot of memory you
+may want to make sure you have enough memory available to use the debug
+version. FDA allocates 20 bytes to store each allocation and 20 bytes
+to store location information (file and line info). This overhead only
+applies if you have DEBUG or _DEBUG defined.
+
+2. Extended functionality
+FDA provides a few handy functions for validating pointers and
+checking for overruns before they occur when debugging.
+The first function fda_sizeof(ptr) returns the size of the buffer
+pointed to by ptr, this allows you to verify that your pointer
+is what it says it is. fda_sizeof() will call assert() if the
+pointer you pass it is not at the start of an allocation.
+
+The second function valid_ptr(ptr, size) verifies that ptr lies within
+allocated memory and there are at least size bytes available in the buffer.
+You can pass valid_ptr() a pointer to any location in allocated memory.
+valid_ptr() calls assert if the pointer points outside of allocated memory
+or the remaining size is less than the size specified.
+valid_ptr() is more efficient if the pointer argument is the value
+returned from malloc because it's a simple hash table lookup, a more
+exhaustive algorithm is used if it's not found in the hash table.
+
+FDA extended functions:
+size_t fda_sizeof(const void*)
+int    valid_ptr(const void*, size_t)
+
+Typical usage for the fda extended functions:
+Note: the assert macro compiles to nothing if NDEBUG is defined.
+Verify a foo_ptr:
+assert(sizeof(struct foo) == fda_sizeof(foo_ptr));
+assert(valid_ptr(foo_ptr, sizeof(struct foo)));
+Check for room to write:
+assert(valid_ptr(buf, len));
+
+3. Leak checking and block validation
+FDA has several functions for leak checking, and reference marking.
+fda_clear_refs() iterates through all of the allocated blocks of
+memory and clears the referenced flag.
+fda_set_ref() marks a single allocation(block) as being referenced or
+in use by somebody.
+fda_assert_refs() iterates through all the allocated blocks of
+memory and calls assert() if it finds one that's not referenced.
+
+Typical usage of the block validation functions:
+fda_clear_refs();   /* clear all block references */
+
+for each allocation do
+fda_set_ref(allocation);  /* mark allocation in use */
+done
+
+fda_assert_refs();  /* this will assert if a leak is found */
+
+4. Reporting functions:
+FDA has 4 functions for reporting various aspects of allocation
+status.
+fda_get_byte_count() tells you the current total number of bytes
+your application has allocated. (this does not include debugging records)
+This will give you an idea of how much memory your application is
+using at any given time.
+
+fda_get_block_count() returns the total count of current allocations.
+
+fda_enum_locations() calls a user supplied enumeration function with
+file, line, count information, this allows you to see your file by
+file allocation density. ;) fda_enum_locations() returns the total
+number of locations that have memory allocated.
+
+fda_enum_leaks() calls a user supplied enumeration function with
+file, line, size, and ptr for every block not marked as referenced.
+One use for fda_enum_leaks() is checking for leaks when your program
+exits:
+void enum_fn(const char* file, int line, size_t size, void* ptr)
+{
+  printf("Memory leak: %s: %d - %d bytes at (%p)\n", file, line, size, ptr);
+}
+
+int main(void)
+{
+  ...
+#if defined(DEBUG)
+  /* check for memory leaks before exiting */
+  fda_clear_refs();
+  fda_enum_leaks(enum_fn);
+#endif
+  return 0;  /* return from main */
+}
+
+The test file fdatest.c gives examples of usage for most of the functions
+available with FDA.
+
+Please let me know if you encounter any problems with FDA.
+So far FDA has been built and tested on linux and Windows NT.
+If you find that it works with or without change on other platforms
+please let me know so I can make the appropriate changes to the
+code and add it to the list of tested platforms.
+
+
diff --git a/doc/features.txt b/doc/features.txt
new file mode 100644 (file)
index 0000000..9b486ea
--- /dev/null
@@ -0,0 +1,208 @@
+Undernet server features.
+-------------------------
+
+This document is supposed to list the features that undernet supports and
+provides to clients, and which version of ircu this was added.  Additional
+numeric replies should be added here too.
+
+Extended Who information: (WHOX)
+ Version: unknown, but at least 2.10.07+
+
+ This is described in the file 'readme.who'
+
+USERIP:
+ Version: unknown, but at least 2.10.07+
+
+ This works the same as userhost, but returns the IP instead, useful for
+ setting a ban on someones IP address instead of their nick.
+ usage:
+  USERIP nick[,nick...]
+ returns:
+  RPL_USERIP (307)
+  :server.name 307 target nick[*]=[+|-]user@host...
+
+RPL_ISUPPORT:
+ version: 2.10.08+
+  
+ This sends a numeric during client signon that lists various features that
+ ircu supports.  This allows client and script writers to know what features
+ they can use, and various parameters about the irc server.  The numeric
+ used is '005' to try and maintain some semblance of compatibility with
+ dalnet which has a similar feature.  The 005 numeric may be split across
+ multiple lines if the length exceeds 512 characters.
+
+ The format is:
+  :servername 005 target feature1 feature2... :are supported by this server.
+  :servername 005 target feature200... :are supported by this server.
+
+ features are either a word describing the feature eg: 'SILENCE', or a word
+ describing the feature and an equals and a list of parameters.  
+ eg: SILENCE=15 (says that we support silence, and we support up to 15 of
+ them per user), or FOO=12,3 (says we support FOO with parameters 12 and 3)
+ for example 2.10.08 lists:
+
+ :test.undernet.org 005 test SILENCE=15 WHOX WALLCHOPS USERIP CPRIVMSG 
+   CNOTICE MODES=6 MAXCHANNELS=10 MAXBANS=30 NICKLEN=9 TOPICLEN=160
+   KICKLEN=160
+ NOTE: Versions prior to 2.10.08+ use numeric 005 as part of 'MAP', so
+ 005 should be /not/ be used after the server registration has occured.
+ (ie: after END_OF_MOTD has arrived).
+
+MAP:
+ Version: unknown, but since 2.9.30 at least, updated in 2.10.08
+ /map shows the servers as the server percieves them, who's connected
+ to who in a pretty display.  In version 2.10.08 it also lists the
+ amount time time it takes a message to get /from/ a server to the local
+ server - this measures the one way lag only, in 2.10.08 it also lists
+ the number of clients that are currently on that server.
+ The lag estimation is very approximate and depends on people changing nick
+ and joining channels, so the less clients on a server the less reliable the
+ lag estimation is.
+
+ Map prior to 2.10.08 uses:
+  RPL_MAP     005
+  RPL_MAPMORE 006
+  RPL_MAPEND  007
+ Map changed in 2.10.08 to allow for ISUPPORT on numeric 005, the new
+  numerics are:
+  RPL_MAP     015
+  RPL_MAPMORE 016
+  RPL_MAPEND  017
+WALLCHOPS:
+ Version: unknown, but since 2.10.07
+ WALLCHOPS sends a message to all channel operators (@)'s on a channel.
+ It does /not/ require you to be op'd (@'d) to do so.  This is a feature.
+ syntax:
+  WALLCHOPS #channel :message
+ or:
+  NOTICE @#channel :message
+
+ this sends:
+  :user NOTICE @#channel :message
+ to clients that are @'d on the channel.
+
+CPRIVMSG/CNOTICE:
+ Version: unknown, but since 2.10.07
+
+ CPRIVMSG/CNOTICE are a way around target limiting in recent undernet
+ servers.  Undernet servers prevent you from sending messages to too many
+ people at once in an attempt to help cut down the amount of spam that
+ occurs on the network.  Because there are several situations where you want
+ to send messages to lots of people that are on the same channel as you
+ (autogreet's and gamebots for example) an 'escape' was made in the form
+ of CPRIVMSG/CNOTICE.  These allow you to send a privmsg/notice to a person
+ on a common channel if you are op'd (@'d) without incuring a target
+ penalty.  If you see 'Target changed too fast' messages, you should
+ probably be using these commands.
+
+ Syntax:
+  CPRIVMSG #channel nick :Message
+  CNOTICE #channel nick :Message
+ Results are the same as for 'PRIVMSG' and 'NOTICE' respectively.
+
+SILENCE:
+ Version: unknown, 2.9.32 at least.
+
+ Silence is a server side ignore.  You can /silence +hostmask or
+ /silence +nick, to add someone to your silence list, or use /silence
+ -hostmask to remove it.  /silence will list your 'silence list'.
+ you can /silence nick, to see someone elses silence list (useful for
+ helping someone).  Silence is preferably used as a last resort as it
+ tends to use server CPU time.  Undernet typically only allows 15 silences
+ per user.  in 2.10.08+ this information is available in the RPL_ISUPPORT
+ line.
+
+ Syntax:
+  SILENCE +hostmask
+  SILENCE +nick
+  SILENCE -hostmask
+  SILENCE -nick
+  SILENCE nick
+
+ reply:
+  RPL_SILELIST      217
+  RPL_ENDOFSILELIST 218
+User modes:
+ Version: various
+
+ Undernet supports these additional user modes:
+  +d: Deaf & Dumb.  This user will not get any channel traffic.  Used for
+      bots.
+  +k: This user cannot be kicked, deop'd or /kill'd.  This usermode may only
+      be set by a server, it may not be set by a user.  This is used by
+      undernet service bots (X/W/UWorld etc)
+  +g: List channel HACK:'s
+  +s: Server messages - takes a parameter of which masks to send, see
+      'snomask.html' for more details. (2.10.0+)
+
+LIST:
+ Version: Unknown
+
+ List now takes various parameters to allow you to quickly and efficiently
+ find interesting channels.  These are:
+
+ >n or <n   show channels with less than or greater than 'n' users
+            respectively
+ C>n or C<n show channels that have existed for less than or greater than
+            'n' minutes.
+ T>n or C<n show channels that have had their topic changed in less than or 
+            greater than 'n' minutes.
+
+ Additional Numerics:
+  RPL_LISTHELP 334
+
+Additional Topic Numerics:
+ Version: Since the dawn of time.
+
+ Topic also lists who set it and when they set it.
+
+ Additional Numerics:
+  RPL_TOPICWHOTIME 333
+ Straight after the topic:
+  :server.name 333 #channel Isomer 923423442
+ where the number is seconds past 00:00 1970-01-01 that the topic was set.
+
+
+INVITE list:
+ Version: 2.10.08+
+
+ /invite without any parameters lists which channels you have an outstanding
+ invite to (ie: an invite to a channel which you haven't joined)
+ Additional Numerics:
+  RPL_INVITELIST      346
+  RPL_ENDOFINVITELIST 347
+
+NICK change:
+ Version: Since the dawn of time.
+
+ Undernet prevents you from changing nick on a channel while your banned.
+ Undernet prevents you changing nicks more than once per 30 seconds, you
+ get one 'free' nick change if you haven't changed nick recently.
+
+ Additional Numerics:
+  RPL_BANNICKCHANGE 347
+  RPL_NICKTOOFAST   349
+
+Target limiting:
+ Version: Recent 2.10.07ish at least.
+
+ Undernet prevents you from changing 20 targets per 2 minutes.  A target
+ is a 'Nick' or 'channel'.  This is to prevent spam.  If you message more
+ than 20 people or join more than 20 channels in two minutes then you'll
+ start getting 'Target change too fast' and will have to wait before you
+ can start talking.  See CPRIVMSG/CNOTICE above for information on how to
+ avoid this.
+
+ Additional Numerics:
+  ERR_TARGETTOOFAST 349
+
+
diff --git a/doc/freebsd.txt b/doc/freebsd.txt
new file mode 100644 (file)
index 0000000..265b758
--- /dev/null
@@ -0,0 +1,28 @@
+This document pertains to kernel panics with FreeBSD involving mbufs.
+
+   This is a well documented problem with programs such as ircu, and inn that
+   involve a lot of clients, the solution is generally to set the option 'NMBCLUSTERS'
+   to a reasonably higher number the default is 1024, you should first try increasing
+   this *10 (10240) and continue checking mbuf usage with netstat -m.
+
+   It has been recommended that this be increased as far as *50 (51200) (although more
+   won't hurt, it uses more memory, so don't go too far overboard) it's been stated
+   over and over that the default is very low, but then, you're supposed to know how
+   to configure your OS for what you're doing right? =)
+
+   There is a note in the configuration for this:
+
+   # Note that you will probably want to bump up NMBCLUSTERS a lot to use
+   options NMBCLUSTERS=1024
+   Merely change the 1024 to the number that best suites your system.
+
+
+     -poptix poptix@poptix.net
+
+
+
+
+
+
+
+   April 17, 2000 Matthew S. Hallacy
diff --git a/doc/history/2.4.notes b/doc/history/2.4.notes
new file mode 100644 (file)
index 0000000..0321b35
--- /dev/null
@@ -0,0 +1,478 @@
+/************************************************************************
+ *   IRC - Internet Relay Chat, 2.4.notes
+ *   Copyright (C) 1990   Markku Savela
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 1, or (at your option)
+ *   any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+IRC 2.4 release notes  6 May 1990/msa (Markku.Savela@vtt.fi)
+============================================================
+
+   This document explains the changes I have done up to this
+point. Some additional changes and packaging has been made by
+Chelsea (chelsea@earth.cchem.berkeley.edu). This is personal
+view of the changes.
+
+CHANGES TO LAST THE OFFICIAL RELEASE (2.2PL1)
+
+   This release of irc2.4 is based to 2.2PL1 release (see the
+HISTORY chapter later in this document). Aside from fixing the
+bugs, this version is in many ways different from the 2.2PL1.
+The purpose of the most changes is to make it easier to run an
+IRC server. Normal users benefit from these changes indirectly
+by getting a better maintained server.
+
+1. Changes visible to normal users
+
+   Even while mainly fixing bugs, some user visible changes have
+crept in too.
+
+1.1 General note on wildcards
+
+   Many commands accept now wildcard matching where applicable. All
+compares are case insensitive (e.g. "a" == "A"). The wild cards are
+
+       ?       matches any single character
+
+       *       matches any number of characters, also empty
+               string. [PL1 had a bug, which caused "*du*"
+               not match "....edu"].
+
+1.2 Server supported wildcards for "/who mask" command.
+
+   Protocol message is "WHO mask", where mask can be
+
+       empty
+       0       List all users [No change from PL1]
+
+       *       List all users on the same channel where the user is
+               (or all, if user is on 0) [No change from PL1].
+
+       number  List all users on the specified channel [No change
+               from PL1]. Note, if the "mask" begings with a digit,
+               this form is assumed, and the remainder of mask is
+               ignored, e.g. "/who 12*.fi" gives all people from
+               channel 12 and ignores the "*.fi" part.
+
+       mask    If the mask is any string, it will be compared
+               *separately* to each information field of the user
+               and if a match is found in any field, that user
+               is included into the list. The fields searched
+               are
+
+                       nickname
+                       loginname (account name)
+                       real name (text shown in parenthesis)
+                       hostname (users machine)
+                       servername (server he/she is using)
+
+               Note: servername is not usually shown on WHO output,
+               but is included in anyway. Example: finding all users
+               somehow connected with Finnish sites, can be achieved
+               with mask "*.fi".
+
+1.3 Changes to /whois command
+
+   As WHO, also /whois accepts wild cards as a parameters. WHOIS
+returns information for all users whose nickname matches the specified
+mask.
+
+   WHOIS automaticly calls WHOWAS [see below], if the attempted nickname
+is not found.
+
+1.4 Short term "WHOWAS" history
+
+   The server has a short in memory cache of the recent nickname changes
+(the current default is set to 200 last changes). The design goal of
+this is that it remembers changes in last few minutes, there is no
+intention of this to be a long term history. That must be a separate
+project, although it could use the hooks provided by this service.
+
+   "WHOWAS nickname" queries this cache and returns about the same
+information that WHOIS would do, if the nickname is found. Wildcards
+are not accepted here, this is a specifically designed feature. If
+the name is not found, WHOWAS doesn't reply anything. This is because
+the most useful use of WHOWAS is implicitly through "WHOIS".
+
+   This history is also implicitly utilized by KILL command.
+
+1.5 New SERVER-SERVER/SERVER-CLIENT protocol message WALLOPS
+
+   The message ":source WALLOPS :Message" sends the message text
+to all operators that are currently online. Any user can use this
+command, it's not restricted. How this function is activated, depends
+on the client, but if nothing else works, "/quote wallops text" should.
+
+   NOTE:This function will not be fully operational until *ALL*
+       servers have upgraded to version 2.4. Also, operators
+       must be using a client that recognizes this command.
+
+   This is really a hasty addition. But, done this way it follows
+the general IRC message philosophy, where messages are sent only
+to links where they are needed (e.g. WALLOPS goes only to servers
+that have opers online--it's not broadcast to every server).
+
+1.6 General use of wildcarding in server queries
+
+   All commands that previously took a servername as a parameter,
+now accept also a wildcarded mask. The mask is replaced with
+the first matching servername. The following user level commands
+are affected
+
+       /admin server   -- administrative info
+       /time server    -- local time
+       /version server -- the server version
+       /motd server    -- "the message of the day"
+       /info server    -- info (usually same on same server version)
+       /stat f server  -- statistics information
+       /users server   -- users logged on server machine
+
+   Note: Remote capability is a new feature for "info" and "stat"
+commands. Until all servers have upgraded, these commands may not
+reach the intended target and may return the information from some
+intermediate server.
+
+1.7 Marking user AWAY
+
+   v2.2PL1 version and earlier showed the AWAY-state (G) only for
+the local users of the same server. AWAY status could be queried
+only by sending a message to a user. This release (or since msa.4)
+broadcasts the away status to every server and the commands /WHO and
+/WHOIS give this information reliably.
+
+   A side effect of this change is: when a user marks himself/herself
+as AWAY, all pre-msa.4 servers that are reached will send back an
+acknowlegde message. Until all servers are upgraged, use of AWAY
+is somewhat inconvenient. If you get extra messages from AWAY,
+they also contain the server information. Use /admin command and
+send a *friendly* request for the admin to upgrage his/her server
+to a working version, namely 2.4 :)
+
+1.8 Servers don't restrict characters within messages
+
+   The parameter fields of the messages can now contain any characters
+in range 1-255, except '\r', '\n' and '\0'. The client programs should
+by default filter away the "dangerous" control characters, but intelligent
+clients can utilize this change and allow exchanges with foreign
+8-bit (or wider) charactersets. (The actual command parts must still be
+represented with the ordinary 7-bit characters.)
+
+2. Changes visible to the server administrator
+
+2.1 Identifying servers
+
+   Servers/clients have now always two names (it was this way in
+PL1, but I think this version makes the idea more clear):
+
+       Announced Name:
+
+       The official name of the server (the name you use in
+       /time, /quote connect, etc) or users nickname. Servers
+       name is usually the hostname, but can actually be almost
+       any string of characters resembling hostname. This one
+       is given in M-line of ircd.conf.
+
+       Socket hostname:
+
+       Socket hostname of the server or client. This is the hostname
+       of the connecting server/client and this is resolved from the
+       connection. If resolve cannot be done, ircd defaults to using
+       numeric IP-address. *ALL* access checks are based on this
+       name, especially noteworthy fact, if your resolver cannot find
+       hostnames by IP-address, you must allow the access by IP-numbers
+       in your ircd.conf.
+
+   In many places, where servers name is shown, actually both are
+shown. The general format of the displayed name is
+
+       AnnouncedName[SocketHostName]
+
+When a connection is yet unkown, there is no AnnouncedName, and if the
+AnnouncedName is the same as SocketHostName, the "[..]"-part is omitted.
+
+2.2 Many notices to local operators
+
+   If an oper is signed on the server, he/she will receive many
+notices about exceptional conditions and servers actions. When
+something goes wrong, it should be much easier to fix the problems.
+
+   Few often occurring, inportant error messages are
+
+   "Write error to SERVERNAME, closing link"
+
+       write() to socket returned with an error. Server is
+       closing the link. This means usually network problems
+       which you can do nothing about.
+
+   "Max buffering limit exceeded for SERVERNAME"
+
+       This is the situation where old server would have been
+       "frozen". The socket buffers in your OS have been filled and
+       even servers own predefined internal buffering MAX for a link
+       has been exceeded. Exceeding this limit most likely means
+       that the link is really dead, so the server closes the link
+       and scratches all queued output for it. If the limit is
+       set high ( > 20000 bytes), you won't usually see this, but
+       just "No responce from SERVERNAME, closing link" as the
+       server does not reply to PING as it should.
+
+   "Link SERVERNAME cancelled, server SERVERNAME already exits"
+
+       Two different servers from your net fragment attempted
+       to connect same other net fragment about the same time
+       and this collision is detected at your server. IRC routing
+       does not allow loops, the link causing the loop is closed.
+       (Which of the two links gets closed is mostly determined
+       by pure chance and timing--you may lose a better link this
+       way. Collisions should be rare in normal operation, if
+       the timers in "config.h" are not messed up too much...)
+
+       Of course, you get this too, if you try to connect to a
+       server that is already connected by some other route. In
+       that case your attempted connection is just safely cancelled.
+
+   The notices attempt to be self explaining.
+
+2.3 Links statistics collecting
+
+   IRCD now counts the bytes and messages transmitted to each open
+link. This information can be output with a command "/stats l"
+("/stats" or "/stat m" will give the old message count statistics).
+
+   Sample output
+
+Link           SendQ  SendM SendBytes  RcveM RcveBytes Open since
+oddjob.uchicago    0    203      8067    772     34321 Sun May  6 02:15:45 1990
+cs.hut.fi[sauna    0   1916     79798     94      3082 Sun May  6 01:51:25 1990
+otax.tky.hut.fi    0   3722    151511    426     22690 Sun May  6 00:25:54 1990
+nada.kth.se        0   8775    355811   5333    223853 Sat May  5 14:11:49 1990
+vehka.cs.uta.fi    0  23816    882000    901     41156 Fri May  4 22:50:23 1990
+lut.fi             0  25145    943765   1068     35020 Fri May  4 22:34:16 1990
+kreeta.helsinki    0  24286    899191    957     47085 Fri May  4 22:33:28 1990
+naakka.tut.fi      0  27754   1067302   8288    362960 Fri May  4 22:33:14 1990
+joyx.joensuu.fi    0  30003   1172949   2300     80053 Fri May  4 22:33:05 1990
+tel4.tel.vtt.fi    04083771 167473890 863475  35022755 Mon Apr 23 00:15:17 1990
+                   |    |       |       |       |      |
+                   |    |       |       |       |      Link established
+                   |    |       |       |       The number of bytes received
+                   |    |       |       The number protocol messages received
+                   |    |       The number of bytes transmitted
+                   |    The number of protocol messages transmitted
+                   The amount of queued data in bytes (if socket is hung)
+
+   The last row (with the local servername) contains the total
+cumulative counts for all connections since the server was started.
+
+   One can query the statistics of a remote server by adding the servers
+name to the command "/stat l servername". Of course, this only works,
+if all intermediate servers have upgraged. The first "old" server
+will stop the propagation and return the message counts by default.
+
+2.4 Connecting servers
+
+   An oper can manually activate a connection phase to any server
+defined in ircd.conf C-lines (to successfully complete the connection,
+the N-line must be present too). The message achieving this is
+
+       CONNECT servername portnumber
+
+   where servername may be a mask string containing wildcards. This
+name is matched against entries in ircd.conf (notice: the testing
+is made in reverse order, e.g. the last C-line in ircd.conf is tested
+first).  If portnumber is omitted, the ircd uses the one given in the
+found C-line. If the C-line does not have the portnumber, the compiled
+default will be used (PORTNUM from config.h).
+
+   This release allows also for remote connecting. An oper can send
+a connect request to remote server with
+
+       CONNECT servername portnumber remoteserver
+
+This command is passed to the 'remoteserver' and it then tries to
+execute it like it was given locally. (If there are opers online on
+that server, they will get a notice about this happening.) Note, that
+one can remotely connect only what is defined in ircd.conf. Usually
+one needs and should use this only for immediate your neighbours. Nobody
+should randomly go and give connect requests to distant servers, unless
+one knows it's absolutely necessary and is very familiar about the
+linking setup there.
+
+2.4 Terminating connections
+
+   The SQUIT command in PL1 was not intended to be used manually and
+was very dangerous to use (it also created so called "ghost servers").
+Since msa.4, the SQUIT has been safer to use manually.
+
+
+   "SQUIT z" s                          a
+              \                        /
+               \                      /
+         ------- x ------- y --| |-- z ------- b
+                /               ^     \
+              /                 |       \
+            p                            c
+
+       "SQUIT z" will break the link between "y" and "z" if injected
+       into system from "s". After that the net will be in two fragmets,
+       broken between "y" and "z". Server "z" never sees the actual
+       SQUIT, all it observers is that the link to "y" suddenly closes
+       (opers on z would see it as "Server y closed the connection"
+       notice. Opers on y would see it as "Received remote SQUIT from
+       x", note that the actual source "s" is not identified in the
+       current version--for reasons too complicated to be explained
+       here).
+
+       *WARNING* *WARNING* If the server "y" is still running pre-msa.4
+       (like PL1), don't *EVER* issue a SQUIT for its links (unless the
+       link is to a leaf node or verifiably a "ghost server").
+
+       Note, that when the link between "y" and "z" breaks, y will spit
+       out SQUIT's for "z", "a", "b" and "c" to "x". At same time "z"
+       is sending SQUIT's for "x", "s", "p", etc to "a", "b" and "c".
+       SQUIT is normally generated by servers automaticly, it's just
+       a later modification (msa.4) that allows an OPER to use this
+       same message to "simulate" a link break at certain point.
+
+       *IMPORTANT* If server "z" has configuration "C:y::y:6667", it
+       automaticly attempts to reconnect after a short delay (currently
+       10 seconds), but only *if* the connection has been up long enough
+       reliably (currently set to 10 minutes). If the thus formed link is
+       squit another time, it will not attempt to come back immeatedly.
+       This gives an oper time to reconfigure the links if that first
+       short delay is not enough.
+       
+    As in all commands, also SQUIT accepts wildcards, but be careful to
+give sufficient identification. SQUIT of wrong server is not nice...
+
+2.5 KILL message
+
+    KILL will implicitly use the history database. If a KILL is
+issued for a nick that has been changed to another, the server
+will automaticly re-issue the kill with the new nickname, if
+the change has happened recently (current value should be 90
+seconds). If a "terrorist" is clearly distrupting channel by
+bombarding it with garbage from negative channels and changing
+nick all time, there is no need to consult the "WHOWAS" data
+base, just use the nickname that was used to send the garbage
+and ircd hunts the culprit down. When this change of target
+happens, the oper issuing the kill is notified.
+
+NOTE:  With automatic, kill-proof-reconnecting clients, the
+       value of KILL is becoming insignificant...
+
+2.6 Changing the server defaults from the command line
+
+    The servers activation command is now
+
+ircd[ -f configfile][ -h servername][ -p portnumber][ -x debuglevel]
+
+where parameters can be given in any order. If the "configfile"
+is defined, it will override the default specified in the file
+"config.h". If "servername" is defined, it will override the
+one defined in the M-line on the configuration line. "portnumber"
+will override the compiled default (from "config.h") or the
+one from the M-line of the configuration file. The "debuglevel"
+will determine the amout of logging the server does into a
+log file that has been define in "config.h". The "debuglevel"
+should never be defined for a server running normally, it can
+quickly generate megabytes of trace. Usually needed only when
+the server is incapable of starting properly at all, then one
+run with "-x9" usually is enough to reveal the problem.
+
+3. General cleaning up and commenting the code
+
+   This issue is controversial. My way of fixing bugs is not just
+fix them, I also want to program defensively, make it difficult to
+make new errors. Thus I have heavily reformatted and reorganized
+those files that I have had to touch. Some functions have been
+renamed intentionally to catch all uses of those functions [because
+the functions semantics or calling sequences have been changed].
+
+   This release (2.4) will be the last IRC version I'm contributing
+to. If you have any wishes or complains about the code or functioining
+of IRC, use the source or ask whomever it happens to be the current
+developer.
+
+HISTORY
+
+   There have been many different versions of IRC and many of those
+versions are still in use. The following attempt to bring some
+clarification to the versions. This starts from 2.01.6, hopefully
+no servers are running older versions...
+
+       ...
+       ...
+       2.01.6  A version from WiZ in summer 1989
+       ...
+               2.01t6  A series of releases, which contained minor
+               2.01T6  adjustements and bug fixes to the base version.
+               2.01u6  Some of those fixes caused extra errors, of
+               2.01U6  this series versions 2.01U6 and 2.01v6 are at
+               2.01v6  least known to be rather stable.
+
+       2.1.0   Mike Bolotski created these versions from the sources
+       2.1.1   of 2.01U6, but unfortunale some devious bug crept in
+               and caused a lots of linking problems (the nasty "ghost
+               server problem" splintered the net constantly). These
+               versions must be deleted on sight :) [Autumn 1989]
+
+       2.2     This version is the 2.01v6 sources repackaged into
+               multiple directories by Mike again. Probably nobody
+               is running this base version, because is was promptly
+               followed by two patch releases [Autumn 1989]
+
+               2.2PL0  These two are the last major "official" releases
+               2.2PL1  and most of the servers upgraged to either of
+                       these.
+
+       2.2msa  Unfortunately 2.2PL1 version had a tendency to die
+               mysteriously very often. So, I started to look into the
+               code from March 1990 and that resulted a series of
+               patches to the 2.2PL1 server code, but finally
+               decided to release full server code releases of which
+               few have got wider distribution
+
+               2.2msa.4
+                       Has most of the known PL1 bugs fixed and seems
+                       to be very reliable. But once servers started
+                       staying up, a new problem appeared: socket
+                       buffers started getting full and servers tended
+                       to freeze very often for long intervals.
+
+       2.3alpha
+       2.3     Is an attempt to make an official release from 2.2msa.4
+               code, but hassles with changed copyrights make this
+               version unacceptable. Besides, 2.3alpha or 2.2msa.4 are
+               now obsolete, old versions :)
+
+       2.2msa.x
+               To solve the freezing problems, the server code is changed
+               to use non-blocking sockets.
+
+               2.2msa.7
+               2.2msa.9
+                       Are intermediate test versions, of which .9 seems
+                       to have most of the problems solved.
+
+               2.2msa.10
+                       Never released. This is slightly improved version
+                       of msa.9, some new features.
+
+       2.4     Is a release which combines 2.2msa.10 and Chelsea's
+               modifications to the server. Also, this release has
+               once again reorganized the directories and makefiles.
+
+
+-- msa (Markku.Savela@vtt.fi)
diff --git a/doc/history/2.7-New b/doc/history/2.7-New
new file mode 100644 (file)
index 0000000..7980d77
--- /dev/null
@@ -0,0 +1,128 @@
+       * WHOREPLY and NAMREPLY become numberics instead of strings.
+
+       * msa's patches to kick/mode to attempt to follow nick name changes
+
+       * spike's patches to get SUMMON to find last idle tty
+
+       * melazy's various DNS improvements.
+
+       * pjg's saber C check
+
+       * prefix changed for all server->client messages in which the origin
+         of the sender is a client to appear as follows:
+               nick!user@host
+
+       * TRACE output changed.
+
+       * # channel topics broadcast
+
+       * +-numeric channels removed from server
+
+       * numerics for TRACE output 201-209
+
+       * new switches for STATS: i,k,q,y
+
+       * numerics for stats output 211-219
+
+       * MODE changed to also operate on users
+
+       * deoper added as both mode and direct command. deoper sends out
+         ":user OPER -" to other servers. (from Kaizzu)
+
+       * XTRA/VOICE/GRAPH removed.
+
+       * MODE +a scrapped.
+
+       * added custom ANSI-compatible ctype macros to ensure speed
+
+       * user modes i,w,s,o implemented as follows:
+               i - invisible. over rides any channel mode for those external
+                   to your channel. you are invisible.
+
+               w - receive wallops
+
+               s - receive local service notices (errors, etc)
+
+               o - operator flag. (can not be set currently except using the
+                   OPER command).
+
+       * MODE +b added to ban a user from a channel using "nick!user@host" as
+         the mask to match to the user. If the user matches the ban mask they
+         are not allowed in. MODE +b with no parameters returns the list of
+         ban masks currently in place. MODE +b <mask> and MODE -b <mask>
+         add/delete a ban mask respectively.
+         Thanks to HulkHogan (andy@lingua.cltr.uq.oz.au) for defining what
+         we needed here and the 'BlackBall' approach.
+
+       * Operator passwords may now be stored in the ircd.conf file as the
+         encrypted plaintext. Crypt(3) is used to generate the matching
+         plaintext from the OPER command. Thanks to the following people
+         for help with this:
+               Sean Batt (sean@coombs.anu.edu.au),
+               Andy. M. Jones (andy@lingua.cltr.uq.oz.au),
+               Nelson Minar (minar@reed.edu).
+
+       * Server now creates "ircd.pid" file when booted. Holds the current
+         pid of the server.
+
+       * Each O and I line in the ircd.conf file may be linked only a number
+         of times equal to or the max. links value for the class they belong
+         to.
+
+       * Server stores results of any successful DNS lookups for servers so
+         that future lookups are not needed. A rehash will wipe all previous
+         lookup results and cause the server to start over. The server will
+         attempt to lookup each hostname in a C/N line on booting. This may
+         cause a delay during starting the server.
+
+       * All functions should be of the form "function_name", macros of the
+         form "MacroName" and constants as CONSTANT.
+
+       * Services are now treated with some respect. A service is associated
+         with an S-line in the ircd.conf. A service must send a NICK/SERVICE
+         pair on connecting to achieve service status.
+
+       * JOIN/PART now accept a list of channels in the first parameter with
+         each separated by a ",". eg "JOIN #foo,#bar,#foobar"
+
+       * A hopcount for the distance to nicknames and servers has been
+         introduced (for better or worse). It is passed as the second
+         parameter to both NICK and SERVER.
+         WHO and LINKS both report the hopcount in the info field.
+
+       * Default for WALL and WALLOPS set "off"
+
+       * rearranged config.h
+
+       * ISON now returns nicknames with the actual case, i.e.
+          ISON wiz will answer WiZ
+
+New into 2.7.1
+
+       * STATS u, r, z
+               u - uptime
+               r - CPU useage stats
+               z - counts and shows current memory useage
+         r & z are only available if DEBUGMODE is defined in config.h
+
+       * GETHOST which forces all reverse lookups of ip#'s to also match
+         when doing a forward lookup of the hostname returned.
+
+       * SENDQ_ALWAYS buffering policy for sending data over links.
+         (Server tries to buffer as much data as possible before attempting
+          a write).
+
+New into 2.7.2
+
+       * NOTE (once again appears and in much better state)
+
+       * WHOWAS gives a list of known users of the nick in question
+         rather than just the most recent.
+
+       * Server can accept both server and client connections via a unix
+         domain socket. This provides greater security and reliability for
+         connections between the host and itself. (#define UNIXPORT)
+
+       * STATS C reports L-lines: New Numeric 241
+
+       * #define for showing all users the invisible count from LUSERS
diff --git a/doc/history/ChangeLog.07 b/doc/history/ChangeLog.07
new file mode 100644 (file)
index 0000000..0b3204b
--- /dev/null
@@ -0,0 +1,32 @@
+#
+# ChangeLog for Undernet ircu Servers
+#
+# $Id: ChangeLog.07,v 1.2 2003-01-08 03:17:18 klmitch Exp $
+#
+# Please insert new entries on the top of the list, a one or two line comment
+# is sufficient. Please include your name on the entries we know who to blame.
+# Please keep lines < 80 chars.
+#-------------------------------------------------------------------------------
+* Added hostname hiding compatible with ircu2.10.10 to allow host hiding
+  for transitioning services, back out pline8 for now. --Bleep
+* Fixed default behavior for BADCHAN. supposed to DEFAULT yes, however
+  should not change each time a make config is done. -- WT
+* doc/readme.www: add Runs link update patch for linux info. --Bleep
+* channel.c, channel.h: add David M's fixup for local channel oper overrides.
+  --Bleep
+* s_misc.c (date): add Runs Y2K patch --Bleep
+* hash.c (hChangeClient): bug fix. If the client pointer matched the first
+  pointer in the bucket, the change was ignored (returned 0), leaving stale
+  values in the hash table, eventually causing the server to die for mysterious
+  reasons. Bug discovered by Quant and Isomer --Bleep
+* config-sh.in, channel.h, numeric.h, channel.c, s_debug.c, s_err.c:
+  add lchanmode patch by CaptJay, add symbols to incredibly long
+  feature string. Bump patchlevel to .03 --Bleep
+* list.h list.c s_conf.h s_conf.c opercmds.c:
+  badchan patch 2 seperate settings, allow global, and allow local.
+  currently allow_local is 'unapproved' for use on undernet. --WildThang
+* ircd.h, s_serv.h, s_debug.h, ircd.c, s_user.c, s_bsd.c:
+  removed STAT_MASTER/BOOT_OPER code, original patch by Isomer --Bleep
+* s_user.c (m_nick): removed redundant check for acptr --Bleep
+* ChangeLog (file): added ChangeLog, and BUGS files, import to ircu2.10 --Bleep
+
diff --git a/doc/history/ChangeLog.10 b/doc/history/ChangeLog.10
new file mode 100644 (file)
index 0000000..9869776
--- /dev/null
@@ -0,0 +1,696 @@
+#
+# ChangeLog for ircu2.10.10
+#
+# $Id: ChangeLog.10,v 1.2 2003-01-08 03:17:18 klmitch Exp $
+#
+# Insert new changes at beginning of the change list.
+#
+-------------------------- Released 2.10.10.pl15
+* Fiddle with /KILL and various exits to make the user experience uniform,
+  no matter who's doing the killing or where.  Previously, differences in
+  QUITs and in the messages sent to the killed client could help make a
+  partial map of the network; now that these messages are all uniform, there
+  is no way to tell. -Kev
+* Split ISUPPORT numeric into two numerics, so as not to exceed the 15
+  parameter limit imposed by the RFC -Kev
+* Turn on HEAD_IN_SAND_REMOTE...oops -Kev
+* Send prefixed error messages to other servers, so ERROR doesn't get
+  interpreted as a prefix -Kev
+* Reverse sense of HEAD_IN_SAND_WHO_HOPCOUNT to do what was intended; use a
+  hopcount of 0 if user is using /who on him/herself -Kev
+* Allow a user to see his/her own idle time without having to do
+  /whois <nick> <nick>; correct spelling of HEAD_IN_SAND_IDLETIME to
+  HEAD_IN_SAND_WHOIS_IDLETIME -Kev
+* Fix a missing ')' in the idle time stuff -Kev
+* Include ircd_policy.h in whocmds.c -Kev
+* Fixed bug in idle time, thanks hektik -- Isomer
+* Update 005 to be compliant with other networks -- Isomer
+* Hide hop count -- Isomer
+* Hide idletime unless you explicitly ask for it -- Isomer
+* /wallops and /wallusers would dump core because of the previous change--my
+  bad.  Now only include user@host when sptr is a client. -Kev
+* /wallops and /wallusers would leave out the user@host--noticed because
+  pl14 broke my script.  Fixed. -Kev
+* Fix several compile warnings, including the one in table_gen.c -Kev
+* Fix a bug in m_silence.c that rendered it uncompilable -Kev
+* Hopefully make mode clears during bursts appear to originate from local
+  server -Kev
+* Fix several things to send server<->server protocol messages with numeric
+  origins -Kev
+* Rework directed notices and mass-messages to use numerics and tokens
+  as appropriate; the latter required the modifications to
+  sendto_match_butone() -Kev
+* Redefined how sendto_match_butone() works, since it's only used with
+  PRIVMSG or NOTICE -Kev
+* Bumped patchlevel to pl15(development) -Kev
+* Corrected reverse-sense of HEAD_IN_SAND_REMOTE test in m_whois() -Kev
+* Clean up logic in m_whowas(), corrected numeric reply -Kev
+* Finally fixed /whois to tell you what your own server is -Kev
+* Clean up logic in add_banid() with some well-placed DupString()'s -Kev
+* Hide which server performed a nick collision kill -- Isomer
+* To allow for remote whois not giving away the remote server, all remote 
+  numerics to clients are remapped to come from the local server :/ -- Isomer
+* All remote queries are disabled for users, except /whois -- Isomer
+  (/whois now uses the second parameter for which server to use, ie:
+   /whois <ignored> <nick> will query <nick>'s server.)
+* Fixed /who showing server name -- Isomer
+* Fixed burst showing linking server -- Isomer
+* Fixed burst bans showing linked server -- Isomer
+* Fixed /whowas showing server name -- Isomer
+-------------------------- Released 2.10.10.pl14 (You got any issues with that punk?)
+* Changed (then fixed) /LINKS to output an empty links list -- Isomer
+* Make netsplit server notice say the right thing
+* Final fix for HEAD_IN_SAND_WHOIS_SERVERNAME
+* Fix a bug with implementation of HEAD_IN_SAND_NETSPLIT
+* Permit users to find out what server they're on, since they already
+  know -- Kev
+* Added HEAD_IN_SAND_WHO_SERVERNAME to cover final source of server
+  names -- Kev
+* Fixed wallops, wallusers now sends wallops to local clients,
+  wallusers to servers.
+* Added host to /kill messages -- Isomer
+* Fixed whois (opers can see server names) -- Isomer
+* Implement walluser -- Bleep
+* stats fixed -- Isomer
+* trace disabled from non opers -- Isomer
+* server name removed from whois (but not /who, shrug!) -- Isomer
+* netsplits are now represented with "*.net *.split" -- Isomer
+* Done /links -- Isomer
+* Modifications to map as suggested by nighty -- Isomer
+* Wallops is the only code that uses sendto_ops_butone now, this
+  isolates wallops entirely. No server notices sent by wallops.
+* HEAD_IN_SAND_SNOTICES done -- Bleep
+* HEAD_IN_SAND_WALLOPS done -- Bleep
+* HEAD_IN_SAND_DESYNC done -- Bleep
+* HEAD_IN_SAND_MAP done -- Isomer
+* According to CFV-165, buring our head in the sand to try and
+* hide from DoS - First pass -- Isomer
+* As requested by hop: hidden keys are shown as "*" not "" -- Isomer
+* As requested by Buff: allow admins to *disable* below behavour -- Isomer
+* As requested by Adriel, compile time option to disable mo_wallops 
+ -- Isomer
+-------------------------- Released 2.10.10.pl13
+* Don't allow two copies of the server to start -- Isomer/Kev
+-------------------------- Released 2.10.10.pl12
+* Release 2.10.10.pl12 before Mr_RIP threatens physical violence -- Isomer
+* Don't 'hubhide' nick's in /trace (oops!) -- Isomer
+* Allow K:line by realname, updated client connection logging -- Gte-
+* ircd/m_join.c: use ERR_BANNEDFROMCHAN instead of ERR_BADCHANNAME -- Kev
+--------------------------- Released 2.10.10.pl11.(release)
+* Fixed G-lined (reason), thanks to dfx -- Isomer
+* Added reason to the "G-lined (reason)" quit messages. -- Isomer
+* Removed 'for nick[1.2.3.4]' from quit messages, they're redundant
+  and make hub hiding more reliable --Isomer
+* ircd/s_user.c (hunt_server): add 'No such server' message back 
+  --Isomer
+* ircd/s_bsd.c: remove ALWAYSFLUSH - the problem wasn't ircu's fault 
+  -- Isomer
+* ircd/m_names.c (m_names): don't add a space if the user's a
+  zombie; fixes an overrun where we generate a huge number of spaces
+  in the names reply without length-checking them properly -- Kev
+* added 'ALWAYSFLUSH', if you thought the furgeson flusher was bad...
+  --Isomer
+* Fixed /USERHOST again.  Horribly embarrased.  Thanks again Liandrin 
+  --Isomer
+* Added extra field to /stats Y showing how many people are in that class.
+  Information was previously available via /trace, however tended to flood
+  you off if you weren't on a good connection.  Requested by Mr_RIP
+  -- Isomer
+* Fixed 'BADCHAN' resetting itself to 'Y', reported by Gator --Isomer
+--------------------------- Released 2.10.10.pl10
+* Released 2.10.10.pl10
+* Backported /names optimisation from 2.10.11.
+  '/names 0' now returns verbose listing, '/names' simply returns
+  ENDOFNAMES. Disallow harmfull /names usage. --Gte
+* Fixed ERR_NOSUCHNICK bug in userhost, thanks to Liandrin --Isomer
+* Conceal more bugs in IPcheck --Isomer
+* Add 'POST' as a unregistered command to disconnect people abusing web
+  proxies --Isomer.
+* Conceal bugs in IPcheck --Isomer
+* Fix for changing the wrong define --Isomer
+* Fix for the easter buggy. --Isomer
+* Fix for rpong --Run
+* Fix for other IPcheck bug, thanks BLMet. --Bleep
+* Fix for IPcheck bug, rewrite IPcheck from scratch (mostly),
+  add changes for new code to s_user.c, ircd.c --Bleep
+* Shorten connection timeout for auth queries to 60 seconds
+  If connection is from localhost use the server alias for the
+  client host. --Bleep
+* Fix for ident bug --Isomer
+* Fix for rping/rpong --Gte
+* Add m_pong to parser handler --Bleep
+* Fix for EXTENDED_NUMERICS bug doh!!! --Bleep
+* Fix for Max Undernet Server bug --Bleep
+* Fix for PRIVMSG<->NOTICE translation from hubs --Bleep
+* Fix for Bogus protocol strings for P9 servers --Bleep
+* Hookup UPING code again, cleanups --Bleep
+* Convert numerics back to mask and shift extended numerics
+  follow same mechanism --Bleep
+* Fixed bogus errno return on Solaris --Bleep
+* Fixed core on RPING bug, tokenized RPING --Bleep
+* Remove add_local_domain entirely, unused --Bleep
+* Merge u2_10_10_beta06 create branch u2_10_10_beta07 --Bleep
+* Remove size_t from socket calls, audit usage of size_t
+  values. --Bleep
+* Fix for OSF1, RES_NOALIASES not defined there. --Bleep
+* Don't bother doing hostname lookup or setting me.sockhost
+  since we never want to display it there is really no reason
+  to have the info. --Bleep
+* Bugfix broken N:line check in chkconf --Maniac
+* Bugfix, fix clients occasionally getting stuck in IPcheck
+  code. Add note to members in client struct that aren't used
+  for any remote client code, didn't want to actually move them
+  this close to release (paranoia) --Bleep
+* A few little cleanups in check_pings, removed yet another
+  address display. --Bleep
+* Bugfix, autoconnects displaying server IP address to opers.
+  --Bleep
+* Remove names from /stats p, since its always the server
+  name from the M:line anyhow, (redundant information)
+  --Bleep
+* Unborked throttling. --Bleep
+* Fix two stupid bugs, related to IP mismatch kills. --Bleep
+* Clean up configuration, make it a bit easier for admins to
+  turn off asserts and heap checking code. Moved host name dns
+  query for listener virtual host ports to dead code and use
+  me.name for the listener name (no sense in looking up the name
+  if we don't want to display it). Change direct bump of unknowns
+  in s_bsd.c to Count_newunknowns(UserStats) for consistency.
+  --Bleep
+* Added option to kill any connecting client with a forward and
+  reverse DNS mismatch. Fixed bug in s_auth that that caused
+  incorrect counts for unknown clients. Replaced missing server
+  notice for SNO_IPMISMATCH. --Bleep
+* Added a few more little name tweaks, no sense in looking up
+  the hostname in the conf if no one knows it. --Bleep
+* Moved to beta archive, bumped patchlevel, fixed message for
+  lost C:line in s_conf.c (I don't think I've ever seen this happen)
+  --Bleep
+* Finished host hiding changes, it should not be possible for any
+  online user to discover the real hostname or IP address of any
+  connected or unconnected server listed in the configuration. This
+  applies to opers and regular users. The name in the M:line is the
+  name used for connecting and all informational messages. --Bleep
+* Removed code in dbuf.c that flushes the dbufs if the server runs out
+  it looks like a fully loaded server may not be able to handle a net
+  break without shedding a few clients. --Bleep
+* Finish IP address cleanup, alpha should be clean for not displaying
+  server hosts or IP addresses to users now. This needs to be verified.
+  Changed version to u2.10.10 per Isomers suggestion. --Bleep
+* Remove server IP address from info line for connecting servers.  
+  This almost completes the IP address hiding changes for alpha, there
+  are still a few stats commands available to users that will show the
+  server addresses, but they can be easily disabled or only show '*'s
+  to non-opers.  --Bleep
+* Fix possible (but not likely) memory leak in debug allocator, couldn't
+  find the "meg a minute" problem, using the debug allocator on the
+  production network with more than 1000 clients on a server may cause
+  problems if you don't have a lot of memory. (This does not seem to
+  be a problem with non-debug builds) --Bleep
+* Captialisation fixes, just to keep certain ppl quiet. --Isomer
+* Removed +s channels from /list.  They were shown sometimes, but not
+  others, and the information that was shown about them was inconsistant.
+  list is not an effective way to gain information anyway. Reformatted
+  and touched up readme.who as well.  --Isomer
+* Added MAP to ISUPPORT, added doc/features.txt --Isomer
+* Added suggestions made by scripters. more info for ISUPPORT, and
+  added stuff to 'TODO' --Isomer
+* More TODO items 'done'.  P:'s now ignore '*'s.  ping shouldn't do funky
+  stuff with mirc anymore, needs discussion --Isomer
+* Typo fixed. Now I'm annoyed.  --Isomer
+* Right, Makefile's gonna work now or I'm going to get REALLY annoyed at it.
+  --Isomer
+* TODO, m_ping, ircd/Makefile.in: Added note to TODO, added info to
+  m_ping, and fixed Makefile bug using bsdmake. --Isomer
+* s_bsd.c, listener.c, s_user.c, s_serv.c, s_bsd.h:
+  Set receive and send buffers in correct order to enable flow
+  control for clients and support fat pipes better for servers.
+  Finally got it right :)
+  See Stevens "Unix Network Programming" v1 p 191-193
+  --Bleep
+* ircd.c (main): added idiot checking to make sure MAXCONNECTIONS
+  is sane. --Bleep
+* send.c: Don't let negative fd's break stuff, audit sentalong
+  usage for sillyness. --Bleep
+* send.c (sendto_common_channels): bug fix, code assumed client
+  local, file descriptor is only in local client struct
+  --Bleep
+* table_gen.c, channel.c: make FIXME changes, removed
+  FIXME code from table_gen, readd FIXME code to channel.c,
+  I hope I got this right. --Bleep
+* Makefile.in: Add purify def, fix so CFLAGS don't error
+  off when using Solaris compiler --Bleep
+* fda.c (fda_free): fix compile error on Solaris --Bleep
+* configure.in: add SunOS case to detect Solaris --Bleep
+* os_solaris.c (os_send_nonb): fix solaris compile error --Bleep
+* exaconf.2: add file from conf design to docs directory to
+  have it available for new conf parser development --Bleep
+* fda.c (fda_free): fix memory leak, doh!!! --Bleep
+* hash.c (addNickJupes): fix buffer overrun --Bleep
+* s_bsd.c (read_message(poll)): fix uninitialized memory read
+  bogosity in poll macros. --Bleep
+* channel.c (send_user_modes): change to send XXX:ov instead
+  of XXX:o:v doesn't send XXX: if no modes set. --Bleep
+* s_bsd.c (connect_server): bugfix for connect/rehash/connect
+  multiple outstanding dns query core. --Bleep
+* channel.c (send_user_modes): bugfix for burst not sending modes
+  when burst line is created. --Gte
+* m_gline.c: change NumServ(cptr) to NumServ(sptr) found by Gte
+  --Bleep
+* config-sh.in: add WildThangs BADCHAN config fix --Bleep
+* config-sh.in: add Runs restart bugfix --Bleep
+* Makefile.in: make sure version.c gets regenerated when checksums
+  change --Bleep
+* Makefile.in: remove hash.c/crypt/sums idiocy, all of the ridiculous
+  anti-hack stuff is already done in version.c anyhow.
+  "Shhh..., don't tell the admins ( .)( .) you're being watched"
+  --Bleep
+* hash.c (m_hash): fix count bugs --Bleep
+* m_squit.c (mo_squit): fix off by one, /quote SQUIT bug --Bleep
+* ircd_relay.c: oops, changed the wrong one.  Fixed previous fix. --Isomer
+* Makefile.in, ircd_relay.c: Fixed 'make depend', added dependancies, fixed
+  bug where server would core on sending a server notice --Isomer
+* m_kick.c (ms_kick): fix core on kick message coming from
+  server --Bleep
+* config.in: remove CRYPT_LINK_PASSWORD option --Bleep
+* doc/readme.www: Applied Runs' doc patch --Bleep
+* client.h: Add member to client struct to try to aggravate the
+  bug found by Jesus --Bleep
+* client.h: Remove IsListening macros and flags, add FLAGS_UPUNG
+  and IsUPing/GetUPing/SetUPing macros --Bleep
+* m_silence.c, m_create.c: check for IsServer(sptr) don't
+  allow X SILENCE X +*@*.com or X C #blah 947477407 core the
+  server. --Bleep
+* os_*.c, res.c: clean interface for os_recvfrom_nonb --Bleep
+* uping.c, uping.h: new files for UDP pings, these aren't hooked up yet, or
+  finished or tested.
+  --Bleep
+* channel.c: find_member_link(): Fail fast for Servers, prevents core when
+  servers set a channel mode. --Isomer
+* channel.c, channel.h, various.c: Changed find_member_link() to take
+  a chptr instead of the first member, and special case'd +k users
+  (see comment in code for more details) --Isomer
+* ircd/Makefile.in: Changed gnu specific $^ for $< in table_gen
+  rules --Bleep
+* INSTALL: Explained about CVS --Isomer
+* example.conf: Point to coder-com@ for help configuring the server. --Isomer
+* INSTALL: Make things a bit more plain.  --Isomer
+* s_bsd.c (read_message (poll)): removed local_cptr array using
+  this temp made possible a bug where if a client lower in the list
+  managed to exit a client higher in the list, a dangling reference
+  to the already exited client would be left in the local_cptr array.
+  Found by Quantum by loading 100's of clones with the same nick.
+  --Bleep
+* INSTALL: Added instructions for -lcrypt FAQ --Isomer
+* INSTALL: Added instructions for -lresolv FAQ --Isomer
+* INSTALL: Added instructions for making ./configure executable --Isomer
+* numeric.h: Merged in some more numerics that other ircds user --Isomer
+* IPcheck.c: Fix gramatical error to keep pedants happy. --Isomer
+* IPcheck.c: Allow -DNOTHROTTLE for debugging purposes.  --Isomer
+* m_stats.c: make stats c available to opers only, TEMP_HACK --Bleep
+* IPcheck.c: Fixed outdated comment.  Thanks Quantum --Isomer
+* ircd_reply.c: Fix the fix, silly typo.  thanks Bleep --Isomer
+* ircd_reply.c: added check for people without nicks.  --Isomer
+* doc/Authors, ircd/version.c.SH: updated /info and maintainer 
+  lists. --Isomer
+* channel.h, channel.c, m_join.c, m_mode.c: add David M's
+  lchanmode patch update --Bleep
+* s_auth.c: fix ident bug, comment code for rule. --Bleep
+* m_invite.c (m_invite): Fix syntax error, missing ')'. -- Isomer.
+* m_invite.c (m_invite): tokenize invites, change from accidental
+  broadcast to directed message (bug fix). --Bleep
+* m_time.c (m_time): send tokenized time messages --Bleep
+* s_user.c (set_user_mode): Send wallops to everyone by default
+  allow compile option WALLOPS_OPER_ONLY for networks that want
+  to disable wallops for users. --Bleep
+* s_misc.c (exit_one_client): tokenize client quit message to other servers.
+  --Gte
+* m_kick.c: you would have thought I'd fix all of them the first time, but
+  no... -- Isomer
+* m_kick.c: Fixed missing space after TOK_KICK -- Isomer
+* m_burst.c: Fixed netrider kick bugs -- Isomer
+* s_user.c: Bug fix --Bleep
+* s_user.c: only send wallops to opers --Bleep
+* s_user.c: enforced undernet policy. -- Isomer
+* s_user.c: replace user_modes with struct UserMode array
+  change code to use new struct. --Bleep
+* s_user.c (set_user_mode): clean up switch statement --Bleep
+* channel.c (set_mode): fixed -k foo bug, extra == 0 typo in
+  conditional. --Bleep
+* dbuf.c (dbuf_alloc): fixed count bug, we _have_ to count it in
+  the branches. --Bleep
+* dbuf.c, send.c, s_bsd.c, send.h: bahh finally did it right,
+  if a dbuf allocation fails, attempt to flush all send buffers except
+  for the one we are trying to build (we're twiddling with the list etc..)
+  if the allocation fails a second time, _then_ bail. --Bleep
+* s_bsd.c, send.c: if dbuf_put fails for send or receive buffers,
+  call flush connections to free up some buffers (safe here). --Bleep
+* dbuf.c (dbuf_put): back out previous change, afaict it would fail
+  spectacularly --Bleep
+* dbuf.c (dbuf_put): call flush_connections(0) if we can't allocate
+  a dbuf the first time, this may prevent the server from dropping
+  connections during netbursts. --Bleep
+* m_privmsg.c: fix IDLE_ON_MSG fix -- Isomer
+* m_privmsg.c, parse.c: fix IDLE_ON_MSG bug --Bleep
+* m_ison.c (m_ison): Temp hack to fix missing null terminator. --Bleep
+* m_nick.c (m_nick): fix null nick reply bug --Bleep
+* ircd_string.c, match.c: fix a couple possible issues with
+  the character attribute changes --Bleep
+* s_auth.c, ircd.c: turn off connection status messages for
+  connections to server ports. --Bleep
+* ircd.c, s_conf.c, m_server.c, ircd.h, s_conf.h:
+  removed portnum and server_port global variables, server port
+  in M:lines is ignored, server ports now need to be defined in
+  the P:lines. Add SERVER_PORT config option to allow:
+  '/connect server.net.dom' without specifying the port. --Bleep
+* config-sh.in: change PORTNUM to SERVER_PORT now used for
+  default server port for outgoing connections in m_connect.
+  --Bleep
+* example.conf: document changes to M:line for server port --Bleep
+* ircd_chattr.h, ircd_string.h, ircd_string.c, table_gen.c:
+  put Nemesi's table generation code and macros back in, the
+  tables are now automagically generated whenever the table_gen.c
+  file is modified, use a slightly different mechanism to get the
+  tables in the executable. Add reference data file to test dir
+  for character attributes. --Bleep
+* s_auth.c (check_ident_reply): add function that implements
+  auth reply undernet rules checking. --Bleep
+* s_misc.c (date): added Runs Y2K patch --Bleep
+* m_privmsg.c: work on server handlers, hookup new code to parser,
+  test, fixed a couple bugs, fixed username bug in server NICK
+  processing --Bleep
+* ircd_chattr.c, m_privmsg.c: Work on privmsg code a bit more,
+  commit for review, still a bit more to do --Bleep
+* os_bsd.c, configure.in: add os dependency file for bsd
+  --Bleep
+* m_privmsg.c, ircd_string.c: little cleanups for privmsg
+  work on prototype handler for new parser. --Bleep
+* m_connect.c, s_conf.c: clean up /connect handling code
+  --Bleep
+* m_away.c, m_admin.c, m_close.c, m_connect.c:
+  start cleaning up handlers --Bleep
+* whocmds.c, whowas.c, *.c: split out handlers from whocmds.c
+  and whowas.c --Bleep
+* s_serv.c, m_*.c: split out handlers from s_serv.c
+  --Bleep
+* querycmds.c, m_*.c: split out handlers from querycmds.c
+  --Bleep
+* opercmds.c, m_stats.c, m_connect.c, parse.c, handlers.h, *.c
+  add new command handlers --Bleep
+* channel.c, m_names.c: new file for names handler --Bleep
+* channel.c, m_list.c: new file for list handler --Bleep
+* channel.c, m_topic.c: new file for topic handler --Bleep
+* channel.c, m_burst.c: new file for burst handler --Bleep
+* channel.c, m_create.c: new file for create handler --Bleep
+* channel.c, m_destroy.c: new file for destroy handler --Bleep
+* channel.c, send.c, m_join.c: new file for join handler,
+  const fixups for send.c --Bleep
+* channel.c, m_mode.c: new file for mode command handler,
+  clean up file scope buffer mess. --Bleep
+* m_silence.c: split out SILENCE handler to a new file,
+  cleanup --Bleep
+* m_ison.c: split out ISON handler to a new file, cleanup --Bleep
+* m_userip.c: split out to new file, change userhost and userip
+  to use same algorithm with different formatting functions --Bleep
+* m_userhost.c: split out to new file --Bleep
+* send.c: add new function send_buffer, cleanup godemode ick a bit
+  --Bleep
+* m_wallchops.c: split out wallchops handler --Bleep
+* m_cprivmsg.c: split out m_cprivmsg and m_cnotice.
+* m_pass.c, s_user.c: split out m_pass, pass message handler
+  --Bleep
+* m_oper.c: split out m_oper.c from s_user.c, setup to use
+  new parser. --Bleep
+* m_pong.c, m_ping.c, parse.c, s_user.c, channel.c:
+  Add new file for pong messages, convert ping and pong to use
+  numerics. Test pings and pongs on testnet. Fix numeric
+  nick bug in channel.c. --Bleep
+* m_ping.c, s_serv.c, parse.c: new file for pings, fixed a 
+  minor bug in ping handling. --Bleep
+* m_nick.c, m_kill.c: clean up nick code for servers, still needs work
+  fix string formatting bug in m_kill --Bleep
+* m_nick.c, s_user.c, ircd_chattr.c: add new file for NICK command,
+  clean up local client registration for nicks. --Bleep
+* m_away.c, s_user.c, parse.c: split out m_away handlers for client,
+  add user_set_away function. --Bleep
+* m_kill.c, ircd_reply: Rework handling of kill from server, add new error
+  message formatter. --Bleep
+* m_kill.c (mo_kill): Rework handling for kill from operator on server
+  kill originated from --Bleep
+* m_kill.c: new message handler file for kill --Bleep
+* configure.in, ircd/Makefile.in: added automatic os checking to autoconf
+  checked --Gte
+* m_quit.c: new message handler file for quit --Bleep
+* m_privmsg.c: new message handler file for privmsg --Bleep
+* ircd_string.c, support.c, support.h, *.c: moved strtoken to ircd_string
+  and renamed ircd_strtok --Bleep
+* channel.c, s_user.c, s_debug.c, send.c, channel.h: finish membership code
+  --Bleep
+* channel.c, more cleanups of membership code and macros --Bleep
+* channel.c, s_misc.c: more cleanup in channel link code, most likely
+  still a bit broken yet, more to come. --Bleep
+* querycmds.h (Count_remoteclientquits): fix minor bug --Bleep
+* ircd.h, querycmds.h, struct.h, channel.c, list.c, map.c, opercmds.c,
+  s_err.c, s_serv.c, s_user.c, s_misc.c: Add Isomers passivelag0-1.patch
+  fixed minor bug in macros --Bleep
+* channel.h, channel.c, s_user.c, s_debug.c, s_user.c:
+  added Membership struct for channel associations, change user/channel
+  lookups to use new struct. --Bleep
+* channel.c, channel.h, s_user.c: cleanup channel and user code
+  a bit, new function find_no_nickchange_channel --Bleep
+* parse.c, m_defaults.c: added default handlers and hooked up new
+  message handlers --Bleep
+* *.c, struct.h: added Isomer's passivelag patch and, the second
+  p10 patch --Bleep
+* ircd_reply.[ch]: new files for commonly used replies --Bleep
+* m_proto.[ch]: new file for protocol command support, needed for zip
+  links --Bleep
+* client.h, parse.c, msg.h: add code to support multiple message handlers
+  depending on client status. --Bleep
+* s_bsd.c, packet.c: code cleanup prep for zip links --Bleep
+* channel.c, opercmds.c, ircd.c, s_serv.c, s_user.c, querycmds.c, 
+  whocmds.c, whowas.c: Add Isomers p10ify patch, tokenize server to
+  server commands --Bleep
+* s_user.c (m_nick): killed goto --Bleep
+* client.h, *.c: moved client stuff to client.h --Bleep
+* version.c.SH, patchlevel.h, .patches: change version string
+  generation, patch level is now set in patchlevel.h by simply
+  bumping the number in the PATCHLEVEL string. --Bleep
+* ircd_alloc.c, channel.c: fixup warnings in release build (NDEBUG)
+  --Bleep
+* fda.h, ircd_alloc.h, fda.c, ircd_alloc.c, fda_t.c: new files,
+  runmalloc was core dumping on squits and unable to handle or
+  detect double frees, the memory debug code can be disabled by
+  compiling with NDEBUG defined --Bleep
+* channel.c (remove_user_from_channel): refactor function --Bleep
+* channel.c (m_kick): refactor function a bit, put all checks at top
+  move code out to new function (make_zombie) --Bleep
+* s_bsd.c (completed_connection): fixed stupid
+  "Write error to blah: Socket not connected" bug --Bleep
+* struct.h, send.h, send.c, s_bsd.c, IPcheck.c, s_user.c, *:
+  More socket code cleanup, move file descriptor to local part of
+  client struct, use cptr->error to handle the errno of any socket
+  error, fix bug in IPcheck that ends up only disallowing every
+  256th clone, Add more ipcheck forgiveness to s_user.c (needs work).
+  Changed IPcheck_local_connect and IPcheck_connect_fail interfaces to
+  use struct in_addrs instead of client structs to allow delaying the
+  allocation of the client struct till after the check was done.
+  Added can_send function to send.c (should be called before work is done
+  but right now it's called just before trying to send (needs work))
+* channel.c: Added Isomers netride2.patch, still needs a config option
+  to turn it on (NO_INVITE_NETRIDE) --Bleep
+* parse.c, msg.h: Added silent ignores for notices so connect progress
+  messages do not cause connecting server to spew ERR_REGISTER_FIRST
+  messages at the server it's connecting to. --Bleep
+* s_serv.c, s_user.c, channel.c, send.c: Tokenised BURST, NICK,
+  END_OF_BURST, EOB_ACK, PRIVMSG and NOTICE Server to Server.
+  About 8-10% Bandwidth saving on BURSTS. --Gte
+* channel.c (m_join): servjoin patch --Isomer
+* ircd_osdep.h, os_*.c, s_bsd.c, send.c: more cleanups in socket code,
+  use enumeration for IO results. --Bleep
+* s_bsd.c: clean up select and poll code a bit more, fixed message pacing bug
+  in poll. --Bleep
+* supported.h, numeric.h, s_user.c, s_err.c: Added Isomers features
+  patch. Use numeric 005 RPL_ISSUPPORT to convey server features to
+  clients. --Bleep
+* s_user.c (m_nick): IP differ patch, use IP address instead of host
+  name to determine different user@host for nick collides. --Isomer
+* hash.c (hChangeClient): Bug fix. Fixed bug that caused stale entries
+  to be left in client hash table after a name change. Discovered by
+  Quant and Isomer. --Bleep
+* hash.c (hSeekClient): fixed bug I introduced when reversing my hash
+  table code changes, thanks Quant and Isomer --Bleep
+* opercmds.c (m_lusers): send limited luser info to remote
+  clients --Isomer
+* numeric.h, channel.c, s_err.c: Changed invite list numerics
+  from 283/284 to 346/347 to match IRCnet numerics --Bleep
+* config-sh.in, gline.h, numeric.h, gline.c, opercmds.c, s_debug.c, s_err.c:
+  Add badchan patch by WildThang --Bleep
+* config-sh.in, channel.h, numeric.h, channel.c, s_debug.c, s_err.c:
+  Add lchanmode patch by David M --Bleep
+* channel.c (cancel_mode): removed incorrect assert --Bleep
+* *.c: removed P9 support, not everything is completely gone but most
+  of it is, the server builds and connects to other servers, but thats
+  as far as it's been tested so far. --Bleep
+* ircd.h, ircd.c, s_bsd.c:
+  removed BOOT_INETD/BOOT_CONSOLE code, unused non-functional --Bleep
+* struct.h, ircd.h, ircd.c, s_user.c, s_bsd.c:
+  removed BOOT_OPER/STAT_MASTER code, original patch by Isomer --Bleep
+* s_user.c (m_nick): removed redundant check for acptr
+* hash.c (hSeekClient, hSeekChannel): roll back some of hash.c changes
+* hash.c (hSeekClient, hSeekChannel): removed unused variable from previous
+   changes.
+* hash.c (hSeekClient, hSeekChannel): fix compile error from status changes,
+   fix logic bug that caused the first client that matched the mask to be
+   returned regardless of whether or not it's name matched, this can result
+   in wierd problems where the wrong server/client could be returned from the
+   hash table lookup. Removed code that moved client to head of hash table
+   chain for it's bucket when it's looked up, if the hash table is working
+   reasonably well this just wastes cpu.
+* hash.c, list.c: added code to zero out cptr->hnext when client removed
+   from hash table, added assert for hnext == 0 in list.c to make sure that
+   client was actually removed from the hash table before freeing it's memory.
+* various: misc cleanups
+* support.c: removed dead code
+* configure.in: remove unneeded checks for minix, aix, ansi/posix headers
+   these things are handled by porting layer code.
+* res.c: remove calls to add_local_domain, these were causing incorrect
+   behavior
+* opercmds.c: cleanups in gline code
+* s_bsd.c: increase socket buffers to 65535 for server connections
+* crypt/mkpasswd.c: mutter correct runes to get file to compile without warnings
+* gline.c, gline.h: add new files to attempt to encapsulate glines a bit,
+   some code from opercmds.c needs to be moved here still
+* opercmds.c (m_gline): fix local gline bug
+* s_conf.c (initconf): add password change on rehash fix
+* s_conf.c (rehash): fix rehash freeing and reloading the motd/rmotd files for
+   every client connected.
+* ircd_log.c: use 2K fixed buffer instead of vsnprintf, nothing we write to
+   the log should ever exceed 512 bytes, but it doesn't hurt to be paranoid.
+* res.c: change resolver timeouts to 5 seconds, per RFC1123
+* channel.c: more little cleanups, no code changes
+* channel.c: a) stops iterating over /invite list
+    b) adds /invite to list the channels you're currently invited to.
+    c) adds lotsa new numerics --Isomer
+* ircd_signal.c, ircd.c: fix bug in signals
+* channel.c (can_send) add Isomer's changes
+* channel.c: add send_ban_list, cleanup a few names, reformat some parts to make
+    more readable, fix bug introduced by name changes
+* ircd_chattr.[ch]: add new macro for checking K:line time chars vs comments
+* listener.c (show_ports): add code to show client/server and hidden status
+* s_conf.c: bug fixes, cleanups, add code to set server port and hidden
+    status for listeners (P:lines)
+* s_conf.c (initconf): add interface selection code to P:lines so ports can
+    be set on a single interface or multiple interfaces (multi-homed hosts)
+* s_conf.c: rewrote C/N line code, removed N:lines entirely, clean up server
+    conf line code.
+* s_conf.c (check_server): move ip checks out of resolved or not so they can
+    be checked for worse case situations on server connects
+* res.c (resolver_read): add Isomer's debug info for failed resolver queries
+* opercmds.c (m_stats): remove call to time(0) for each local client in 
+    stats l command, use CurrentTime instead
+* s_conf.c (initconf): only do lookups on C:lines instead of both C/N lines
+* res.c: fix resolver hang bugs
+* s_conf.c (rehash): remove extra semicolin that was causing c/n lines to
+    accumulate
+* s_conf.c (rehash): add portnum back to the listener list so we don't loose
+    the server port on a rehash
+* s_auth.c, listener.c: remove warnings for normal errors
+* s_auth.c, listener.c: use osdep non-blocking calls instead of locals
+* s_auth.c, listener.c: add code for non-blocking recovery for listeners and
+    auth queries
+* s_auth.c (auth_error): call IPcheck_connect_fail if the client socket dies
+    during the auth check so the reference count doesn't get borked in the
+    IPcheck code.
+* numnicks.c: yet another extended numerics bug fix... sheesh
+* s_bsd.c, s_conf.c: move conf line code from s_bsd.c to s_conf.c, cleanup
+    cleanup check_server, check_client (still not completely tested, may be
+    a bit buggy yet).
+* parse.h, parse.c, s_debug.c: remove privmsg logging code
+* numnicks.c (FindXNServer): fix off by one bug
+* common.h, common.c: removed unused files
+* s_bsd.c (net_connect_completed): new function, called after connection
+    establishment for servers and clients, release reference count for
+    the dns reply and set the socket buffer size to IRCD_READBUF_SIZE 
+    for servers and 2K for clients.
+* channel.c, crule.c: cleanup bogus casts
+* listener.h (add_listener): fix bug that caused server a server port listener
+    to think it was a client port listener.
+* s_user.c, s_serv.c: release reference to dns_reply when connection is
+    established.
+* s_bsd.c (completed_connection): removed call to start_auth for connects
+    the auth module expects connections not to be linked anywhere and owns
+    the client struct until it's done.
+* listener.c (release_listener): fix inverted assert client exit bug
+* ircd_chattr.c: fix signed/unsigned warnings with Sun Workshop (+w)
+* ircd_chattr.c, ircd_chattr.h: new files for character attributes and case
+    translation, hopefully they will be a bit easier to maintain.
+* s_conf.c (rehash): fixed logic bug that caused and infinite loop, 
+    fix port update bug (needed to call mark_listeners_closing before initconf)
+* *.c, runmalloc.[ch]: change the way the server deals with out of memory
+    conditions. On server startup a no-memory handler is installed which
+    calls server_restart if an allocation fails. Allocations are now checked
+    in the memory allocation functions. Added asserts after every allocation
+    to verify for debug.
+* *.c *.h: move authentication and dns to authentication module rename a few
+    globals, const correctness fixes, add ircd_string code, rework network
+    code, use dns callbacks, removed a lot of redundant code 
+* s_bsd.c: finish this stage of net code work
+* *.c, *.h: rewrite select and poll code, add listener.[ch] net.code overhaul
+    in progress, prepare for adding auth module
+* s_bsd.h, struct.h: moved client struct macros back into struct.h for now,
+    the last place they belonged was in the network code... feh
+* ircd.c (open_debugfile): removed client for debug file
+* ircd_string.h, ircd_string.c: new files for string processing, add
+    ircd_strncpy function
+* *.c, *.h: rename ircstp to ServerStats
+* *.c, *.h: rename now to CurrentTime
+* listener.h, listener.c: new files for listener ports
+* include/ircd_defs.h: new file for global definitions (HOSTLEN, USERLEN)
+* struct.h: add local_flag to client struct, to make local/remote detection simpler
+* s_bsd.c (read_message): split out separate versions for select and poll
+* s_bsd.h, various source files: remove the rest of the unix domain socket 
+    support this removes a number of comparisons that were unneeded in 
+    code that should run reasonably fast.
+* os_*.c, res.c, ircd_osdep.h: add os_recvfrom_nonb for resolver
+* os_*.c, s_bsd.c, s_auth.c, ircd_osdep.h: add os_get_sockname, os_get_peername
+* bsd.h, bsd.c: merge into s_bsd
+* ircd_osdep.h, os_generic.c, os_linux.c, ircd_osdep.h: move os variable stuff
+    to separate compilation units, os generic contains the original code
+    (start here). 
+* s_bsd.c, send.c, struct.h: remove pyr (pyramid) finally
+* res.h, res.c, s_misc.c: cleanup headers/dependencies in res.h
+* match.h: include sys/types.h before netinet/in.h, broken BSD system headers
+* ircd/Makefile.in: remove CFLAGS from link line, use LDFLAGS instead
+* ircd.c: add missing include for sys/socket.h
+* common.h (strChattr, strCasediff): remove pointless non-portable inline
+    decls. The functions are complex enough that inlining just bloats the code
+* ircd_xopen.h, ircd_xopen.c, s_user.c, s_serv.c: porting layer for crypt and
+    other xopen library calls, moved crypt to ircd_xopen.
+* s_uping.c, s_uping.h, s_bsd.c, s_misc.c, s_bsd.h, ircd.c, s_debug.c:
+    Removed s_ping. There are much better tools available that actually work
+    correctly. The s_ping code was a waste of resources, and has historically
+    given incorrect results (it never worked correctly).
+* ircd/s_bsd.c, res.c, s_user.c, s_serv.c: little fixups to allow code to
+    build on Solaris, still have some warnings there.
+    TODO: wrap crypt and things that depend on _XOPEN_SOURCE in their own
+    file so it doesn't bother the network code.
+* ircd/s_bsd.c: cast option arg to const char* for setsockopt (solaris)
+* ircd/Makefile.in: removed hard coded dependencies for hash.o chkconfig.o,
+    let the automatic stuff take care of it, it does it better than humans.
+* *.c *.h: remove register keywords, attribute macro junk, cleanup
+    dependencies, rename MIN and MAX to IRCD_MIN IRCD_MAX all headers in
+    C files are sorted, removed as many duplicate includes as I could find
+    (dozens) general cleanups. Mutter the correct runes to get the protoype
+    for crypt included where it was needed.
+* *.c *.h: dependency cleanups up to querycmds.c
+* ircd.c, bsd.c, s_bsd.c: move signal handling code to ircd_signal.c
+* ircd_signal.c, ircd_signal.h: new files, use only POSIX signals remove
+    support for unreliable signals.
+* *.h *.c: include guards, dependency cleanups
+* Configure.in, setup-sh.in: include guards, config.h includes setup.h
+    add config dir to include path
+* sys.h: include guards, remove hard coded path to config.h
+* s_user.c (hunt_server): fix logic bug
+* numnicks.c (SetServerYXX): fix off by one error
+* multiple files (n2k patch): add code to handle extended numerics
diff --git a/doc/history/ChangeLog.11 b/doc/history/ChangeLog.11
new file mode 100644 (file)
index 0000000..cc8a9ca
--- /dev/null
@@ -0,0 +1,4169 @@
+2002-01-08  Perry Lorier  <isomer@coders.net>
+       * Fixed the build system -- MAKEFILES is *not* a variable you can
+       just use in a makefile :)
+       * Added "Quit: " prefix to quit messages.
+
+2001-10-14  Perry Lorier  <isomer@coders.net>
+       * Minor fixes to the below
+
+2001-09-21  Perry Lorier  <isomer@coders.net>
+       * ircd/send.c and various: replace sendcmdto_flag_butone with
+       sendwallto_group_butone
+
+2001-09-21  Vampire-  <unknown>
+       * ircd/ircd_string.c: unique_name_vector round II.
+
+2001-09-21  mbuna  <mbuna@undernet.org>
+       * configure.in: Add support for darwin
+
+2001-09-21  Perry Lorier  <isomer@coders.net>
+       * ircd/s_user.c I'm stupid, s/acptr/from/, Hektik pointed it out
+
+2001-09-20  Perry Lorier  <isomer@coders.net>
+
+       * Pullups from 2.10.10.pl16
+       * Added some warnings, and the concept of rate limited snotices
+
+2001-08-31  Kevin L Mitchell  <klmitch@mit.edu>
+
+       * ircd/channel.c: use "%u" to format limit arguments; use
+       strtoul() to process limit arguments in a /mode command--note:
+       most clients seem to truncate the integer, probably because
+       they're using atoi, and perhaps signed ints
+
+2001-08-17  Kevin L Mitchell  <klmitch@mit.edu>
+
+       * ircd/numnicks.c: include stdlib.h for exit()
+
+       * ircd/ircd_log.c: include stdlib.h for exit()
+
+       * ircd/ircd_events.c: include stdlib.h for exit()
+
+       * ircd/s_stats.c: remove description of /stats v, since it's gone
+
+       * ircd/m_wallops.c (mo_wallops): add "*" to the beginning of
+       /wallops to distinguish wallops from wallusers
+
+       * ircd/m_error.c (mr_error): ignore ERROR from clients that aren't
+       in the "handshake" or "connecting" states--I think the latter will
+       never happen, but...
+
+       * doc/Authors: apply delete's Authors patch
+
+       * RELEASE.NOTES: rewrite RELEASE.NOTES, basing it a little on
+       Braden's version
+
+       * README: rewrite README
+
+2001-07-31  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/s_serv.c (server_estab): remove unused variable split
+
+       * ircd/parse.c: add mr_error to the parse table
+
+       * ircd/m_error.c (mr_error): add mr_error() to handle ERRORs from
+       unregistered connections--if IsUserPort() is true, the ERROR is
+       ignored, otherwise, the message is saved
+
+2001-07-28  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/m_kill.c (ms_kill): another minor typo *sigh*
+
+       * ircd/s_user.c (send_supported): oops, minor typo...
+
+       * ircd/s_user.c: implement send_supported() to send two ISUPPORT
+       messages containing our feature buffers; make register_user() use
+       send_supported()
+
+       * ircd/s_misc.c (exit_client): make sure not to give away a remote
+       server in the ERROR message sent to the client; if the killer is a
+       server, we substitute our name in its place
+
+       * ircd/m_version.c (m_version): use send_supported() to send the
+       ISUPPORT values to the user
+
+       * ircd/m_nick.c: shave nick collision kills here a bit, too, for
+       the same reasons as for m_kill.c
+
+       * ircd/m_kill.c: shave kills a bit so that the results look
+       exactly the same no matter where you are; if we didn't do this, it
+       would be possible to map the network by looking at the differences
+       between kills originating under various circumstances
+
+       * include/supported.h: split the features into two, so as to not
+       bust the parameter count when sending the features list
+
+       * include/s_user.h: declare new send_supported() function to send
+       the ISUPPORT information
+
+2001-07-27  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/s_bsd.c: disable IP (*not* TCP) options to prevent
+       source-routed spoofing attacks; this is only available under
+       u2.10.11, so don't even bother, since no one but testers are using
+       the source base
+
+2001-07-25  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * include/ircd_policy.h: enable HEAD_IN_SAND_REMOTE by default
+
+       * ircd/s_err.c: put in a . for reporting link version on /trace,
+       to match what /version does
+
+2001-07-21  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/s_misc.c (exit_client): servers don't understand what the
+       numeric nick ERROR is supposed to mean, so they ignore error
+       messages, resulting in not knowing why we were rejected; use
+       sendcmdto_one for servers and sendrawto_one for clients
+
+2001-07-17  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/m_burst.c (ms_burst): in the case of a modeless channel and
+       a nick collide, a bare BURST may be propagated; adjust the
+       enforced parameter count to accept the bare BURST
+
+2001-07-12  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/s_bsd.c: mark a client as having been IP checked
+
+       * ircd/IPcheck.c (ip_registry_check_remote): remove unneeded
+       second call to SetIPChecked()
+
+2001-07-11  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/engine_poll.c: deal with POLLHUP properly (hopefully)
+
+       * ircd/engine_devpoll.c: deal with POLLHUP properly (hopefully)
+
+2001-07-09  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/os_bsd.c (os_get_rusage): move buf into the two ifdef'd
+       sections so that if neither is used, the declaration of buf will
+       not elicit an "unused variable" warning under NetBSD
+
+       * ircd/m_map.c: include string.h to declare strcpy (fix warnings
+       on alpha)
+
+       * ircd/m_away.c: include string.h to declare strcpy/strlen (fix
+       warnings on alpha)
+
+       * ircd/ircd_log.c: include string.h to declare strcpy/strlen (fix
+       warnings on alpha)
+
+       * ircd/client.c: include string.h to declare memset (fix warnings
+       on alpha)
+
+       * ircd/channel.c: remove unused functions next_overlapped_ban,
+       del_banid, and is_deopped (fix warnings under -O1)
+
+       * ircd/IPcheck.c: include string.h to declare memset/memcpy (fix
+       warnings on alpha)
+
+2001-06-29  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/s_user.c (set_user_mode): clear the snomask if the user
+       isn't supposed to receive server notices anymore
+
+       * ircd/ircd_features.c: change CONFIG_OPERCMDS to default to FALSE
+
+       * configure.in: use AC_MSG_CHECKING/AC_MSG_RESULT when checking
+       installation prefix; default devpoll and kqueue to on (they get
+       turned off if the required headers aren't present)
+
+       * ircd/whocmds.c (do_who): use ircd_snprintf() instead of
+       sprintf_irc(); it's a bit hackish, but it'll do for now
+
+       * ircd/support.c: remove unused #include
+
+       * ircd/send.c: remove unused #include
+
+       * ircd/s_user.c: use ircd_snprintf() instead of sprintf_irc()
+
+       * ircd/s_serv.c: remove unused #include
+
+       * ircd/s_misc.c: use ircd_snprintf() and friends instead of
+       sprintf_irc() and friends
+
+       * ircd/s_err.c: moved atoi_tab[] from ircd/sprintf_irc.c to
+       ircd/s_err.c, which is the only other file to refer to it
+
+       * ircd/s_conf.c (conf_add_deny): use ircd_snprintf() instead of
+       sprintf_irc()
+
+       * ircd/s_bsd.c (connect_server): use ircd_snprintf() instead of
+       sprintf_irc()
+
+       * ircd/s_auth.c: use ircd_snprintf() instead of sprintf_irc()
+
+       * ircd/res.c: use ircd_snprintf() instead of sprintf_irc()
+
+       * ircd/m_version.c: use ircd_snprintf() instead of sprintf_irc()
+
+       * ircd/m_kill.c: use ircd_snprintf() instead of sprintf_irc()
+
+       * ircd/listener.c: use ircd_snprintf() instead of sprintf_irc()
+
+       * ircd/gline.c: use ircd_snprintf() instead of sprintf_irc()
+
+       * ircd/channel.c: don't include sprintf_irc.h; use ircd_snprintf()
+       instead of sprintf_irc()
+
+       * ircd/Makefile.in: remove sprintf_irc.c from sources list; run
+       make depend
+
+       * include/ircd_string.h: remove declaration of sprintf_irc() (what
+       was it doing here anyway?)
+
+       * include/sprintf_irc.h: removed unneeded source file
+
+       * ircd/sprintf_irc.c: removed unneeded source file
+
+       * ircd/s_debug.c (count_memory): remove some dead code
+
+       * ircd/s_auth.c: remove some dead code
+
+       * ircd/res.c (update_list): remove some dead code
+
+       * ircd/m_whowas.c: remove some dead code
+
+       * ircd/m_whois.c: remove some dead code
+
+       * ircd/m_who.c: remove some dead code
+
+       * ircd/m_wallusers.c: remove some dead code
+
+       * ircd/m_wallops.c: remove some dead code
+
+       * ircd/m_wallchops.c: remove some dead code
+
+       * ircd/m_version.c: remove some dead code
+
+       * ircd/m_userip.c: remove some dead code
+
+       * ircd/m_userhost.c: remove some dead code
+
+       * ircd/m_uping.c: remove some dead code
+
+       * ircd/m_trace.c: remove some dead code
+
+       * ircd/m_topic.c: remove some dead code
+
+       * ircd/m_tmpl.c: remove some dead code
+
+       * ircd/m_time.c: remove some dead code
+
+       * ircd/m_squit.c: remove some dead code
+
+       * ircd/m_silence.c: remove some dead code
+
+       * ircd/m_settime.c: remove some dead code
+
+       * ircd/m_set.c: remove some dead code
+
+       * ircd/m_server.c: remove some dead code
+
+       * ircd/m_rpong.c: remove some dead code
+
+       * ircd/m_rping.c: remove some dead code
+
+       * ircd/m_restart.c: remove some dead code
+
+       * ircd/m_reset.c: remove some dead code
+
+       * ircd/m_rehash.c: remove some dead code
+
+       * ircd/m_quit.c: remove some dead code
+
+       * ircd/m_proto.c: remove some dead code
+
+       * ircd/m_privs.c: remove some dead code
+
+       * ircd/m_privmsg.c: remove some dead code
+
+       * ircd/m_pong.c: remove some dead code
+
+       * ircd/m_ping.c: remove some dead code
+
+       * ircd/m_pass.c: remove some dead code
+
+       * ircd/m_part.c: remove some dead code
+
+       * ircd/m_opmode.c: remove some dead code
+
+       * ircd/m_oper.c: remove some dead code
+
+       * ircd/m_notice.c: remove some dead code
+
+       * ircd/m_nick.c: remove some dead code
+
+       * ircd/m_map.c: remove some dead code
+
+       * ircd/m_lusers.c: remove some dead code
+
+       * ircd/m_list.c: remove some dead code
+
+       * ircd/m_links.c: remove some dead code
+
+       * ircd/m_kill.c: remove some dead code
+
+       * ircd/m_kick.c: remove some dead code
+
+       * ircd/m_jupe.c: remove some dead code
+
+       * ircd/m_join.c: remove some dead code
+
+       * ircd/m_ison.c: remove some dead code
+
+       * ircd/m_invite.c: remove some dead code
+
+       * ircd/m_info.c: remove some dead code
+
+       * ircd/m_help.c: remove some dead code
+
+       * ircd/m_gline.c: remove some dead code
+
+       * ircd/m_get.c: remove some dead code
+
+       * ircd/m_error.c: remove some dead code
+
+       * ircd/m_endburst.c: remove some dead code
+
+       * ircd/m_die.c: remove some dead code
+
+       * ircd/m_desynch.c: remove some dead code
+
+       * ircd/m_destruct.c: remove some dead code
+
+       * ircd/m_defaults.c: remove some dead code
+
+       * ircd/m_create.c: remove some dead code, along with an #if 1
+
+       * ircd/m_cprivmsg.c: remove some dead code
+
+       * ircd/m_connect.c: remove some dead code
+
+       * ircd/m_close.c: remove some dead code
+
+       * ircd/m_clearmode.c: remove some dead code
+
+       * ircd/m_burst.c: remove some dead code
+
+       * ircd/m_away.c: remove some dead code
+
+       * ircd/m_admin.c: remove some dead code
+
+       * ircd/listener.c (accept_connection): remove some dead code
+
+       * ircd/ircd_reply.c (need_more_params): remove some dead code
+
+       * ircd/channel.c (add_banid): remove some dead code
+
+       * include/support.h: remove some dead code
+
+       * include/querycmds.h: remove some dead code
+
+       * doc/readme.chroot: document how to do chroot operation
+
+2001-06-28  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/Makefile.in: tune for VPATH builds/installs; add a rule to
+       force bin directory to be created if necessary prior to
+       installation; run make depend
+
+       * doc/Makefile.in (install): tune for VPATH installs by cd'ing to
+       the ${srcdir}
+
+       * Makefile.in: tune to detect Makefile.in changes in
+       subdirectories and to create installation directory indicated by
+       ${prefix}
+
+       * ircd/whocmds.c (count_users): routine to count the number of
+       users matching a given user@host mask
+
+       * ircd/s_err.c: add error messages for ERR_LONGMASK,
+       ERR_TOOMANYUSERS, and ERR_MASKTOOWIDE
+
+       * ircd/m_gline.c: look for and advance past '!' flag on G-lines
+       from operators; only set GLINE_OPERFORCE flag if oper has the
+       PRIV_WIDE_GLINE privilege
+
+       * ircd/ircd_features.c: add GLINEMAXUSERCOUNT, which is the
+       maximum number of users a G-line can impact before it has to be
+       forced; OPER_WIDE_GLINE, to allow operators to use ! to force a
+       wide G-line to be set; and LOCOP_WIDE_GLINE, to allow local
+       operators to use ! to force a wide G-line to be set
+
+       * ircd/gline.c: make make_gline() be called with separate user and
+       host arguments, and not call canon_userhost() directly; implement
+       gline_checkmask() to verify that a host mask is acceptable; move
+       BADCHAN check up in gline_add(), and check passed-in mask under
+       certain circumstances for acceptability; fix call to
+       sendto_opmask_butone() to handle separation of userhost into user
+       and host in gline_add(); update call to make_gline()
+
+       * ircd/client.c: use FEAT_OPER_WIDE_GLINE and
+       FEAT_LOCOP_WIDE_GLINE to set PRIV_WIDE_GLINE for an operator; add
+       PRIV_WIDE_GLINE to privtab[] for client_report_privs()
+
+       * include/whocmds.h (count_users): declare routine to count users
+       matching a given user@host mask
+
+       * include/numeric.h: added three new error returns: ERR_LONGMASK
+       -- mask can't be formatted into a buffer; ERR_TOOMANYUSERS -- too
+       many users would be impacted by the mask; ERR_MASKTOOWIDE -- mask
+       contains wildcards in the wrong places
+
+       * include/ircd_features.h: add FEAT_GLINEMAXUSERCOUNT,
+       FEAT_OPER_WIDE_GLINE, and FEAT_LOCOP_WIDE_GLINE
+
+       * include/gline.h (GLINE_OPERFORCE): provides a way for m_gline()
+       to signal to gline_add() that the operator attempted to force the
+       G-line to be set
+
+       * include/client.h (PRIV_WIDE_GLINE): new privilege for operators
+
+       * doc/readme.gline: update to document new "!" prefix to a G-line
+       user@host mask
+
+       * doc/readme.features: document GLINEMAXUSERCOUNT,
+       OPER_WIDE_GLINE, and LOCOP_WIDE_GLINE
+
+       * doc/example.conf: update to mention new features along with
+       their defaults
+
+2001-06-27  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * doc/example.conf: updated example.conf from Braden
+       <dbtem@yahoo.com>
+
+       * include/supported.h: forward-port from pl15
+
+2001-06-25  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/whocmds.c: include ircd_policy.h and implement
+       HEAD_IN_SAND_WHO_OPCOUNT--forward-port from pl15
+
+       * ircd/m_whois.c: forward-port of the idle-time hiding code from
+       pl15; this also required passing parc into do_whois(), which also
+       meant passing parc into do_wilds()--*sigh*
+
+       * include/ircd_policy.h: add a couple more HEAD_IN_SAND
+       #define's--WHOIS_IDLETIME and WHO_HOPCOUNT
+
+2001-06-22  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * tools/wrapper.c: add a wrapper program that can be used to
+       adjust file descriptor limits and root directories; program must
+       be run as root--NOT SETUID!--and given appropriate -u arguments
+
+       * doc/readme.log: documentation of how to configure logging
+
+       * doc/readme.features: documentation of each feature (except for
+       logging)
+
+2001-06-21  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * Makefile.in (config): add a deprecation notice with a pointer to
+       tools/transition
+
+       * tools/transition: shell script to convert old compile-time
+       options into new compile-time options and appropriate F-lines
+
+       * tools/mkchroot: shell-script to prepare the chroot area by
+       copying over all the necessary libraries so they can be found
+
+2001-06-20  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * INSTALL: partial update of INSTALL for u2.10.11 release...
+
+2001-06-14  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/table_gen.c (makeTables): finally got tired of the
+       "overflow in implicit conversion" warning, so just got rid of it
+       by explicitly casting UCHAR_MAX to a (default) char; diffs show no
+       differences in the tables generated
+
+2001-06-11  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/send.c (sendcmdto_match_butone): don't let the server crash
+       if a client is in the STAT_CONNECTING status
+
+2001-06-10  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/send.c: remove unused vsendcmdto_one(), consolidating it
+       into sendcmdto_one(); define new sendcmdto_prio_one(), which
+       places the message into the priority queue
+
+       * ircd/s_user.c (hunt_server_prio_cmd): definition of
+       hunt_server_prio_cmd(), which simply calls sendcmdto_prio_one()
+       instead of sendcmdto_one()
+
+       * ircd/m_settime.c: use sendcmdto_prio_one() and
+       hunt_server_prio_cmd() to send SETTIME
+
+       * ircd/m_server.c: use sendcmdto_prio_one() to send SETTIME
+
+       * include/send.h: removed declaration for unused vsendcmdto_one();
+       added a declaration for sendcmdto_prio_one()
+
+       * include/s_user.h: declare hunt_server_prio_cmd(), which calls
+       sendcmdto_prio_one()
+
+       * ircd/send.c (sendcmdto_flag_butone): oops; /wallops should be
+       put in the server's priority queue, too...
+
+       * ircd/ircd.c: don't check LPATH for accessibility at all
+
+2001-06-08  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/s_serv.c (server_estab): send a +h flag in our SERVER
+       command if we're configured as a hub; send individual server flags
+       in SERVER commands
+
+       * ircd/s_bsd.c (completed_connection): send a +h flag in our
+       SERVER command if we're configured as a hub
+
+       * ircd/m_server.c: implement parv[7] as a mode-like string; +h
+       sets the FLAGS_HUB flag for a server; +s sets the FLAGS_SERVICE
+       flag for a server; +hs sets both flags; also modify CMD_SERVER
+       format string to send the flags
+
+       * include/client.h: define two new flags, FLAGS_HUB and
+       FLAGS_SERVICE to mark services and hubs as such; define testing
+       macros, setting macros
+
+       * ircd/s_user.c: remove deprecated struct Gline* argument to
+       register_user(); remove GLINE rebroadcast; do not send GLINE
+       acknowledgement parameter to NICK; do not look for GLINE
+       acknowledgement parameter to NICK while parsing
+
+       * ircd/s_serv.c (server_estab): remove deprecated struct Jupe*
+       argument to server_estab(); do not send JUPE/GLINE acknowledgement
+       parameters for SERVER or NICK
+
+       * ircd/m_user.c (m_user): remove deprecated argument to
+       register_user()
+
+       * ircd/m_server.c: remove deprecated argument to server_estab();
+       remove documentation comment regarding JUPE acknowledgement
+       parameter to SERVER; remove JUPE rebroadcast
+
+       * ircd/m_pong.c (mr_pong): remove deprecated argument to
+       register_user()
+
+       * ircd/m_nick.c: remove documentation comment regarding GLINE
+       acknowledgement parameter to NICK
+
+       * ircd/jupe.c: use user's real name in JUPE server notices if
+       HEAD_IN_SAND_SNOTICES is defined
+
+       * ircd/ircd.c: remove deprecated chroot() code; remove deprecated
+       setuid code; correct ancient DEBUG vs DEBUGMODE typo
+
+       * ircd/gline.c: use user's real name in GLINE server notices if
+       HEAD_IN_SAND_SNOTICES is defined
+
+       * ircd/channel.c (modebuf_flush_int): make apparent source be
+       local server, not oper's server; use user's real name in hack
+       notices and DESYNC notices if HEAD_IN_SAND_SNOTICES is defined
+
+       * include/s_user.h: remove struct Gline pre-declaration; remove
+       deprecated struct Gline argument from register_user()
+
+       * include/s_serv.h: remove struct Jupe pre-declaration; remove
+       deprecated struct Jupe argument from server_estab()
+
+2001-06-07  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/s_stats.c (hunt_stats): forward-port from pl15 of all the
+       changes required to control remote stats
+
+       * ircd/s_numeric.c (do_numeric): rewrite numeric origins if
+       recipient is not an operator and HEAD_IN_SAND_REWRITE is defined
+       [forward-port from pl15]
+
+       * ircd/m_whowas.c (m_whowas): report server name only if requester
+       is an operator [forward-port from pl15]
+
+       * ircd/m_whois.c (do_whois): /whois <mynick> now correctly reports
+       my server; if HEAD_IN_SAND_REMOTE is 1, ignore the middle argument
+       and obtain the report from the user's server [forward-port from
+       pl15]
+
+       * ircd/m_who.c: add missing include for ircd_policy.h
+       [forward-port from pl15]
+
+       * ircd/m_version.c (m_version): require oper access for remote
+       /version if HEAD_IN_SAND_REMOTE is 1 [forward-port from pl15]
+
+       * ircd/m_time.c (m_time): require oper access for remote /time if
+       HEAD_IN_SAND_REMOTE is 1 [forward-port from pl15]
+
+       * ircd/m_stats.c: pass extra argument to hunt_stats(); correct
+       missing semicolon [forward-port from pl15]
+
+       * ircd/m_nick.c (ms_nick): hide the origin of certain collision
+       kills [forward-port from pl15]
+
+       * ircd/m_motd.c (m_motd): require oper access for remote /motd if
+       HEAD_IN_SAND_REMOTE is 1 [forward-port from pl15]
+
+       * ircd/m_lusers.c (m_lusers): require oper access for remote
+       /lusers if HEAD_IN_SAND_REMOTE is 1 [forward-port from pl15]
+
+       * ircd/m_burst.c (ms_burst): server-added bans are stored using
+       local server name, to hide remote server names; modes also are to
+       originate from the local server [forward-port from pl15]
+
+       * ircd/m_admin.c (m_admin): require oper access for remote /admin
+       if HEAD_IN_SAND_REMOTE is 1 [forward-port from pl15]
+
+       * ircd/channel.c (add_banid): if a server is adding a ban, use my
+       server name to hide the remote server's name [forward-port from
+       pl15]
+
+       * ircd/Makefile.in: ran make depend
+
+       * include/s_stats.h: hunt_stats() has to have an extra argument to
+       support the forward-port from pl15
+
+       * include/ircd_policy.h: #define HEAD_IN_SAND_STATS_P; add
+       HEAD_IN_SAND_{BANWHO,REWRITE,REMOTE} [forward-port from pl15]
+
+       * ircd/engine_poll.c (engine_loop): remove bogus assert that I
+       forgot to check in the events branch
+
+2001-06-06  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/res.c (init_resolver): don't start DNS expires with a 0
+       relative timeout--if the server starts slow, timeouts could be
+       messy...there's probably a better solution, but this'll do for now
+
+       * ircd/os_solaris.c: _XOPEN_SOURCE doesn't get along with Solaris
+       headers very well; include stropts.h; define an os_set_tos()
+
+       * ircd/os_generic.c (os_set_tos): added an os_set_tos() for
+       os_generic.c
+
+       * ircd/ircd.c: if there are no C-lines, we don't want to have a
+       timer that expires at the absolute time of 0--it kinda blocks all
+       the other timers!
+
+       * ircd/engine_devpoll.c: some includes for open(); declare errcode
+       and codesize in engine_loop()
+
+       * ircd/list.c (free_client): remove bogus check on timer active
+       flag
+
+       * ircd/s_auth.c: pull out destruction code in
+       auth_timeout_request() into an externally-visible
+       destroy_auth_request(); manage cli_auth pointer in client
+       structure; use it for an extra assertion check
+
+       * ircd/list.c: include s_auth.h for destroy_auth_request(); add
+       debugging notices to show flow when deallocating
+       connections/clients; call destroy_auth_request() when free'ing a
+       client that has an auth outstanding; don't free the connection if
+       the process timer is unmarked but still active
+
+       * ircd/ircd_events.c: set GEN_ACTIVE when initializing a generator
+       and reset it before calling the event handler for an ET_DESTROY
+       event
+
+       * include/s_auth.h (destroy_auth_request): declare
+       destroy_auth_request(), which can be used to destroy an
+       outstanding auth request if a client socket goes away before the
+       auth exchange is completed
+
+       * include/ircd_events.h: add an active flag to keep track of
+       whether or not particular generators are active, for the
+       convenience of functions using the API
+
+       * include/client.h: add a pointer for auth requests to struct
+       Connection so we can kill outstanding auth requests if a client
+       socket closes unexpectedly
+
+       * ircd/s_bsd.c: cli_connect() could become 0 during the course of
+       the sock or timer callback; take that into account in the assert
+
+       * ircd/list.c: add magic number checking and setting--magic
+       numbers are zero'd on frees to detect double-frees; add back
+       setting of cli_from() to 0 to break the back-link from the struct
+       Connection (duh)
+
+       * ircd/ircd.c: set me's magic number correctly
+
+       * include/client.h: define magic numbers and accessor/verifier
+       macros
+
+       * ircd/list.c: assert that dealloc_client() is called with
+       cli_connect(cptr) == 0; set cli_connect(cptr) to 0 before calling
+       dealloc_client(); don't mess with cli_from(cptr)
+
+       * ircd/s_bsd.c: only attempt to dealloc a connection if the
+       associated client has already been destroyed, or at least delinked
+
+2001-06-05  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/list.c (free_client): only try to delete the socket when
+       the fd hasn't already been closed, avoiding a double-free
+
+       * ircd/list.c (free_connection): make sure the client is really
+       gone before doing away with the connection
+
+       * ircd/s_bsd.c: record that socket has been added in con_freeflag
+       field; queue a socket_del() as soon as the socket is close()'d;
+       use con_freeflag & FREEFLAG_TIMER instead of con_timer; clear
+       FREEFLAG_SOCKET on ET_DESTROY event in client_sock_callback(),
+       then dealloc the connection if safe; mark socket as dead when
+       there's a read error or EOF; clear FREEFLAG_TIMER flag upon entry
+       to client_timer_callback(); dealloc connection if safe upon
+       ET_DESTROY event in client_timer_callback()
+
+       * ircd/list.c: use con_freeflag instead of con_timer; only dealloc
+       the connection if both socket and timer have been destroyed;
+       destroy both socket and timer explicitly and carefully
+
+       * include/client.h: replace the con_timer field with a
+       con_freeflag field, to indicate what still needs freeing; define
+       the freeflags
+
+       * ircd/engine_select.c (engine_loop): duh...sockList[i] could
+       become 0
+
+       * ircd/engine_devpoll.c (engine_loop): duh...sockList[i] could
+       become 0
+
+       * ircd/s_bsd.c: add some extra assertions to try to track down a
+       corruption problem
+
+       * ircd/engine_select.c (engine_loop): add an extra assert to try
+       to track down a corruption problem
+
+       * ircd/engine_poll.c (engine_loop): add an extra assert to try to
+       track down a corruption problem
+
+       * ircd/engine_kqueue.c (engine_loop): add an extra assert to try
+       to track down a corruption problem
+
+       * ircd/engine_devpoll.c (engine_loop): skip slots that have become
+       empty during processing; add an extra assert to try to track down
+       a corruption problem
+
+       * ircd/engine_kqueue.c (engine_delete): make sure to zero deleted
+       entries
+
+2001-06-04  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/s_bsd.c (client_sock_callback): client is no longer
+       blocked, so we must mark it as unblocked
+
+       * ircd/engine_select.c: add Debug() calls galore; add handling for
+       SS_NOTSOCK; use a dummy sock variable to keep things from
+       disappearing on us; correct timeout calculation; update nfds for
+       efficiency
+
+       * ircd/engine_poll.c: use new debugging level (DEBUG_ENGINE);
+       remove a spurious "if (sock)" which will always be true; update
+       nfds for efficiency
+
+       * ircd/engine_kqueue.c: add Debug() calls galore; add handling for
+       SS_NOTSOCK (just in case); correct timeout calculation
+
+       * ircd/engine_devpoll.c: add Debug() calls galore; add handling
+       for SS_NOTSOCK; correct timeout calculation; add EAGAIN handling
+
+       * include/s_debug.h (DEBUG_ENGINE): add new debugging level;
+       pretty-indent numbers
+
+       * ircd/engine_poll.c (engine_loop): break out SS_NOTSOCK
+       case--it's not a socket; the check for writability is most likely
+       not needed, but present for completeness
+
+2001-05-24  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/s_bsd.c: add Debug messages; call read_packet() even if the
+       no newline flag is set; call read_packet() when the timer expires,
+       regardless of what's in the buffer--read_packet() should be able
+       to deal properly
+
+       * ircd/IPcheck.c (ip_registry_connect_succeeded): correct a NOTICE
+       sent to clients to include the client nickname (duh)
+
+       * ircd/ircd_events.c: don't destroy a timer if it's already marked
+       for destruction; replace a missing ! in socket_del()
+
+       * ircd/engine_poll.c (engine_loop): reference a temporary variable
+       so we don't have to worry about sockList[i] going away
+
+       * ircd/s_bsd.c (client_sock_callback): add Debug messages
+
+       * ircd/s_auth.c: add Debug messages all over the place
+
+       * ircd/ircd_events.c: add and edit some Debug messages; add a list
+       of routines to convert some of the enums and flags from numbers
+       into human-readable strings for the Debug messages
+
+       * ircd/engine_poll.c: hack some Debug messages to use the new name
+       conversion routines in ircd_events.c; add an extra assert for a
+       condition that shouldn't ever happen; apparently recv() can return
+       EAGAIN when poll() returns readable--I wonder why...
+
+       * include/ircd_events.h: declare some helper routines under
+       DEBUGMODE
+
+2001-05-23  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/s_bsd.c (client_sock_callback): add an extra assertion
+       check
+
+       * ircd/s_auth.c: add more Debug messages
+
+       * ircd/list.c (make_client): add an extra assertion check
+
+       * ircd/ircd_events.c (socket_events): don't call the engine events
+       changer if we haven't actually made any changes to the event mask
+
+       * ircd/uping.c: add some Debug messages
+
+       * ircd/s_stats.c: document new /STATS e
+
+       * ircd/s_err.c: add RPL_STATSENGINE to report the engine name
+
+       * ircd/s_bsd.c: remove static client_timer variable; in
+       read_packet(), if there's still data in the client's recvQ after
+       parsing, add a 2 second timer (con_proc); fix the ET_DESTROY case
+       of client_sock_callback to handle destroying the timer properly;
+       rewrote client_timer_callback from scratch to be called on an
+       individual client
+
+       * ircd/m_stats.c: add /STATS e to report the engine name
+
+       * ircd/list.c: deal with con_timer field in struct Connection
+       properly; correct a core-level bug in remove_client_from_list--if
+       the client is the only one in the list, we try to update
+       GlobalClientList's cli_prev pointer--not good
+
+       * ircd/ircd.c: remove call to init_client_timer()
+
+       * ircd/engine_poll.c: made Debug messages more uniform by
+       prepending "poll:" to them all; corrected an off-by-one error that
+       caused poll_count to be 1 less than the actual count and removed
+       my work-around; added Debug messages to indicate which socket is
+       being checked and what the results are
+
+       * ircd/Makefile.in: ran a make depend
+
+       * include/s_bsd.h: remove init_client_timer(), since we're doing
+       it differently now
+
+       * include/numeric.h (RPL_STATSENGINE): a stats reply to report the
+       engine name
+
+       * include/ircd_policy.h (HEAD_IN_SAND_STATS_E): turn off /stats e
+       reports for non-opers
+
+       * include/client.h: add con_timer and con_proc fields to struct
+       Connection and define accessor macros--con_timer marks that
+       con_proc contains a valid timer, and con_proc is used to pace user
+       data
+
+       * ircd/s_bsd.c (close_connection): let free_client() destroy the
+       socket
+
+       * ircd/s_auth.c (start_auth): add a Debug call to indicate when
+       auth has begun on a client
+
+       * ircd/ircd_events.c: ensure that event_execute() is called with a
+       non-NULL event; modify event_add() macro to properly zero list
+       bits; modify gen_dequeue() to not try to clip it out of a list
+       it's already been clipped out of; change signal socket
+       initialization to use state SS_NOTSOCK; permit timeout values of
+       0 in add_timer(); add many Debug calls; change socket_del() and
+       timer_del() to always set the GEN_DESTROY flag; use GEN_MARKED in
+       timer_run() instead of GEN_DESTROY so that event_generate() will
+       pass on the events; remove the switch and replace with a simpler
+       if-then-else tree in timer_run(); don't allow destroyed sockets to
+       be destroyed again, nor their states or event masks to be changed
+
+       * ircd/ircd.c: initialize "running" to 1
+
+       * ircd/engine_poll.c: deal with SS_NOTSOCK "sockets"; add Debug
+       messages all over the place; fix a counting problem in
+       engine_add(); turn wait into a signed integer and set it to -1
+       only if timer_next() returns 0; adjust wait time to be relative;
+       don't call gen_ref_dec() if socket disappeared while we were
+       processing it
+
+       * include/ircd_events.h: the pipe for signals is not a socket, so
+       we must mark it as such--added SS_NOTSOCK for that special socket;
+       events won't be generated if GEN_DESTROY is on, so add GEN_MARKED
+       for the benefit of timer_run()
+
+       * configure.in: add --enable-pedantic and --enable-warnings to
+       turn on (and off) -Wall -pedantic in CFLAGS
+
+2001-05-21  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/s_conf.c: change "s_addr" element accesses to "address"
+       element accesses
+
+       * include/s_conf.h: on some systems, "s_addr" is a macro; use
+       "address" instead
+
+2001-05-18  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/engine_kqueue.c: include ircd_alloc.h; set_or_clear returns
+       void in this file; add a missing semi-colon; declare errcode,
+       codesize
+
+       * ircd/uping.c (uping_sender_callback): it's pptr, not uping
+
+       * ircd/s_user.c (register_user): comment out spurious reference to
+       nextping
+
+       * ircd/s_serv.c (server_estab): comment out spurious reference to
+       nextping
+
+       * ircd/s_conf.c (read_configuration_file): comment out spurious
+       reference to nextping and nextconnect
+
+       * ircd/s_bsd.c: comment out some spurious references to formerly
+       global (now non-existant) variables; correct a couple of typos
+
+       * ircd/s_auth.c: pre-declare some functions referenced in the
+       callback; correct a typo
+
+       * ircd/res.c (start_resolver): pass errno value of ENFILE
+
+       * ircd/listener.c (accept_connection): you know your API is messed
+       up when...variables that shouldn't have been global crop up in
+       other files
+
+       * ircd/list.c (free_client): substitution of == for =
+
+       * ircd/ircd_signal.c: include assert.h for assertion checking;
+       check ev_data() to find out what signal generated event
+
+       * ircd/ircd_events.c: some references to the variable "timer"
+       should have been references to the variable "ptr"
+
+       * ircd/engine_select.c: it's struct fd_set, not struct fdset;
+       ev_timer(ev) is already a timer pointer; declare codesize as a
+       size_t to correct signedness issue; use timer_next(), not
+       time_next()
+
+       * ircd/engine_poll.c: ev_timer(ev) is already a timer pointer;
+       select fd out of struct pollfd in assertion checking; declare
+       errcode and codesize; use timer_next(), not time_next()
+
+       * ircd/engine_kqueue.c: ev_timer(ev) is already a timer pointer;
+       use function timer_next(), not time_next()
+
+       * ircd/engine_devpoll.c: ev_timer(ev) is already a timer pointer;
+       use function timer_next(), not time_next()
+
+       * ircd/Makefile.in (IRCD_SRC): add ircd_events.c to the list of
+       compiled sources; do make depend
+
+       * include/list.h: pre-declare struct Connection
+
+       * include/ircd_events.h (gen_ref_inc): cast to the right structure
+       name
+
+       * include/s_auth.h: duh; missing */
+
+2001-05-10  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/send.c: update write events status after sending data or
+       accumulating data to be sent
+
+       * ircd/m_list.c (m_list): update write events status after
+       canceling a running /list
+
+       * ircd/channel.c (list_next_channels): update write events status
+       after listing a few channels
+
+       * ircd/s_bsd.c: extensive changes to update to new events model;
+       remove on_write_unblocked() and the two implementations of
+       read_message(), which have been deprecated by this change
+
+       * ircd/s_auth.c: set the socket events we're interested in for
+       clients; simplify some logic that does the connect_nonb followed
+       by the socket_add
+
+       * ircd/list.c: define free_connection() to free a connection
+       that's become freeable once the struct Socket has been
+       deallocated; fix up free_client() to take this new behavior into
+       account
+
+       * ircd/ircd.c: call init_client_timer()
+
+       * include/s_bsd.h: declare new REGISTER_ERROR_MESSAGE when unable
+       to register connect-in-progress with events system; declare
+       init_client_timer() (HACK!) to preserve rate-limiting behavior
+
+       * include/list.h: declare new free_connection()
+
+       * include/client.h: add a struct Socket to struct Connection
+
+2001-05-09  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/ircd_signal.c: massage the handlers for SIGHUP, SIGINT, and
+       SIGTERM into event callbacks; perform the actions in the
+       callbacks, since they're not called in the context of the signal;
+       set up the signal callbacks in the event engine
+
+       * ircd/ircd_events.c (signal_callback): we're supposed to look for
+       a specific signal; don't generate an event if there is no signal
+       structure for it
+
+       * ircd/ircd.c: nuke nextconnect and nextping and replace them with
+       connect_timer and ping_timer; massage try_connections() and
+       check_pings() into timer callbacks that re-add themselves at the
+       right time; remove ircd.c's "event_loop()"; initialize the event
+       system and the connect_timer and ping_timer
+
+       * ircd/uping.c: correct a couple more typos
+
+       * ircd/s_auth.c: rework to use new events system
+
+       * ircd/os_solaris.c (os_connect_nonb): update to new interface
+
+       * ircd/os_openbsd.c (os_connect_nonb): update to new interface
+
+       * ircd/os_linux.c (os_connect_nonb): update to new interface
+
+       * ircd/os_generic.c (os_connect_nonb): update to new interface
+
+       * ircd/os_bsd.c (os_connect_nonb): update to new interface
+
+       * include/s_auth.h: remove deprecated members of struct
+       AuthRequest, replacing them with struct Socket and struct Timer
+       structures; add flags to indicate when these structures have been
+       released by the event system; remove the deprecated
+       timeout_auth_queries()
+
+       * include/ircd_osdep.h (os_connect_nonb): connect could complete
+       immediately, so change the interface to handle that possibility
+
+       * ircd/uping.c (uping_server): noticed and corrected a typo
+
+       * ircd/listener.c: set up to use ircd_event's struct Socket by
+       adding an socket_add() call to inetport(), replacing
+       free_listener() with socket_del() in close_listener(), and
+       reworking accept_connection to be called as the callback
+
+       * ircd/ircd.c: add a call to IPcheck_init()
+
+       * ircd/IPcheck.c: remove IPcheck_expire(); rework
+       ip_registry_expire() to be called from a timer; write
+       IPcheck_init() to set up the expiration timer (hard-coded for a
+       60-second expiration time)
+
+       * include/listener.h: add a struct Socket to the struct Listener;
+       remove accept_connection()
+
+       * include/IPcheck.h: add IPcheck_init(), remove IPcheck_expire()
+
+2001-05-08  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/ircd_events.c: include config.h; use USE_KQUEUE and
+       USE_DEVPOLL instead of HAVE_KQUEUE and HAVE_DEVPOLL_H
+
+       * ircd/engine_select.c: include config.h; set FD_SETSIZE to
+       MAXCONNECTIONS, not IRCD_FD_SETSIZE...
+
+       * ircd/engine_poll.c: include config.h
+
+       * ircd/engine_kqueue.c: include config.h
+
+       * ircd/engine_devpoll.c: include config.h
+
+       * ircd/Makefile.in: include engine sources in compilation and make
+       depend steps
+
+       * configure.in: add checks for enabling the /dev/poll- and
+       kqueue-based engines
+
+       * acconfig.h: add lines for USE_DEVPOLL and USE_KQUEUE
+
+       * ircd/Makefile.in: work in the engine sources
+
+2001-05-07  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/m_settime.c: include ircd_snprintf.h
+
+       * ircd/ircd_relay.c: stomp a couple of gcc warnings suggesting
+       parens around a construct that had both || and &&
+
+       * ircd/chkconf.c: #include "config.h" to get some important
+       definitions
+
+       * ircd/Makefile.in: revamp ircd makefile for new build system
+
+       * doc/Makefile.in: revamp doc makefile for new build system
+
+       * config/*: Removed old build system files
+
+       * stamp-h.in: a stamp file
+
+       * install-sh: install-sh for new build system
+
+       * configure.in: configure.in for new build system
+
+       * configure: configure script for new build system (built by
+       autoconf)
+
+       * config.sub: config.sub for new build system
+
+       * config.h.in: config.h.in for new build system (built by
+       autoheader)
+
+       * config.guess: config.guess for new build system
+
+       * aclocal.m4: aclocal.m4 for new build system (built by aclocal
+       1.4)
+
+       * acinclude.m4: aclocal.m4 macros for new build system
+
+       * acconfig.h: config.h skeleton for new build system
+
+       * Makefile.in: modify for new build system
+
+2001-05-01  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/s_err.c: get rid of the last vestiges of TIME_T_FMT
+
+       * ircd/m_settime.c: get rid of the last vestiges of TIME_T_FMT
+
+       * ircd/m_server.c: get rid of the last vestiges of TIME_T_FMT
+
+2001-05-01  Perry Lorier       <Isomer@coders.net>
+       * doc/iauth.doc: Protocol for iauth server. (from hybrid).
+       * doc/linux-poll.patch: Patch to make Linux under 2.2 not deadlock
+               when you have far far too many sockets in use.
+       * {include,ircd}/iauth.c: A start on iauth support.
+
+2001-05-01  Perry Lorier       <Isomer@coders.net>
+       * ircd/s_err.c: Suggested wording change.
+       * ircd/s_user.c: Users aren't target limited against +k users.
+       * ircd/chkconf.c: Made it compile again, who knows if it works, but
+               now I can at least make install
+        * various: Cleanups on m_*.c files.
+
+
+2001-04-23  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/s_misc.c (exit_client): make netsplit server notice say the
+       right thing
+
+       * ircd/m_links.c (m_links_redirect): forward-port RPL_ENDOFLINKS
+       change to make Khaled happy...
+
+       * ircd/m_whois.c (do_whois): pull-up of m_whois() fix
+       (do_whois): duh...
+
+2001-04-21  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/msgq.c: finally remove the msgq_integrity() hack, as it's
+       turned up no more bugs
+
+       * ircd/ircd.c: use /* */ comments instead of // comments--all the
+       world's not gcc :(
+
+       * ircd/s_conf.c (conf_add_server): use /* */ comments instead of
+       // comments--all the world's not gcc :(
+
+       * ircd/runmalloc.c: finally garbage-collect unused file
+
+       * include/runmalloc.h: finally garbage-collect unused file
+
+       * ircd/<multiple files>: addition of '#include "config.h"' before
+       all other includes in most .c files
+
+       * include/<multiple files>: remove includes of config.h, which are
+       now going into the raw .c files
+
+2001-04-20  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/m_whois.c (do_whois): display proper server name if the
+       user is looking up himself
+
+       * ircd/m_who.c (m_who): disable match by servername or display of
+       server names by non-opers
+
+       * include/ircd_policy.h: add define for
+       HEAD_IN_SAND_WHO_SERVERNAME to cover full intent of sub-motion 15
+       of CFV 165
+
+2001-04-18  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/s_conf.c: keep the $R in memory so we can see it clearly
+       when we do a /stats k
+
+       * ircd/s_user.c (set_user_mode): pull-up of changes to prevent
+       users from turning on +s and +g
+
+       * ircd/s_misc.c (exit_client): pull-up of changes to turn off
+       net.split notice
+
+       * ircd/parse.c: pull-up of changes to disable /trace, /links, and
+       /map for users
+
+       * ircd/m_whois.c (do_whois): pull-up of server name masking for
+       /whois
+
+       * ircd/m_user.c (m_user): removal of umode and snomask defaulting
+       functions, pull-up
+
+       * ircd/m_stats.c (m_stats): pull-up of stats-disabling stuff
+
+       * ircd/m_map.c (m_map_redirect): pull-up of m_map_redirect()
+
+       * ircd/m_links.c (m_links_redirect): pull-up of m_links_redirect()
+
+       * ircd/channel.c (channel_modes): pull-up of channel key display
+       as *
+
+       * include/ircd_policy.h: pull-up of ircd_policy.h
+
+       * include/client.h: pull-up of Set/ClearServNotice()
+
+       * ircd/gline.c (do_gline): report client name in G-line message
+       (pull-up)
+
+       * ircd/s_user.c (register_user): pull-up--show IP address in some
+       server notices dealing only with users; report which connection
+       class has filled up
+
+       * ircd/s_stats.c (report_deny_list): use conf->flags &
+       DENY_FLAGS_IP insteaf of conf->ip_kill
+
+       * ircd/m_stats.c (report_klines): use conf->flags & DENY_FLAGS_IP
+       insteaf of conf->ip_kill
+
+       * ircd/s_conf.c: use flags field in struct DenyConf; pull-up of
+       K-line by real name
+
+       * include/s_conf.h: use a flags field in struct DenyConf; define
+       DENY_FLAGS_FILE, DENY_FLAGS_IP, and DENY_FLAGS_REALNAME for
+       pull-up of K-line by real name
+
+       * ircd/m_trace.c: pull-up of IP show for user connections
+
+       * doc/example.conf: pull-up of the realname K-line documentation
+
+       * ircd/ircd.c: forward port of pid file advisory locking mechanism
+
+2001-04-16  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/send.c (sendcmdto_flag_butone): recast to just broadcast to
+       all servers, rather than to only servers that have +w/+g/whatever
+       users on them; among other things, this removes that atrocity
+       known as sentalong[] from this function
+
+       * ircd/m_admin.c: must include ircd.h to declare "me"; must
+       include hash.h to declare FindUser()
+
+       * ircd/m_wallusers.c: implementation of WALLUSERS
+
+       * ircd/m_desynch.c (ms_desynch): only send DESYNCHs to opers
+
+       * ircd/m_wallops.c: only send WALLOPS to opers
+
+       * ircd/parse.c: add WALLUSERS command to parser table
+
+       * include/handlers.h: declare wallusers handlers
+
+       * include/msg.h: add WALLUSERS command
+
+       * ircd/send.c (sendcmdto_flag_butone): if FLAGS_OPER is or'd with
+       flag, send only to appropriate opers
+
+2001-04-13  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/uping.c: refit to use the new events interface
+
+       * ircd/res.c: refit to use the new events interface
+
+       * ircd/ircd_events.c: create timer_chg(), which permits a
+       (non-periodic) timer's expire time to be modified; change the
+       logic in timer_run() so that timers that were re-added while the
+       event was being processed will not be destroyed prematurely
+
+       * include/uping.h: include the events header, declare some extra
+       fields in struct UPing, remove timeout value, and define some
+       flags for marking which cleanup items have yet to be done
+
+       * include/ircd_events.h: add a prototype for timer_chg() to change
+       the expire time of a running timer
+
+2001-03-13 Joseph Bongaarts <foxxe@wtfs.net>
+       * ircd/os_openbsd.c: Tweaked the openbsd hack a bit.
+       
+2001-03-07  Joseph Bongaarts  <foxxe@wtfs.net>
+
+       * config/configure.in: Add check for OpenBSD
+
+       * ircd/os_openbsd.c: Add seperate os dep file for openbsd which
+       differs from generic BSD, particularly in its handling of
+       _XOPEN_SOURCE.
+       
+2001-02-12  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/m_gline.c (ms_gline): propagate a G-line that happened to
+       have been added by a U-lined server, rather than going through the
+       activate/deactivate logic; propagate G-line removals by U-lined
+       servers as well
+
+       * ircd/gline.c: rename propagate_gline() to gline_propagate();
+       make gline_propagate() return an int 0 (convenience return); only
+       update lastmod in gline_activate() and gline_deactivate() if the
+       current lastmod is non-zero, since 0 lastmod is our flag of a
+       U-lined server having added a G-line
+
+       * include/gline.h (gline_propagate): exporting the G-line
+       propagation function
+
+       * ircd/m_list.c (m_list): duh; permit explicit channel name
+       specification only when /list gets two arguments ("Kev
+       #wasteland") rather than when /list gets more than two
+       arguments--nice braino
+
+2001-01-29  Thomas Helvey <twhelvey1@home.com>
+
+       * ircd/ircd_reply.c (need_more_params): fix bug that allowed
+       unregistered clients to spam opers with protocol violation
+       messages. Note: the bugfix may have eliminated some useful
+       protocol violation messages.
+       Please send protocol violation messages explicitly from the
+       functions they are discovered in, you have much better context
+       for the error there and it helps to document the behavior of the
+       server. This was also a design bug in that it violated the
+       "A function should do one thing" heuristic. Patching this one
+       would have resulted in a continuous spawning of other bugs over
+       the next 3 years, so I killed it. Check around for stuff this
+       broke and readd the calls to protocol_violation in the functions
+       that need to send the message.
+
+2001-01-29  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/channel.c (mode_parse_ban): stopper a tiny leak--if a ban
+       already existed, then the logic would (attempt to) skip it, but
+       would not free the ban string; now the ban string is free'd and
+       the ban count is decremented, releasing the ban for use
+
+       * ircd/s_user.c: make send_umode_out() take a prop argument
+       instead of testing for the PRIV_PROPAGATE privilege itself; fix
+       set_umode() to use this new argument, calculating it before
+       calculating the new privileges for a -o'd user
+
+       * ircd/m_oper.c (m_oper): pass the new prop argument to
+       send_umode_out()
+
+       * ircd/channel.c (mode_parse_ban): turn off MODE_ADD bit in bans
+       that we're not actually going to add because they already exist;
+       test that particular bit before adding to the linked list
+
+       * include/s_user.h: add a prop argument to send_umode_out() to
+       indicate whether or not to propagate the user mode
+
+2001-01-24  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/msgq.c: ircd_vsnprintf() returns the number of bytes that
+       it would have written; upper-bound the number to prevent overflows
+       by proxy; also, tune buffer size given to ircd_vsnprintf() to take
+       into account the fact that ircd_vsnprintf() already takes the
+       terminal \0 into account
+
+2001-01-22  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/msgq.c: add an incredibly ugly hack to attempt to track
+       down an apparent buffer overflow; remove msgq_map(), since it's no
+       longer used anywhere; slight tweaks to prevent off-by-one errors,
+       but these can't explain the problems we've seen
+
+       * include/msgq.h: remove msgq_map(), since it's no longer used
+       anywhere
+
+2001-01-18  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/s_user.c (set_nick_name): call client_set_privs() after
+       parsing user modes
+
+2001-01-17  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/s_bsd.c (read_message): fix a typo in the select version of
+       read_message()
+
+       * ircd/whowas.c (whowas_free): MyFree() is a macro that expects
+       its argument to be an lvalue, which means we can't use
+       whowas_clean()'s handy-dandy "return ww" feature
+
+       * ircd/ircd_features.c: default LOCOP_KILL to TRUE--oops...
+
+2001-01-16  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/ircd_events.c (timer_run): it's possible that the timer got
+       deleted during the callback processing, so don't go to the bother
+       of requeuing it if the destroy flag is set
+
+       * ircd/engine_select.c: define FD_SETSIZE to be IRCD_FD_SETSIZE
+       out of config.h if this is a *BSD; include errno.h (oops);
+       decrement error count after an hour using a timer; use FD_SETSIZE
+       constant instead of IRCD_FD_SETSIZE constant; fill in event
+       processing code
+
+       * ircd/engine_poll.c: include errno.h (oops); decrement error
+       count after an hour using a timer; fill in event processing code
+
+       * ircd/engine_kqueue.c: include errno.h (oops); decrement error
+       count after an hour using a timer; assert events filter is either
+       EVFILT_READ or EVFILT_WRITE; fill in event processing code
+
+       * ircd/engine_devpoll.c: include errno.h (oops); decrement error
+       count after an hour using a timer; fill in event processing code
+
+2001-01-15  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/client.c: fixed feattab; basically, when I changed features
+       to use small integers specifying bit positions, instead of the
+       bits themselves, I forgot to update feattab to not | these
+       privileges together; also fixed a bug in the antiprivs masking
+       loop in client_set_privs()--last index wouldn't get parsed
+
+2001-01-11  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/ircd_events.c: call event_generate() with new data
+       argument; make it set that field in struct Event; make
+       socket_add() return the value of the eng_add callback
+
+       * ircd/engine_select.c: make engine_add() return a
+       successful/unsuccessful status; add bounds-checking outside of an
+       assert; use accessor macros; use log_write(), not the deprecated
+       ircd_log(); add an assert to engine_loop() to double-check for
+       data structure corruption
+
+       * ircd/engine_poll.c: make engine_add() return a
+       successful/unsuccessful status; add bounds-checking outside of an
+       assert; use accessor macros; use log_write(), not the deprecated
+       ircd_log(); add an assert to engine_loop() to double-check for
+       data structure corruption
+
+       * ircd/engine_kqueue.c: implementation of an engine for kqueue()
+
+       * ircd/engine_devpoll.c: implementation of an engine for /dev/poll
+
+       * include/ircd_events.h: define some accessor macros; add ev_data
+       to struct Event for certain important data--errno values, for
+       instance; make EngineAdd callback tell us if it was successful or
+       not; add extra argument to event_generate(); make socket_add()
+       return the status from EngineAdd
+
+2001-01-10  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/ircd_events.c: pass initializer information about how many
+       total _filedescriptors_ may be opened at once
+
+       * ircd/ircd.c: use exported "running" instead of unexported
+       thisServer.running
+
+       * ircd/engine_select.c: implementation of an event engine based on
+       select()
+
+       * ircd/engine_poll.c: implementation of an event engine based on
+       poll()
+
+       * include/ircd_events.h: pass the engine initializer an integer
+       specifing how many _filedescriptors_ may be opened at once
+
+       * include/ircd.h: running has to be exported for the engine_*
+       event loops
+
+2001-01-09  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/ircd_events.c: include some needed headers; add some
+       comments; make evEngines[] const; bundle sig_sock and sig_fd into
+       a struct named sigInfo; rework struct evInfo to have a queue of
+       _generators_, and only when threaded; added a gen_init() function
+       to centralize generator initialization; fix various compile-time
+       errors; rework event_add() for new queueing scheme and checked for
+       compile-time errors; add casts where needed; spell evEngines[]
+       correctly; make engine_name() return const char*
+
+       * include/ircd_events.h: type EventCallBack depends on struct
+       Event, so pre-declare it; put _event_ queue into generators, and
+       only when threaded; give engine data a union to store both ints
+       and pointers; make engine name a const; fix gen_ref_dec() macro;
+       make engine_name() return a const char*
+
+       * ircd/ircd_events.c: gen_dequeue() is now exported, so move it
+       down with the non-static functions; modify event_execute() to use
+       the new gen_ref_dec() to simplify code; make sure event_generate()
+       does not generate new events for generators marked for destruction
+
+       * include/ircd_events.h: the engines, at least, may need to modify
+       reference counts to keep generators from going away while
+       something still points at them, so add reference counter
+       manipulators and export gen_dequeue() for them
+
+       * ircd/ircd_events.c: set up the list of engines to try; set up
+       the signal struct Socket; rename netInfo to evInfo; move static
+       functions near the beginning of the file; do away with
+       signal_signal() (since we no longer keep a signal count ourselves)
+       and call event_generate() directly from signal_callback--also
+       renamed some functions; allow signal_callback() to read up to
+       SIGS_PER_SOCK at once from the signal pipe; add event_init() to
+       initialize the entire event system; add event_loop() to call the
+       engine's event loop; initialize new struct GenHeader member,
+       gh_engdata; remove timer_next(); add socket_add() function to add
+       a socket; add socket_del() to mark a socket for deletion; add
+       socket_state() to transition a socket between states; add
+       socket_events() to set what events we're interested in on the
+       socket; add engine_name() to retrieve event engine's name
+
+       * include/ircd_events.h: add engine data field to struct
+       GenHeader; rename SOCK_ACTION_REMOVE to SOCK_ACTION_DEL; add a
+       note about states vs s_events; remove signal count; fold union
+       Generator back into struct Event; remove count members from struct
+       Generators; redefine engine callbacks to not take a struct
+       Engine*; add explanatory comments to callback definitions; add
+       some engine callbacks to handle operations; remove struct Engine
+       flag member--can detect single flag from eng_signal member; add
+       event_init(), event_loop(), engine_name(), and the socket_*()
+       functions; make timer_next() a macro to avoid a function call
+
+2001-01-08  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * include/ircd_events.h: rename to ircd_events.h, since it handles
+       events, not just networking stuff; add signal support; more
+       structural rearrangement
+
+       * ircd/ircd_events.c: rename to ircd_events.c, since it handles
+       events, not just networking stuff; add signal support; more
+       structural rearrangement
+
+2001-01-07  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/ircd_network.c: implement timer API; add reference counts
+       appropriately
+
+       * include/ircd_network.h: firm up some pieces of the interface;
+       split out members everything has into a separate structure; add
+       reference counts; add timer API
+
+2001-01-06  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/ircd_network.c: static data and event manipulation
+       functions for new event processing system
+
+       * include/ircd_network.h: data structures for new event processing
+       system
+
+2001-01-03  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/whowas.c: Completely re-did the old allocation scheme by
+       turning it into a linked list, permitting the
+       NICKNAMEHISTORYLENGTH feature to be changed on the fly
+
+       * ircd/s_debug.c (count_memory): use FEAT_NICKNAMEHISTORYLENGTH
+       feature instead of old #define
+
+       * ircd/ircd_features.c: add NICKNAMEHISTORYLENGTH feature as an
+       integer feature with a notify callback (whowas_realloc)
+
+       * ircd/client.c (client_set_privs): second memset was supposed to
+       be over antiprivs, not privs; thanks, Chris Behrens
+       <cbehrens@xo.com> for pointing that out...
+
+       * include/whowas.h: new elements for an extra linked list in
+       struct Whowas; a notify function for feature value changes
+
+       * include/ircd_features.h: new feature--FEAT_NICKNAMEHISTORYLENGTH
+
+       * config/config-sh.in: NICKNAMEHISTORYLENGTH is now a feature
+
+2001-01-02  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * config/config-sh.in: get rid of DEFAULT_LIST_PARAMETER
+       compile-time option--now in features subsystem
+
+       * ircd/motd.c (motd_init): rework motd_init() to be called as the
+       notify function for MPATH and RPATH features (should probably
+       split it up a bit, though...)
+
+       * ircd/m_privs.c (mo_privs): if called with no parameters, return
+       privs of the caller, rather than an error
+
+       * ircd/m_list.c: pull usage message into its own function; pull
+       list parameter processing into its own function that does not
+       modify the contents of the parameter; add list_set_default() to
+       set the default list parameter (uses the notify hook); rework
+       m_list() to make use of these functions; removed dead code
+
+       * ircd/ircd_log.c (log_feature_mark): make sure to return 0, since
+       we have no notify handler
+
+       * ircd/ircd_features.c: add notify callback for notification of
+       value changes; give mark callback an int return value to indicate
+       whether or not to call the notify callback; fix up feature macros
+       for new notify callback; add DEFAULT_LIST_PARAM feature; rewrite
+       string handling in feature_set() to deal with def_str being a null
+       pointer; wrote feature_init() to set up all defaults appropriately
+
+       * ircd/ircd.c (main): call feature_init() instead of
+       feature_mark(), to avoid calling notify functions while setting up
+       defaults
+
+       * ircd/client.c: updated to deal with new privileges structure
+
+       * ircd/class.c: updated so init_class() can be called should one
+       of PINGFREQUENCY, CONNECTFREQUENCY, MAXIMUM_LINKS, or
+       DEFAULTMAXSENDQLENGTH be changed
+
+       * include/ircd_log.h: log_feature_mark() updated to fit with new
+       API changes
+
+       * include/ircd_features.h: added DEFAULT_LIST_PARAM feature and
+       feature_init() function (found necessary since adding the notify
+       stuff and notifying motd.c during start-up...before we defined
+       RPATH!)
+
+       * include/client.h: move privs around to enable addition of more
+       bits if necessary; based on the FD_* macros
+
+       * include/channel.h: declare list_set_default (actually located in
+       m_list.c *blanche*)
+
+       * ircd/s_user.c: retrieve MAXSILES and MAXSILELENGTH (now
+       AVBANLEN*MAXSILES) from features subsystem
+
+       * ircd/s_debug.c (debug_serveropts): CMDLINE_CONFIG doesn't go to
+       anything anymore
+
+       * ircd/s_bsd.c: retrieve HANGONGOODLINK and HANGONRETRYDELAY from
+       the features subsystem
+
+       * ircd/s_auth.c (start_auth): NODNS migrated to the features
+       subsystem
+
+       * ircd/random.c: created random_seed_set() function to set seed
+       value, along with some stuff to make ircrandom() a little more
+       random--state preserving, xor of time instead of direct usage,
+       etc.; it's still a pseudo-random number generator, though, and
+       hopefully I haven't broken the randomness
+
+       * ircd/m_version.c: FEATUREVALUES makes use of feature_int() calls
+
+       * ircd/m_join.c: use features interface to retrieve
+       MAXCHANNELSPERUSER
+
+       * ircd/ircd_features.c: add NODISP flag for super-secret features;
+       add a whole bunch of new features migrated over from make config
+
+       * ircd/ircd.c: use features interface to retrieve PINGFREQUENCY,
+       CONNECTTIMEOUT, and TIMESEC
+
+       * ircd/client.c (client_get_ping): use features interface to
+       retrieve PINGFREQUENCY
+
+       * ircd/class.c: use features interface to retrieve PINGFREQUENCY,
+       CONNECTFREQUENCY, MAXIMUM_LINKS, and DEFAULTMAXSENDQLENGTH
+
+       * ircd/chkconf.c (DEFAULTMAXSENDQLENGTH): since it's now in the
+       features subsystem, we have to add something explicit
+
+       * ircd/channel.c: use features interface to retrieve
+       KILLCHASETIMELIMIT, MAXBANLENGTH, MAXBANS, and MAXCHANNELSPERUSER;
+       note that MAXBANLENGTH is now calculated dynamically from MAXBANS
+       and AVBANLEN
+
+       * ircd/Makefile.in: run make depend
+
+       * include/supported.h (FEATURESVALUES): update to reference
+       feature settings
+
+       * include/random.h: add prototype for random_seed_set
+
+       * include/ircd_features.h: add several more features
+
+       * include/channel.h: move MAXBANS and MAXBANLENGTH into feature
+       subsystem
+
+       * config/config-sh.in: feature-ized some more stuff
+
+       * include/motd.h: some new elements in motd.h for motd.c changes
+
+       * ircd/motd.c: motd_cache() now searches a list of already cached
+       MOTD files; saves us from having duplicate caches in memory if
+       there are two identical T-lines for two different sites...
+
+2001-01-02  Perry Lorier <isomer@coders.net>
+       * ircd/motd.c: don't core if the motd isn't found.  Bug found by
+       Amarande.
+
+2001-01-02  Perry Lorier <isomer@coders.net>
+       * ircd/s_err.c: Added third param to 004 - the channel modes that tage params.  Used by hybrid/epic.
+       * ircd/s_channels.c: Added fix for msg'ing a -n+m channel - thanks
+               to guppy for noticing, and hektik for providing the fix.
+       * misc others: Minor cleanups, added more protocol_violations, ripped
+               out more P09 stuffs, bit more protocol neg stuff.
+
+2000-12-19  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/m_ison.c (m_ison): Dianora says that ISON has to end with a
+       space (*sigh* stupid clients...)
+
+       * ircd/s_user.c: make WALLOPS_OPER_ONLY a feature managed through
+       ircd_features.[ch]
+
+       * ircd/s_err.c: get rid of GODMODE conditionals
+
+       * ircd/s_debug.c (debug_serveropts): switch to using appropriate
+       calls into the features subsystem for various serveropts
+       characters
+
+       * ircd/s_conf.c (find_conf_entry): get rid of USEONE conditional
+
+       * ircd/s_bsd.c: remove GODMODE conditional; use features subsystem
+       to get value of VIRTUAL_HOST and CLIENT_FLOOD; remove
+       NOFLOWCONTROL conditional
+
+       * ircd/s_auth.c: use features subsystem to determine value of
+       KILL_IPMISMATCH
+
+       * ircd/parse.c: get rid of NOOPER and GODMODE conditionals; use
+       features subsystem to determine the setting of IDLE_FROM_MSG
+
+       * ircd/numnicks.c: get rid of EXTENDED_NUMERICS conditionals
+
+       * ircd/motd.c: get value of NODEFAULTMOTD from features subsystem;
+       use features subsystem to get motd file names
+
+       * ircd/m_settime.c: get value of RELIABLE_CLOCK from features
+       subsystem
+
+       * ircd/m_server.c: get rid of CRYPT_LINK_PASSWORD, since it does
+       us no good; use features subsystem to figure out if we need to do
+       HUB-type stuff; make TESTNET debugging sendto_opmask_butone's use
+       the Debug(()) macro instead; get value of RELIABLE_CLOCK from
+       features subsystem
+
+       * ircd/m_privmsg.c: get IDLE_FROM_MSG from the features subsystem
+
+       * ircd/m_oper.c: get CRYPT_OPER_PASSWORD from the features
+       subsystem
+
+       * ircd/m_connect.c: get SERVER_PORT from the features subsystem
+
+       * ircd/ircd_log.c (log_set_file): fix a bug that kept log files
+       from getting marked if they were already set to something...
+
+       * ircd/ircd_features.c: add a flag to indicates read-only access;
+       add several new features that used to be compile-time selected
+
+       * ircd/ircd.c: grab pidfile out of feature subsystem; don't check
+       access to motd files (what the heck?); make sure to initialize the
+       feature subsystem before trying to write the config file
+
+       * ircd/dbuf.c: use feature_int() to retrieve BUFFERPOOL settings;
+       use feature_bool() to figure out if we're using the FERGUSON
+       flusher
+
+       * ircd/Makefile.in: MPATH and RPATH are now done differently, so
+       remove the clause that creates empty files of that name; also ran
+       make depend
+
+       * include/sys.h: CLIENT_FLOOD is now a feature; unfortunately,
+       there is no easy way to bounds-check it at present
+
+       * include/querycmds.h: make sure ircd_features.h is included; use
+       feature_str(FEAT_DOMAINNAME) in calls to match()
+
+       * include/ircd_features.h: many new features that used to be
+       compile-time selected
+
+       * config/config-sh.in: add * to DOMAINNAME; try also using first
+       argument to search in /etc/resolv.conf; removed many compile-time
+       options that now can be configured through the features system
+
+2000-12-18  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * doc/api/log.txt: how to use the logging API
+
+       * doc/api/features.txt: how to use the features API
+
+       * doc/api/api.txt: how to write API documentation
+
+       * include/ircd_features.h: rearranged a couple of features for
+       neatness purposes
+
+       * ircd/ircd_features.c: cleaned up the macros some; rearranged
+       some code to all go into the switch; rearranged a couple of
+       features for neatness purposes
+
+2000-12-16  Greg Sikorski <gte@atomicrevs.demon.co.uk>
+       * ircd/os_bsd.c: Added os_set_tos for BSD users.
+
+2000-12-16  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/ircd_features.c: Isomer almost got it right; you need to
+       use F_I(), since it's an integer value, not a boolean value.  The
+       asserts in feature_int would catch you out...  Also made the F_*
+       macros take flags
+
+       * ircd/s_err.c: define RPL_PRIVS reply
+
+       * ircd/parse.c: put new PRIVS command into command table
+
+       * ircd/m_privs.c (mo_privs): message handler to report operator
+       privileges
+
+       * ircd/ircd_features.c: declare new features OPER_SET and
+       LOCOP_SET; redo boolean testing routine to accept TRUE, YES, and
+       ON for boolean TRUE, and FALSE, NO, and OFF for boolean FALSE
+
+       * ircd/client.c: simplify client_set_privs() with a table that
+       defines what features to test for; add new client_report_privs()
+
+       * ircd/Makefile.in: compile new m_privs.c; run make depend
+
+       * include/numeric.h (RPL_PRIVS): new reply numeric for displaying
+       an operator's privileges
+
+       * include/msg.h: define new command: PRIVS
+
+       * include/ircd_features.h: create new features OPER_SET and
+       LOCOP_SET for controlling access to /set
+
+       * include/handlers.h (mo_privs): declare message handler for
+       reporting oper privileges
+
+       * include/client.h (client_report_privs): declare function to
+       report what privileges an oper has
+
+       * ircd/m_whois.c (do_whois): fix a bug that caused /whois to
+       report that a user is an oper if the oper doing the /whois had
+       PRIV_SEE_OPERS
+
+2000-12-17  Isomer <Isomer@coders.net>
+       * ircd/listener.c: added support for TOS twiddling as a 'feature'.
+
+2000-12-17  Isomer <Isomer@coders.net>
+       * ircd/os_linux.c: add TOS stuffs
+
+       * ircd/listener.c: add TOS stuffs
+
+2000-12-16  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/whocmds.c (do_who): use HasPriv to determine whether or not
+       to indicate a user is an oper
+
+       * ircd/s_user.c: clear privileges setting when deopping; don't
+       propagate +o unless user has PRIV_PROPAGATE privilege
+
+       * ircd/s_debug.c (debug_serveropts): created debug_serveropts()
+       function and replaced how the server option string is generated
+
+       * ircd/parse.c: remove conditional on CONFIG_OPERCMDS
+
+       * ircd/m_whois.c (do_whois): use HasPriv to determine whether or
+       not to indicate the user is an operator
+
+       * ircd/m_who.c: use HasPriv to determine whether or not a user
+       should be displayed in the list of opers
+
+       * ircd/m_version.c: call debug_serveropts() to get server option
+       string
+
+       * ircd/m_userip.c (userip_formatter): use HasPriv to determine
+       whether or not to show oper status
+
+       * ircd/m_userhost.c (userhost_formatter): use HasPriv to determine
+       whether or not to show oper status
+
+       * ircd/m_restart.c (mo_restart): replace ugly #ifdef conditional
+       checks with HasPriv check; remove dead code
+
+       * ircd/m_rehash.c (mo_rehash): replace ugly #ifdef conditional
+       checks with HasPriv check
+
+       * ircd/m_opmode.c (mo_opmode): use HasPriv to check permissions;
+       use feature_bool to check if disabled
+
+       * ircd/m_oper.c (m_oper): set oper priviliges
+
+       * ircd/m_mode.c (m_mode): replace #ifdef conditional with HasPriv
+       check
+
+       * ircd/m_kill.c (mo_kill): use HasPriv checks to determine if we
+       can kill
+
+       * ircd/m_kick.c (m_kick): replace #ifdef conditional with HasPriv
+       check
+
+       * ircd/m_jupe.c (mo_jupe): rework permissions checking structure;
+       use feature_bool to check if disabled
+
+       * ircd/m_join.c (m_join): remove BADCHAN conditional; replace
+       #ifdef conditional with a HasPriv check
+
+       * ircd/m_gline.c (mo_gline): rework permissions checking
+       structure; use feature_bool to check if any part is disabled
+
+       * ircd/m_die.c: replace ugly #ifdef conditionals with HasPriv
+       check; remove dead code
+
+       * ircd/m_clearmode.c: use feature_bool() to detect if we're
+       disabled; use HasPriv to figure out what we're permitted to do;
+       only allow clearmode on moded channels
+
+       * ircd/ircd_features.c: define various features; use HasPriv to
+       verify permissions to set/reset
+
+       * ircd/gline.c (gline_add): use HasPriv instead of #ifdef
+       conditionals
+
+       * ircd/client.c (client_set_privs): function to set an oper's
+       privileges
+
+       * ircd/channel.c: use HasPriv calls instead of #ifdef conditionals
+
+       * include/whocmds.h: deconditionalize several macros and
+       substitute appropriate calls to HasPriv()
+
+       * include/s_debug.h: get rid of global serveropts[]; define new
+       function debug_serveropts() to build that string on the fly
+
+       * include/ircd_features.h: define some features
+
+       * include/client.h: add privs member to struct Connection; define
+       various priviledges
+
+       * include/channel.h: no longer using IsOperOnLocalChannel; remove
+       conditional of MAGIC_OPER_OVERRIDE on OPER_WALK_THROUGH_LMODES
+
+       * doc/Configure.help: remove help information for deprecated
+       options
+
+       * config/config-sh.in: remove certain deprecated options having to
+       do with what opers can and cannot do--first stage in moving
+       compile-time constants into the .conf
+
+2000-12-16  Isomer <Isomer@coders.net>
+       * ircd/parse.c: detect if the prefix is missing and try and recover
+       instead of coring.
+
+2000-12-15  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/ircd_log.c: found and fixed some bugs in the debug logging
+       code that would sometimes result in the log file not being
+       reopened--which meant that a user could connect and get the
+       logging output--oops
+
+       * ircd/Makefile.in: run make depend...
+
+       * ircd/s_stats.c: get rid of report_feature_list()
+
+       * ircd/s_err.c: add the 'bad value' error message, shift error
+       messages over somewhat
+
+       * ircd/s_debug.c (debug_init): call log_debug_init with the
+       use_tty flag
+
+       * ircd/s_conf.c (read_configuration_file): unmark features before
+       reading the config file, then reset unmarked features after
+       reading the config file
+
+       * ircd/m_stats.c: use feature_report() instead of
+       report_feature_list()
+
+       * ircd/ircd_log.c: fix log_debug_file (bogus assertion); add
+       special 'mark' flags and use them; add the stuff needed by the
+       features API
+
+       * ircd/ircd_features.c: rework the features API and add gobs of
+       comments to try to explain what some of these complex functions
+       are actually doing
+
+       * include/s_stats.h: get rid of report_feature_list(); use
+       feature_report() instead
+
+       * include/numeric.h: added a new error message and shifted old
+       values over some--this is, after all, an alpha
+
+       * include/ircd_log.h: log_debug_init now takes an integer to tell
+       it if it should be using the tty; added a couple of functions
+       required by the features API
+
+       * include/ircd_features.h: add an enum and some more functions to
+       flesh out the feature API--it should now be possible to put all
+       those compile-time constants in the config file!
+
+       * ircd/send.c: got the direction of the assert incorrect...
+
+       * ircd/send.c: implement the efficiency of flush_connections by
+       creating a linked list of struct Connection's with queued data;
+       also get rid of flush_sendq_except and make sure to yank
+       connections out of the list when their sendQs become empty (notice
+       the assertion in flush_connections!)
+
+       * ircd/s_bsd.c (close_connection): must yank the Connection out of
+       the sendq list
+
+       * ircd/list.c (dealloc_connection): must yank the Connection out
+       of the sendq list
+
+       * ircd/dbuf.c (dbuf_put): call flush_connections instead of the
+       deprecated flush_sendq_except
+
+       * ircd/client.c: define a couple new helper functions for sendq
+       threading--this will make the flush_connections function in send.c
+       considerably more efficient by creating a linked list of
+       Connections that have queued data to send
+
+       * include/send.h: remove flush_sendq_except, as it's not used
+       anymore
+
+       * include/client.h: declare a couple new helper functions for the
+       sendq threading system
+
+2000-12-14  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/m_ison.c (m_ison): Apply Diane Bruce's patch to make ISON
+       parse all arguments
+
+       * ircd/s_debug.c (count_memory): modify to report for clients and
+       connections, not local clients and remote clients
+
+       * ircd/list.c: fiddle with the client-fiddling functions to take
+       into account the divorce of struct Connection from struct Client
+
+       * ircd/ircd.c: define a struct Connection for me, initialize it,
+       and link it into the right place (ewww, globals!)
+
+       * include/client.h: remove CLIENT_{LOCAL,REMOTE}_SIZE; split
+       struct Client into struct Client and struct Connection; redefine
+       local-portion accessor macros to go through struct Client to the
+       struct Connection; define struct Connection accessor macros
+
+2000-12-13  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/whowas.c: missed a couple of accesses to a struct Client
+
+       * ircd/uping.c: missed a couple of accesses to a struct Client
+
+       * ircd/send.c: missed a couple of accesses to a struct Client
+
+       * ircd/s_user.c: missed a couple of accesses to a struct Client
+
+       * ircd/s_misc.c: missed a couple of accesses to a struct Client
+
+       * ircd/s_conf.c: missed a couple of accesses to a struct Client
+
+       * ircd/s_bsd.c: missed a couple of accesses to a struct Client
+
+       * ircd/s_auth.c: missed a couple of accesses to a struct Client
+
+       * ircd/res.c: missed a couple of accesses to a struct Client
+
+       * ircd/parse.c: missed a couple of accesses to a struct Client
+
+       * ircd/m_whois.c: use new accessor macros for struct Client
+
+       * ircd/m_who.c: use new accessor macros for struct Client
+
+       * ircd/m_wallchops.c: use new accessor macros for struct Client
+
+       * ircd/m_version.c: use new accessor macros for struct Client
+
+       * ircd/m_userip.c: use new accessor macros for struct Client
+
+       * ircd/m_userhost.c: use new accessor macros for struct Client
+
+       * ircd/m_user.c: use new accessor macros for struct Client
+
+       * ircd/m_uping.c: use new accessor macros for struct Client
+
+       * ircd/m_trace.c: use new accessor macros for struct Client
+
+       * ircd/m_topic.c: use new accessor macros for struct Client
+
+       * ircd/m_time.c: use new accessor macros for struct Client
+
+       * ircd/m_stats.c: use new accessor macros for struct Client
+
+       * ircd/m_squit.c: use new accessor macros for struct Client
+
+       * ircd/m_silence.c: use new accessor macros for struct Client
+
+       * ircd/m_server.c: use new accessor macros for struct Client;
+       remove dead code
+
+       * ircd/m_rpong.c: use new accessor macros for struct Client
+
+       * ircd/m_rping.c: use new accessor macros for struct Client
+
+       * ircd/m_quit.c: use new accessor macros for struct Client
+
+       * ircd/m_privmsg.c: use new accessor macros for struct Client
+
+       * ircd/m_pong.c: use new accessor macros for struct Client; remove
+       dead code
+
+       * ircd/m_ping.c: use new accessor macros for struct Client
+
+       * ircd/m_pass.c: use new accessor macros for struct Client
+
+       * ircd/m_part.c: use new accessor macros for struct Client
+
+       * ircd/m_oper.c: use new accessor macros for struct Client
+
+       * ircd/m_notice.c: use new accessor macros for struct Client
+
+       * ircd/m_nick.c: use new accessor macros for struct Client
+
+       * ircd/m_names.c: use new accessor macros for struct Client
+
+       * ircd/m_mode.c: use new accessor macros for struct Client
+
+       * ircd/m_map.c: use new accessor macros for struct Client
+
+       * ircd/m_list.c: use new accessor macros for struct Client
+
+       * ircd/m_links.c: use new accessor macros for struct Client;
+       remove some dead code
+
+       * ircd/m_kill.c: use new accessor macros for struct Client; remove
+       some dead code
+
+       * ircd/m_kick.c: use new accessor macros for struct Client
+
+       * ircd/m_join.c: use new accessor macros for struct Client; remove
+       some dead code
+
+       * ircd/m_ison.c: use new accessor macros for struct Client
+
+       * ircd/m_invite.c: use new accessor macros for struct Client
+
+       * ircd/m_info.c: use new accessor macros for struct Client
+
+       * ircd/m_gline.c: use new accessor macros for struct Client
+
+       * ircd/m_error.c: use new accessor macros for struct Client
+
+       * ircd/m_create.c: use new accessor macros for struct Client
+
+       * ircd/m_connect.c: use new accessor macros for struct Client;
+       removed some dead code
+
+       * ircd/m_burst.c: use new accessor macros for struct Client
+
+       * ircd/m_away.c: use new accessor macros for struct Client
+
+       * ircd/m_admin.c: use new accessor macros for struct Client
+
+       * ircd/hash.c: missed a couple of accesses to a struct Client
+
+       * ircd/gline.c: missed a couple of accesses to a struct Client
+
+       * ircd/crule.c: missed a couple of accesses to a struct Client
+
+       * ircd/class.c: missed an access to a struct Client
+
+       * ircd/channel.c: missed a couple of accesses to a struct Client
+
+       * ircd/IPcheck.c: missed an access to a struct Client
+
+       * include/querycmds.h: fix a couple of stats macros to use
+       structure accessor macros
+
+       * include/client.h: change structure member names to highlight any
+       places in the code I've missed
+
+2000-12-12  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/whowas.c: use new struct Client accessor macros
+
+       * ircd/whocmds.c: use new struct Client accessor macros
+
+       * ircd/send.c: use new struct Client accessor macros
+
+       * ircd/s_user.c: use new struct Client accessor macros; removed
+       some dead code
+
+       * ircd/s_serv.c: use new struct Client accessor macros; removed
+       some dead code
+
+       * ircd/s_numeric.c: use new struct Client accessor macros
+
+       * ircd/s_misc.c: use new struct Client accessor macros
+
+       * ircd/s_debug.c: use new struct Client accessor macros
+
+       * ircd/s_conf.c: use new struct Client accessor macros
+
+       * ircd/s_bsd.c: use new struct Client accessor macros
+
+       * ircd/s_auth.c: use new struct Client accessor macros
+
+       * ircd/parse.c: use new struct Client accessor macros
+
+       * ircd/packet.c: use new struct Client accessor macros
+
+       * ircd/numnicks.c: use new struct Client accessor macros
+
+       * ircd/motd.c: use new struct Client accessor macros
+
+       * ircd/listener.c: use new struct Client accessor macros
+
+       * ircd/list.c: use new struct Client accessor macros
+
+       * ircd/jupe.c: use new struct Client accessor macros
+
+       * ircd/ircd_snprintf.c: use new struct Client accessor macros
+
+       * ircd/ircd_reply.c: use new struct Client accessor macros
+
+       * ircd/ircd_relay.c: use new struct Client accessor macros
+
+       * ircd/ircd.c: use new struct Client accessor macros
+
+       * ircd/gline.c: catch some instances of me.<stuff> I missed
+       previously
+
+       * ircd/client.c: use cli_ instead of con_
+
+       * ircd/class.c: use cli_ instead of con_
+
+       * ircd/channel.c: use cli_ instead of con_
+
+       * ircd/IPcheck.c: use cli_ instead of con_; catch some instances
+       of me.<stuff> I missed previously
+
+       * include/client.h: use cli_ instead of con_...seemed like a good
+       idea at the time *shrug*
+
+2000-12-11  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/hash.c: use struct Client accessor macros
+
+       * ircd/gline.c: use struct Client accessor macros
+
+       * ircd/crule.c: use struct Client accessor macros
+
+       * ircd/client.c: use struct Client accessor macros; remove some
+       dead code
+
+       * ircd/class.c: use struct Client accessor macros
+
+       * ircd/channel.c: use struct Client accessor macros; remove some
+       dead code
+
+       * ircd/IPcheck.c: use struct Client accessor macros
+
+       * include/numnicks.h: use struct Client accessor macros
+
+       * include/client.h: first step to divorcing struct Client and
+       struct Connection--define accessor macros and use them
+
+       * ircd/gline.c: When Uworld removed Uworld-set G-lines, only the
+       uplink would remove them.  This is because the removal protocol
+       message wasn't being sent to the uplinks.  This is fixed by fixing
+       propagate_gline() to send the proper number of arguments depending
+       on whether or not we're adding or deleting the Uworld gline, and
+       by having gline_deactivate() make sure to turn off the active bit
+       and call propagate_gline() if it's a Uworld gline
+
+2000-12-10  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/os_generic.c: make sure IOV_MAX gets defined, just in case
+
+       * ircd/os_bsd.c: apparently BSD doesn't have IOV_MAX defined
+       anywhere intelligent...
+
+2000-12-09  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/send.c (send_queued): call deliver_it with appropriate
+       arguments
+
+       * ircd/s_serv.c: reorder a couple of headers--cosmetic
+
+       * ircd/s_bsd.c (deliver_it): make deliver_it work with a struct
+       MsgQ
+
+       * ircd/os_solaris.c (os_sendv_nonb): function for calling writev
+       with appropriate iovec
+
+       * ircd/os_linux.c (os_sendv_nonb): function for calling writev
+       with appropriate iovec
+
+       * ircd/os_generic.c (os_sendv_nonb): function for calling writev
+       with appropriate iovec
+
+       * ircd/os_bsd.c (os_sendv_nonb): function for calling writev with
+       appropriate iovec
+
+       * ircd/msgq.c (msgq_mapiov): add a len_p argument for totalling up
+       exactly how much we're trying to write out to the fd
+
+       * include/s_bsd.h: make deliver_it take a struct MsgQ
+
+       * include/msgq.h: add a len_p argument to msgq_mapiov to help
+       detect short writes that indicate possible socket blocking
+
+       * include/ircd_osdep.h: declare os_sendv_nonb()
+
+       * ircd/channel.c (modebuf_mode): don't add empty modes...
+
+2000-12-08  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * include/send.h: add prio argument to send_buffer to select
+       between normal and priority queues
+
+       * ircd/s_user.c (send_user_info): add prio argument to send_buffer
+       call
+
+       * ircd/m_ison.c (m_ison): add prio argument to send_buffer call
+
+       * ircd/ircd_reply.c (send_reply): add prio argument to send_buffer
+       call
+
+       * ircd/channel.c (send_channel_modes): add prio argument to
+       send_buffer call
+
+       * ircd/send.c (send_buffer): add a prio argument to select the
+       priority queue; update send.c functions to use it
+
+       * ircd/msgq.c (msgq_add): remove msgq_prio; fold msgq_link and
+       msgq_add; add a prio argument to msgq_add to select the priority
+       queue
+
+       * include/msgq.h: remove msgq_prio; add a prio argument to
+       msgq_add
+
+       * ircd/send.c: remove sendbuf; remove GODMODE code; switch to
+       using msgq functions instead of dbuf functions; remove old, dead
+       sendto_* functions; redo send_buffer to take a struct MsgBuf;
+       rework sendcmdto_* functions to make use of the new struct MsgBuf
+
+       * ircd/s_user.c: remove hunt_server; restructure send_user_info to
+       make appropriate use of struct MsgBuf
+
+       * ircd/s_debug.c (count_memory): count memory used by the MsgQ
+       system and report it
+
+       * ircd/s_conf.c (read_configuration_file): use
+       sendto_opmask_butone instead of the now dead sendto_op_mask
+
+       * ircd/s_bsd.c: switch to using appropriate MsgQLength and other
+       calls on sendQ
+
+       * ircd/parse.c (parse_server): get rid of a piece of GODMODE code
+
+       * ircd/msgq.c: add msgq_append and msgq_bufleft; fix a bug in
+       msgq_clean
+
+       * ircd/m_version.c: fix spelling in comments marking dead code
+
+       * ircd/m_userip.c (userip_formatter): restructure to make use of
+       struct MsgBuf
+
+       * ircd/m_userhost.c (userhost_formatter): restructure to make use
+       of struct MsgBuf
+
+       * ircd/m_stats.c: use MsgQLength on a sendQ
+
+       * ircd/m_settime.c: use MsgQLength instead of DBufLength on a
+       sendQ; mark a piece of dead code
+
+       * ircd/m_names.c: use send_reply instead of sendto_one
+
+       * ircd/m_mode.c: use new mode; remove old dead code
+
+       * ircd/m_ison.c (m_ison): restructure to make use of struct MsgBuf
+
+       * ircd/m_burst.c: use BUFSIZE instead of IRC_BUFSIZE; remove old
+       dead code
+
+       * ircd/listener.c (accept_connection): use sendto_opmask_butone
+       instead of sendto_op_mask
+
+       * ircd/list.c (free_client): use MsgQClear to clear sendQ
+
+       * ircd/ircd_reply.c: remove send_error_to_client; restructure
+       send_reply to make use of struct MsgBuf
+
+       * ircd/dbuf.c (dbuf_put): remove argument to flush_sendq_except,
+       since its no longer used (at least currently)
+
+       * ircd/channel.c: restructure send_channel_modes to make use of
+       struct MsgBuf; remove set_mode, add_token_to_sendbuf, cancel_mode,
+       and send_hack_notice; use BUFSIZE instead of IRC_BUFSIZE
+
+       * ircd/Makefile.in: add msgq.c to list of sources; run make depend
+
+       * ircd/IPcheck.c: use sendcmdto_one instead of sendto_one
+
+       * include/send.h: send_buffer now takes a struct MsgBuf * instead
+       of a char *; flush_sendq_except now takes no arguments, as sendq
+       flushing currently only happens in dbuf.h and sendQ is a struct
+       MsgQ; remove prototypes for a lot of old sendto_* functions that
+       aren't used anymore; remove sendbuf and IRC_BUFSIZE--the former is
+       no longer needed, and the latter is identical to BUFSIZE in
+       ircd_defs.h
+
+       * include/s_user.h: make InfoFormatter take a struct MsgBuf*
+       instead of a char *; also make it return void, instead of char *
+
+       * include/msgq.h: add msgq_append and msgq_bufleft functions
+
+       * include/client.h: use a struct MsgQ instead of a struct DBuf for
+       sendq
+
+       * doc/Configure.help: Remove help for compile-time options that
+       have gone away
+
+       * config/config-sh.in: remove CONFIG_NEWMODE
+
+       * ircd/m_server.c (mr_server): don't send server IPs in any server
+       notices
+
+       * ircd/msgq.c (msgq_vmake): add \r\n to messages
+
+2000-12-07  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * include/msgq.h: declare the MsgQ API
+
+       * ircd/msgq.c: implementation of new MsgQ system
+
+2000-12-06  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/ircd_features.c: #include was supposed to be for
+         ircd_features.h, not features.h--missed when I had to do a
+         rename because of namespace collision
+
+2000-12-05  Greg Sikorski <gte@atomicrevs.demon.co.uk>
+       * ircd/m_topic.c: Added missing braces that caused all remote
+         topics to be ignored.
+
+2000-12-04  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/m_create.c: I'm tired of the exit_client warning :)
+       (ms_create): discovered that exit_client() was being called with
+       too few arguments
+
+       * ircd/s_misc.c (exit_client): remove all dependance on
+       FNAME_USERLOG, since that's now gone; log only to LS_USER
+
+       * ircd/s_debug.c: USE_SYSLOG no longer means anything
+
+       * ircd/m_oper.c (m_oper): no longer log to LS_OPERLOG--we already
+       log to LS_OPER
+
+       * ircd/m_kill.c: no longer conditionalize on SYSLOG_KILL
+
+       * ircd/ircd_log.c: remove LS_OPERLOG, LS_USERLOG
+
+       * include/ircd_log.h: remove LS_OPERLOG, LS_USERLOG--they serve
+       the same purpose as LS_USER and LS_OPER
+
+       * config/config-sh.in: remove no longer relevant log config
+       variables
+
+       * ircd/uping.c (uping_init): use log_write instead of ircd_log
+
+       * ircd/s_misc.c (exit_client): use log_write instead of ircd_log
+
+       * ircd/s_conf.c: use log_write instead of ircd_log
+
+       * ircd/s_bsd.c (report_error): use log_write instead of ircd_log
+
+       * ircd/s_auth.c (timeout_auth_queries): use log_write instead of
+       ircd_log
+
+       * ircd/res.c (send_res_msg): use log_write instead of ircd_log
+
+       * ircd/m_who.c: use log_write instead of write_log; no longer
+       conditionalize on WPATH; mark dead ircd_log calls
+
+       * ircd/m_uping.c: mark dead ircd_log call
+
+       * ircd/m_server.c (mr_server): use log_write instead of ircd_log
+
+       * ircd/m_restart.c: use log_write instead of ircd_log; mark dead
+       ircd_log calls
+
+       * ircd/m_rehash.c (mo_rehash): use log_write instead of ircd_log
+
+       * ircd/m_oper.c: use log_write instead of ircd_log; no longer
+       conditionalize on FNAME_OPERLOG; mark dead ircd_log calls
+
+       * ircd/m_kill.c: mark dead ircd_log calls
+
+       * ircd/m_connect.c: use log_write instead of ircd_log; mark dead
+       ircd_log
+
+       * ircd/m_clearmode.c: use log_write instead of write_log; no
+       longer conditionalize on OPATH
+
+       * ircd/jupe.c: use log_write instead of write_log; no longer
+       conditionalize on JPATH
+
+       * ircd/ircd_log.c: add USER subsystem; remove ircd_log() compat
+       function; fix a couple of bugs
+
+       * ircd/ircd_alloc.c: fixed a comment
+
+       * ircd/ircd.c: use log_write instead of ircd_log; fold server
+       notice generation in a couple of cases
+
+       * ircd/gline.c: use log_write instead of write_log; no longer
+       conditionalize on GPATH
+
+       * ircd/channel.c (modebuf_flush_int): use log_write instead of
+       write_log; no longer conditionalize on OPATH
+
+       * ircd/Makefile.in: run make depend, since dependencies have
+       changed
+
+       * doc/example.conf: add system USER to documentation
+
+       * include/ircd_log.h: add system USER; remove old ircd_log()
+       declarations
+
+2000-12-04  Isomer <isomer@coders.net>
+       * ircd/m_names.c: Add NAMES_EON to do_names to say add a
+       'end_of_names' reply when done.
+       * ircd/m_join.c: use NAMES_EON as mentioned above
+
+2000-12-01  net  <simms@LUCIDA.QC.CA>
+
+       * ircd/motd.c: add a freelist for struct Motds
+
+2000-11-30  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/s_stats.c (report_feature_list): report features--only
+       local opers can see logging configuration, since it doesn't really
+       mean anything to users
+
+       * ircd/s_err.c: add reply messages for new feature subsystem
+
+       * ircd/s_conf.c: add F lines to .conf
+
+       * ircd/parse.c: add the message descriptions for /set, /reset, and
+       /get
+
+       * ircd/m_stats.c: add /stats f
+
+       * ircd/m_set.c (mo_set): implement /set
+
+       * ircd/m_reset.c (mo_reset): implement /reset
+
+       * ircd/m_rehash.c: /rehash m now flushes MOTD cache, and /rehash l
+       reopens log files (for log file rotation)
+
+       * ircd/m_get.c (mo_get): implement /get
+
+       * ircd/ircd_log.c: use int instead of void return value; add
+       log_report_features() and log_canon(); fix a function that
+       disappears if DEBUGMODE not #define'd
+
+       * ircd/ircd_features.c: functions to manipulate feature settings
+       either from the config file or with the new /set, /reset, and /get
+       commands
+
+       * ircd/Makefile.in: add new .c files, run make depend
+
+       * include/s_stats.h: declare report_feature_list() (/stats f
+       handler)
+
+       * include/numeric.h: add RPL_STATSFLINE, RPL_FEATURE,
+       ERR_NOFEATURE, ERR_BADLOGTYPE, ERR_BADLOGSYS, and ERR_BADLOGVALUE
+       reply numerics
+
+       * include/msg.h: add defines for SET, RESET, and GET
+
+       * include/ircd_log.h: add a function to canonicalize subsystem
+       names; change some void return values to int
+
+       * include/ircd_features.h: new features subsystem handles all the
+       manipulation of special features, like log files
+
+       * include/handlers.h: declare new mo_{s,res,g}et message handlers
+       for fiddling with features run-time
+
+       * include/client.h (SNO_DEFAULT): don't set SNO_DEBUG by default;
+       seemed like a good idea at the time...
+
+       * doc/example.conf: document new F lines
+
+2000-11-29  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/s_debug.c: rewrite debug_init() and vdebug() in terms of
+       new logging functions, which have special support for the debug
+       log; added loop detection to vdebug(), so that I can
+       sendto_opmask_butone() from log_vwrite() without incurring another
+       call to vdebug()
+
+       * ircd/s_conf.c (rehash): call log_reopen() from rehash routine;
+       this allows log file rotations
+
+       * ircd/m_kill.c: call log_write_kill() instead of ircd_log_kill()
+
+       * ircd/ircd_log.c: much more work fleshing out the interface;
+       removed old interface; included backwards-compat ircd_log()
+       function that logs to subsystem LS_OLDLOG
+
+       * ircd/ircd.c: switch to new log_init()/log_close()/log_reopen()
+       functions
+
+       * include/ircd_log.h: include stdarg.h for va_list; move ordering
+       warning to top of file; fill out LogSys enum; declare new
+       log_debug_init(), log_vwrite(), log_write_kill(), and
+       log_[sg]et_*() functions; add flags argument to log_write();
+       defined flags to inhibit various logging actions
+
+       * include/client.h: added support for new SNO_DEBUG, enabled only
+       if DEBUGMODE is defined
+
+2000-11-28  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/ircd_log.c: make sure the various LOG_* constants are
+       defined (probably not needed, since #include <syslog.h> isn't
+       conditional); various static data needed for the new logging
+       functions; definitions of new logging functions
+
+       * include/ircd_log.h: new LogSys enum, declarations for part of
+       new logging API
+
+       * ircd/motd.c: we were setting type to MOTD_CLASS unconditionally,
+       which was of course stupid; switched to using switch/case in
+       initialization in motd_create(); zero the MotdList.other pointer
+       from motd_clear()
+
+       * ircd/ircd.c (main): motd_init() has to come before init_conf(),
+       or we overwrite init_conf()'s hard work with respect to T-lines
+
+2000-11-27  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/s_stats.c: comment out report_motd_list and include a
+       reference to motd_report()
+
+       * ircd/s_conf.c: rip out the old MOTD manipulation functions; call
+       motd_add() from the conf parser; call motd_clear() from the rehash
+       routine; remove the no longer needed memory clearing and reloading
+       stuff from the rehash service routine
+
+       * ircd/motd.c: loads new API, including static internal functions
+       to do allocation/deallocation, etc.
+
+       * ircd/m_stats.c: use new motd_report() instead of
+       report_motd_list()
+
+       * ircd/m_motd.c: use new syntax for motd_send()
+
+       * ircd/ircd.c: use new motd_init() function
+
+       * ircd/Makefile.in (SRC): forgot to add motd.c to SRC in
+       Makefile.(in); also ran make depend
+
+       * include/motd.h: don't need config.h, but now do need time.h;
+       define new structures and constants; redefine old API and define
+       new functions
+
+2000-11-22  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/s_user.c (register_user): use motd_signon() instead of
+       calling m_motd; much cleaner this way
+
+       * ircd/motd.c: write the new motd_* stuff to make MOTD handling
+       less of a crock
+
+       * ircd/m_motd.c: rewrite m{,s}_motd to call out to new motd_*
+       functions
+
+       * include/motd.h: define new MOTD API stuff
+
+2000-11-20  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/ircd_reply.c (protocol_violation): rewrite
+       protocol_violation so it'll actually work
+
+       oh, yeah, use %s -> cptr->name, instead of %c -> cptr, so we get
+       the client's real name in there.
+
+       * ircd/m_motd.c (m_motd): Iso's addition of get_client_class(sptr)
+       resulted in core dumps if NODEFAULTMOTD is defined, because m_motd
+       gets called from register_user with a NULL sptr.  This is probably
+       a design problem, but this bandaid will do for now...
+
+2000-11-19  Isomer <isomer@coders.net>
+       * ircd/ircd_reply.c: added 'protocol_violation', thus alerting us
+       to problems in the server<->server protocol.
+
+       * ircd/m_connect.c: allow remote connects with a port of '0'
+       meaning to use the port in the config file.
+
+       * ircd/m_create.c: Enable hacking protection, lets see how far we
+       get.
+
+       * ircd/m_error.c: The RFC says never accept ERROR from unreg'd
+       clients, so we don't any more.
+
+       * ircd/m_kill.c: The kill path is now made up of numnicks of servers,
+       and the user@host is displayed of the victim.
+
+       * ircd/m_map.c: reloaded 'dump_map'.
+
+       * ircd/m_trace.c: allow per class T:
+
+       * ircd/m_stats.c: allow local opers /remote stats anywhere on the 'net.
+
+2000-11-17  Isomer <isomer@coders.net>
+
+       * ircd/m_topic.c: Fixed bug where we'd only send to clients topics
+       that were the *same* instead of different.  Oh the embarrasment!
+
+       * ircd/IPcheck.c: Merged net's fix.
+
+2000-11-02  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/m_whois.c: remove compiler warning by adding a newline to
+       end of file
+
+       * ircd/m_names.c: moved the flags up to s_user.h
+
+       * ircd/m_join.c: call do_names instead of m_names; restructure
+       ms_join to never transmute a JOIN into a CREATE, but use the TS in
+       the JOIN (if present) to timestamp the channel
+
+       * ircd/channel.c: send JOINs individually, instead of grouping
+       them, so that we can send the channel's creation time
+
+       * include/s_user.h: declare do_names()
+
+2000-10-30  Isomer <isomer@coders.net>
+       * ircd/m_oper.c: Fixed warning
+
+2000-10-30  Isomer <isomer@coders.net>
+       * ircd/m_oper.c: Fixed over agressive cut and no paste
+
+2000-10-30  Isomer <isomer@coders.net>
+
+       * ircd/m_topic.c: Restructured, fixed bug where topics on local
+       channels are propergated (I forget who pointed this out to me, but
+       thanks anyway).  Also to save bandwidth don't send the topic to
+       users if the topic is already the same on the server (but still
+       propergate to other servers).  X/W's "autotopic" feature must
+       chew a lot of bandwidth, hopefully this will help reduce this.
+
+       * doc/rfc1459.rfc: Updated documentation on /topic.
+
+       * ircd/listener.c: snotice warnings about failed accept()'s
+       potentially warning admins that they're running out of fd's.
+
+       * ircd/stats.c, ircd/class.c: Removed /stats v, added number of
+       people in a class in /stats y
+
+       * ircd/m_create.c: Checks for timewarp hacking and squit's
+       evil servers. (currently disabled)
+       
+
+2000-10-30  net <simms@lucida.qc.ca>
+       
+       * ircd/gline.c: Fixed various bugs Isomer left behind.
+
+2000-10-26  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/m_join.c (m_join): reply on attempt to join a BADCHANed
+       channel is now ERR_BANNEDFROMCHAN instead of ERR_BADCHANNAME
+
+2000-10-24  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/channel.c: ok, now last mode rules; mode +ps will always
+       result in +s (and won't send a mode if the channel is already +s);
+       mode +sp will always result in +p; -n+n on a +n channel results in
+       no mode change; -n+n on a -n channel results in a +n mode change;
+       etc.
+
+2000-10-23  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/channel.c: add "add" and "del" elements to ParseState to
+       avoid not-too-pretty -p+s when +s is sufficient; fix a bug in
+       mode_parse_limit that caused it to clear all channel modes
+       prematurely; restructure mode_parse_mode to avoid calling
+       modebuf_mode too early (ties in with first mentioned change);
+       better logic for +p/+s mutual exclusivity; initialize "add" and
+       "del" elements in mode_parse; send simple modes down to
+       modebuf_mode after the loop in mode_parse
+
+2000-09-28  Greg Sikorski <gte@atomicrevs.demon.co.uk>
+       * ircd/m_names.c: Fixed a non-lethal logic error that 
+       triggers an assert() in find_member_link while debugging.
+       (Spotted by Maniac-).
+2000-09-19  Thomas Helvey <helveytw@home.com>
+       * ircd/s_conf.c: move K:lines to their own list and data
+       structures, add supporting code.
+       * ircd/m_stats.c: cleanup stats processing a bit move
+       kline listing code to a new function, haven't figured
+       out where it goes yet tho'
+       * ircd/s_stats.c: added K:line bulk lister
+       * include/s_conf.h: added new DenyConf struct
+       * *[ch]: fixeup code that depended on changes
+
+2000-09-17  Thomas Helvey <helveytw@home.com>
+       * ircd/class.c: encapsulate class list
+       * include/class.h: clean up classes
+       * * fixup code that depended on changes
+
+2000-09-17  Thomas Helvey <helveytw@home.com>
+       * ircd/s_conf.c: add me to local conf
+       * include/s_conf.h: move CONF_ME macro to chkconf.c
+       * ircd/s_bsd.c: cleanup initialization, allow virtual host
+       to be changed by rehash
+
+2000-09-17  Thomas Helvey <helveytw@home.com>
+       * include/class.h: add missing prototype
+       * ircd/class.c: make argument to get_conf_class const
+
+2000-09-17  Thomas Helvey <helveytw@home.com>
+       * ircd/*.c: merged in changes from 2.10.10.pl12, cleanup
+       merge conflicts.
+       * ircd/*.h: merged in changes from 2.10.10.pl12, cleanup
+       merge conflicts
+
+2000-09-16  Thomas Helvey <helveytw@home.com>
+       * ircd/s_conf.c: add code for server struct
+       * ircd/client.c: copy of class.c sort of, new file for client
+       specific operations, will move things here as appropriate,
+       currently only one function is exported from here.
+       * ircd/*.c: general logic cleanups, convert negatives to
+       positives in places.
+
+2000-09-16  Thomas Helvey <helveytw@home.com>
+       * ircd/s_conf.c: add code for new crule data structs, strip quotes
+       * ircd/crule.c: clean up scary casting a bit, type safety stuff
+       * include/s_conf.h: add CRuleConf struct and support, remove
+       unused constants
+       * include/crule.h: type safety cleanups
+       * ircd/*.c: fixup code that depended on stuff I changed
+
+2000-09-15  Thomas Helvey <helveytw@home.com>
+       * ircd/s_conf.c: start adding code for new conf data structs, changed
+       listeners, admin line, motd lines, class lines. Move validate_hostent
+       to resolver. General mayhem.
+       * include/s_conf.h: new data structs and accessors
+       * ircd/res.c: move validate_hostent here, rewrite, use regular
+       expression for validation.
+       * doc/example.conf: update docs for port
+
+2000-09-14  Thomas Helvey <helveytw@home.com>
+       * ircd/s_conf.c (conf_init): rewrite conf file parser, start to break
+       up conf_init into managable chunks.
+       * ircd/listener.c (set_listener_mask): fix logic bug core dump.
+       * include/s_conf.h: add new data struct for local info (unwinding the mess).
+
+2000-09-13  Thomas Helvey <helveytw@home.com>
+       * ircd/list.c: put Clients in free lists, pre-allocate MAXCONNECTIONS
+       local clients.
+       * ircd/list.c: put SLinks in free lists
+       * ircd/channel.c: put Memberships in free lists
+       * ircd/ircd.c: rearrange initializations a bit in main
+       Note: With these changes, ircd NEVER frees Clients, SLinks or
+       Memberships. It will also rarely need to allocate new
+       ones during net bursts and other disruptions. This should
+       cut down on memory fragmentation a bit as well.
+
+2000-08-30  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/m_names.c (do_names): pull-up from do_names fix in
+       u2.10.10.pl11
+
+2000-07-15  Perry Lorier       <Isomer@coders.net>
+       * various: IP only k:'s and G:'s now do bit tests instead of two(!) 
+                 match()'s.  Major Major cpu savings.  Also speed up the
+                 other case slightly.  As a side effect you can now
+                k/Gline *@10.0.0.0/8.  I'll do bans tomorrow, it's nearing
+                3am.
+
+2000-07-15  Perry Lorier       <Isomer@coders.net>
+       * various: Fixed warnings after compiling on an alpha.
+2000-07-09  Perry Lorier       <Isomer@coders.net>
+       * doc/ircd.8: Applied grammitical changes by Liandrin, applied
+                     changes suggested by various other people.
+       * ircd/IPcheck.c: More bug fixes.  Current problem appears to be
+                       that it gets a corrupt entry somehow.
+2000-07-09  Greg Sikorski <gte@atomicrevs.demon.co.uk>
+       * ircd/m_oper.c: Clean up compiler warning.
+
+2000-07-08  Perry Lorier       <Isomer@coders.net>
+       * doc/ircd.8: Updated the documentation, it was slightly out of date
+                     being updated around 1989.
+       * ircd/m_whois.c: Rewrote for clarity, and probably a bit more speed.
+                         fixed a few minor glitches.
+       * doc/rfc1459.unet: Updated.
+       * ircd/IPcheck.c: Fixed more bugs.
+       * ircd/s_bsd.c: We now keep track of servers we've conected.
+
+2000-07-02  Perry Lorier       <Isomer@coders.net>
+       * ircd/s_misc.c: Fixed remote IPcheck bug.  Ok, I'm a moron, so sue
+                       me.  Thanks to Hektik, thanks thanks thanks thanks
+                       thanks thanks thanks thanks thank thanks thank thanks
+
+2000-07-01  Perry Lorier       <Isomer@coders.net>
+       * ircd/s_conf.c: "Fixed" the "bug" where people would "evade" K:'s.
+       * ircd/s_conf.c, include/IPcheck.h: Fixed compile warnings.
+
+2000-06-22  Perry Lorier       <Isomer@coders.net>
+       * ircd/IPcheck.c: Large chunks redone.
+       * ircd/s_conf.c: Changes due to IPcheck - ONE nolonger supported,
+                       single AND double digit limits are allowed now.
+       * misc other: Changes to IPcheck.
+
+2000-06-30  Perry Lorier       <Isomer@coders.net>
+       * ircd/ircd.c: Fix command line parameter bugs.
+
+2000-06-30  Perry Lorier       <Isomer@coders.net>
+       * ircd/m_kill.c: Fixed bug with LOCAL_KILL_ONLY
+       * ircd/m_nick.c: Tidied things up.
+
+2000-06-12 Joseph Bongaarts <foxxe@trms.com>
+       * ircd/m_stats.c: Iso forgot mo_stats when he added /stats v
+       
+2000-05-29  Perry Lorier       <Isomer@coders.net>
+       * ircd/m_stats.c: add /stats v to do only the last part of the /trace
+       * ircd/IPcheck.c: Cosmetic change, if we meddle with it enough do
+                       you think it'll get bored and fix itself?
+
+2000-06-09  Greg Sikorski <gte@atomicrevs.demon.co.uk>
+
+       * ircd/m_names.c: Clean up compiler warnings.
+
+2000-06-09  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/channel.c (mode_parse_client): don't send warning if
+       there's not enough arguments for a +/-o/v; means the habit of
+       doing "/mode #channel +oooooo bob" doesn't result in a bunch of
+       error messages
+
+2000-06-04  Greg Sikorski <gte@atomicrevs.demon.co.uk>
+
+       * ircd/m_names.c: Re-factor code to remove unneccessary
+       GlobalChannelList iteration every time someone joins a channel.
+
+2000-06-02  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/s_user.c: add struct Gline * argument to register_user;
+       look up global glines and repropagate them if necessary; send
+       acknowledgement of gline to remote servers when registering users
+
+       * ircd/s_serv.c (server_estab): don't send acknowledgement of
+       local glines to remote servers; do send gline acknowledgement of
+       bursted users
+
+       * ircd/m_user.c (m_user): pass new struct Gline * argument to
+       register_user
+
+       * ircd/m_pong.c: pass new struct Gline * argument to register_user
+
+       * ircd/m_nick.c (ms_nick): document protocol change
+
+       * ircd/gline.c: support GLINE_LASTMOD
+
+       * include/s_user.h: add struct Gline * argument to register_user
+
+       * include/gline.h: add GLINE_LASTMOD to look up non-zero lastmods
+
+       * ircd/s_conf.c (find_kill): add unsigned int argument to
+       gline_lookup()
+
+       * ircd/gline.c: add GLINE_GLOBAL to lookup or find only global
+       glines; add unsigned int argument to gline_lookup()
+
+       * include/gline.h: add GLINE_GLOBAL flag; add unsigned int
+       argument to gline_lookup()
+
+       * ircd/m_server.c: Resend jupe only when there is no %<lastmod>
+       parameter, or when it falls out of bounds: see comments prior to
+       call to jupe_resend(); call server_estab with struct Jupe
+       parameter, so that we place the appropriate %<lastmod> in the
+       appropriate place.
+
+       * ircd/s_serv.c (server_estab): send %<lastmod> for introduced
+       server, as well as for servers when we're sending the BURST
+
+       * include/s_serv.h: add a struct Jupe * to the arguments for
+       server_estab() so that we can send the appropriate lastmod
+       parameter
+
+       * ircd/m_gline.c (ms_gline): actually, this should be the
+       slightest bit more efficient...
+
+       * ircd/m_jupe.c (ms_jupe): actually, this should be the slightest
+       bit more efficient...
+
+       * ircd/m_gline.c (ms_gline): inhibit GLINE processing resends
+       during netburst
+
+       * ircd/m_jupe.c (ms_jupe): inhibit JUPE processing resends during
+       netburst
+
+       * ircd/channel.c (joinbuf_join): really remove user from local
+       channels
+
+2000-05-29  Perry Lorier       <Isomer@coders.net>
+       * ircd/m_names.c: Removed redundant space. 
+       * ircd/s_bsd.c: Fixed incorrect syntax on ERROR line.
+
+2000-05-18  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/m_burst.c (ms_burst): er...that should have been a ",", not
+       a " "
+
+2000-05-04  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/channel.c: replace bogus assertions with returns, which is
+       logically correct; only wipe out limit/key if they were originally
+       set in the first place; remove user from channel when doing a
+       PARTALL; only send MODE +o for user CREATEing channel if user is
+       not MyUser--CREATE will only be used if the channel did not
+       originally exist, therefore we can assume no one local is on the
+       channel anyway, and we don't exactly need for the user to see an
+       explicit +o for themselves
+
+       * doc/readme.gline: describe the syntax of the GLINE command
+
+       * doc/readme.jupe: update to reflect a couple of changes to JUPE
+
+       * ircd/gline.c: don't propagate local changes
+
+       * ircd/jupe.c: don't propagate local changes
+
+       * ircd/m_gline.c (mo_gline): force local flag when deactivating
+       glines with 0 lastmod
+
+       * ircd/gline.c (gline_deactivate): G-lines with zero lastmod time
+       are now removed instead of being deactivated
+
+       * ircd/m_gline.c (ms_gline): make G-lines of the form "GLINE *
+       -<mask>" be accepted
+
+       * ircd/channel.c (send_channel_modes): deal with one of the last
+       vestiges of sendbuf
+
+       * ircd/m_burst.c (ms_burst): debugged ban processing; removed
+       debugging hooks
+
+       * ircd/channel.c (modebuf_extract): remove debugging
+       sendto_opmask_butone calls
+
+2000-05-03  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/channel.c: support a couple of new flags to support using
+       mode_parse; fix some bugs with 0 struct ModeBuf *; implementation
+       of modebuf_extract to extract added flags for use by ms_burst
+
+       * include/channel.h: a couple of new flags to support using
+       mode_parse inside ms_burst
+
+       * ircd/m_burst.c (ms_burst): brand new implementation of BURST
+
+       * ircd/m_endburst.c: add loop to processing of end_of_burst to
+       free empty channels after the BURST is over.
+
+       * ircd/m_server.c: convert to use new send.c functions--I wanted
+       to rewrite it from scratch, but the logic's pretty complex; I may
+       still rewrite it, though...
+
+2000-05-02  Thomas Helvey <tomh@inxpress.net>
+
+       * ircd/ircd.c: fix broken header include ordering
+
+2000-05-02  Thomas Helvey <tomh@inxpress.net>
+       
+       * ircd/IPcheck.c: cleanups for ZenShadow's cleanups
+        review emailed privately
+
+       * include/IPcheck.h: removed unneeded include
+
+2000-05-02  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/s_user.c (hunt_server): throw in a comment so I know what
+       the sendto_one is for
+
+       * include/querycmds.h (Count_unknownbecomesclient): convert to
+       sendto_opmask_butone
+
+       * ircd/send.c: start removing dead code
+
+       * include/send.h: start removing dead code
+
+       * ircd/m_rping.c: convert to sendcmdto_one / send_reply /
+       hunt_server_cmd
+
+       * ircd/m_rpong.c: convert to sendcmdto_one / send_reply
+
+2000-05-01  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/m_stats.c: convert to sendcmdto_one / send_reply
+
+       * ircd/m_kick.c: Completely reimplement m_kick
+
+       * ircd/channel.c: send_user_joins removed; it was dead code,
+       anyway...
+
+2000-05-01  Perry Lorier <isomer@coders.net>
+       * ircd/m_invite.c: Fix for the rest of m_invite.c, and again.
+       * ircd/channels.c: My fix for the part problem.  Untested, probably
+               won't work.  Can't be much worse than the current problem.
+               it'll either work or core, take your pick.
+
+
+2000-04-30  Perry Lorier <isomer@coders.net>
+       * config/config-sh.in: Fix for CONNEXIT
+       * ircd/s_{user,misc}.c: Fix for CONNEXIT
+       * ircd/m_invite.c: Fix for incorrectly numnickified invite.
+                       (Kev: Want to come talk to me about this?)
+
+2000-04-30  Steven M. Doyle <steven@doyle.net>
+       * ircd/ircd.c
+         - general cleanups and readability enhancements
+         - rewrite of setuid/chroot code.
+         - server will no longer run as root
+         - -DPROFIL compile option removed
+         - Fixed IPcheck API calls
+       * config/config-sh.in
+         - Fixed up chroot compile options
+         - Added options for debug and profile compiles
+       * config/gen.ircd.Makefile
+         - Support for new debug/profile options
+       * ircd/Makefile.in
+         - Support for new debug/profile options
+       * ircd/ircd_signal.c
+         - Removed -DPROFIL
+
+       * include/IPcheck.h
+         - Removed old API prototypes, added new ones
+       
+       * ircd/IPcheck.c
+         - Readability cleanups (well, I -think-...)
+         - Changed IPRegistryEntry.last_connect to a time_t.  The previously
+           used unsigned short was probably causing interesting things after
+           a client had been connected longer than about 65,535 seconds...
+         - Removed old API functions.
+
+       * ircd/whocmds.c
+         - Removed IPcheck.h include
+       
+       * Additionally modified IPcheck API calls in:
+         - ircd/m_nick.c
+         - ircd/m_auth.c
+         - ircd/s_bsd.c
+         - ircd/s_conf.c
+         - ircd/s_misc.c
+         - ircd/s_serv.c
+         - ircd/s_user.c
+       
+       
+2000-04-30  Perry Lorier <isomer@coders.net>
+       * ircd/s_bsd.c: Sigh. :)
+        * ircd/m_mode.c: fix for modeless channels by poptix.
+
+2000-04-29  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/m_join.c: reimplement JOIN in terms of struct JoinBuf
+
+       * ircd/channel.c (clean_channelname): make clean_channelname also
+       truncate long channel names
+
+2000-04-28  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/m_create.c: reimplement CREATE in terms of struct JoinBuf
+
+       * ircd/channel.c: implemented joinbuf_init, joinbuf_join,
+       joinbuf_flush
+
+       * include/channel.h: definitions and declarations for the struct
+       JoinBuf abstraction
+
+2000-04-29  Perry Lorier <isomer@coders.net>
+       * ircd/s_bsd.c: Ok, so I thought I compiled and tested this...
+
+2000-04-29  Perry Lorier <isomer@coders.net>
+       * ircd/s_bsd.c: Add debugging code to IPcheck
+
+2000-04-28  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * include/ircd_reply.h (SND_EXPLICIT): use instead of RPL_EXPLICIT
+
+       * ircd/ircd_reply.c (send_reply): use SND_EXPLICIT instead of
+       RPL_EXPLICIT
+
+       * ircd/m_userhost.c (m_userhost): add a dead code comment
+
+       * ircd/m_desynch.c: forgot one...
+
+       * ircd/m_rehash.c (mo_rehash): er, duplicates :)
+
+       * ircd/m_proto.c (proto_send_supported): just change a comment so
+       it doesn't show up in my scans
+
+       * ircd/ircd_reply.c (send_reply): fix a slight bug...
+
+       * ircd/s_numeric.c (do_numeric): use new sendcmdto_* functions,
+       kinda hackish...
+
+       * ircd/parse.c (parse_server): argument wrangling to make
+       processing in do_numeric a little easier to deal with
+
+       * ircd/s_serv.c (server_estab): SERVER should come from
+       acptr->serv->up, not &me
+
+       * ircd/m_lusers.c: accidentally left out sptr for a %C
+
+       * ircd/send.c: hack to support doing wallchops...
+
+       * ircd/m_whowas.c: convert to new send functions
+
+       * ircd/m_whois.c: convert to new send functions
+
+       * ircd/m_who.c: convert to new send functions
+
+       * ircd/m_wallops.c: convert to new send functions
+
+       * ircd/m_wallchops.c: convert to new send functions
+
+       * ircd/m_version.c: convert to new send functions
+
+       * ircd/m_userip.c: convert to new send functions
+
+       * ircd/m_userhost.c: convert to new send functions
+
+       * ircd/m_uping.c: convert to new send functions
+
+       * ircd/m_trace.c: convert to new send functions
+
+       * ircd/m_topic.c: convert to new send functions
+
+       * ircd/m_time.c: convert to new send functions
+
+       * ircd/m_squit.c: convert to new send functions
+
+       * ircd/m_silence.c: convert to new send functions
+
+       * ircd/m_settime.c: convert to new send functions
+
+       * ircd/m_restart.c: convert to new send functions
+
+       * ircd/m_rehash.c: convert to new send functions
+
+       * ircd/m_privmsg.c: convert to new send functions
+
+       * ircd/m_pong.c: convert to new send functions
+
+       * ircd/m_ping.c: convert to new send functions
+
+       * ircd/m_pass.c: convert to new send functions
+
+       * ircd/m_opmode.c: convert to new send functions
+
+       * ircd/m_oper.c: convert to new send functions
+
+       * ircd/m_notice.c: convert to new send functions
+
+       * ircd/m_nick.c: convert to new send functions
+
+       * ircd/m_names.c: convert to new send functions
+
+       * ircd/m_motd.c: convert to new send functions
+
+       * ircd/m_mode.c: convert to new send functions
+
+       * ircd/m_map.c: convert to new send functions
+
+       * ircd/m_lusers.c: convert to new send functions
+
+       * ircd/m_list.c: convert to new send functions
+
+       * ircd/m_links.c: convert to new send functions
+
+       * ircd/m_kill.c: convert to new send functions
+
+       * ircd/m_jupe.c: convert to new send functions
+
+       * ircd/m_invite.c: convert to new send functions
+
+       * ircd/m_info.c: convert to new send functions
+
+       * ircd/m_help.c: convert to new send functions
+
+       * ircd/m_gline.c: convert to new send functions
+
+       * ircd/m_error.c: convert to new send functions
+
+       * ircd/m_endburst.c: convert to new send functions
+
+       * ircd/m_die.c: convert to new send functions
+
+       * ircd/m_destruct.c: convert to new send functions
+
+       * ircd/m_defaults.c: convert to new send functions
+
+       * ircd/m_connect.c: convert to new send functions
+
+2000-04-28  Perry Lorier <isomer@coders.net>
+       * RELEASE.NOTES: Describe a few more undocumented features.
+       * config/config-sh.in: change the default paths for logging
+       and the recommended number of channels.
+       * include/supported.h: Rearrange slightly, added CHANTYPE's
+
+2000-04-27  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/m_close.c: convert to send_reply
+
+       * ircd/m_clearmode.c: convert to send_reply, sendcmdto_serv_butone
+
+       * ircd/m_away.c: convert to send_reply and sendcmdto_serv_butone
+
+       * ircd/m_admin.c: convert to send_reply and hunt_server_cmd
+
+       * ircd/s_user.c (hunt_server_cmd): new hunt_server replacement
+       that takes cmd and tok arguments, etc.  NOTE: THIS IMPLEMENTATION
+       HAS A MAJOR HACK!!!  The whole hunt_server architecture should be
+       carefully rethought...
+
+       * ircd/s_stats.c (hunt_stats): use new hunt_server_cmd
+
+       * include/s_user.h: hunt_server_cmd -- replacement for hunt_server
+
+       * ircd/s_misc.c: *sigh* 2.10.10 doesn't support squitting by
+       numeric nick; therefore, we have to use the server name
+
+       * ircd/m_squit.c (ms_squit): allow to squit by server numeric nick
+
+       * ircd/send.c: fix minor bugs
+
+       * ircd/s_user.c (check_target_limit): mark dead code so I filter
+       it when I grep
+
+       * ircd/s_serv.c (exit_new_server): mark dead code so I filter it
+       when I grep
+
+       * ircd/parse.c: mark dead code so I filter it when I grep
+
+       * ircd/map.c: mark dead code so I filter it when I grep
+
+       * ircd/ircd.c: mark dead code so I filter it when I grep
+
+       * ircd/ircd_relay.c: convert over to new sendcmdto_*, send_reply
+       functions
+
+       * ircd/channel.c: mark dead code so I filter it when I grep
+
+       * ircd/s_stats.c: use send_reply instead of sendto_one w/rpl_str;
+       hope I'm not stepping on toes...
+
+       * ircd/s_conf.c: more sendto_opmask_butone / send_reply
+       conversions; use ircd_snprintf in a couple of cases to negate the
+       possibility of buffer overflow
+
+2000-04-26  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/channel.c: convert as much as possible to new send
+       semantics
+
+       * ircd/send.c (sendcmdto_common_channels): fix a subtle bug --
+       test member->user->from->fd, not from->fd
+
+       * ircd/gline.c (gline_add): go ahead and add badchans; we just
+       won't look for them in m_gline; this way, they always work...
+
+       * ircd/jupe.c: use ircd_vsnprintf conversion specifiers
+
+       * ircd/gline.c: since write_log now uses ircd_vsnprintf, use
+       ircd_vsnprintf conversion specifiers
+
+       * ircd/support.c (write_log): use ircd_vsnprintf for write_log, so
+       I have my conversion specifiers
+
+       * ircd/gline.c (do_gline): use send_reply for ERR_YOUREBANNEDCREEP
+
+       * ircd/send.c (sendcmdto_flag_butone): explicitly send WALLOPS to
+       local users
+
+       * ircd/s_serv.c (exit_new_server): rewrite exit_new_server to be a
+       little less brain-dead
+
+       * ircd/s_misc.c: use sendcmdto_one, sendrawto_one, and send_reply
+
+       * ircd/s_debug.c: use send_reply with RPL_EXPLICIT for
+       RPL_STATSDEBUG
+
+       * ircd/res.c (cres_mem): use send_reply with RPL_EXPLICIT for
+       RPL_STATSDEBUG
+
+       * ircd/list.c (send_listinfo): use send_reply with RPL_EXPLICIT
+       for RPL_STATSDEBUG
+
+       * ircd/m_pong.c: use RPL_EXPLICIT for ERR_BADPING
+
+       * ircd/ircd.c: use RPL_EXPLICIT for ERR_BADPING
+
+       * ircd/s_user.c (register_user): use RPL_EXPLICIT for
+       ERR_INVALIDUSERNAME
+
+       * ircd/ircd_reply.c (send_reply): support RPL_EXPLICIT
+
+       * include/ircd_reply.h (RPL_EXPLICIT): somewhat of a hack to mark
+       a numeric as needing to use an explicit pattern, which will be the
+       first argument in the variable argument list
+
+       * ircd/s_user.c: use sendrawto_one instead of sendto_one to send
+       non-prefixed nospoof PING
+
+       * ircd/s_bsd.c: use sendrawto_one instead of sendto_one to send
+       non-prefixed SERVER login
+
+       * ircd/ircd.c (check_pings): fix last sendto_one calls (except for
+       a numeric usage further up)
+
+       * include/send.h: declare sendrawto_one
+
+       * ircd/send.c (sendrawto_one): new function to use ONLY for
+       non-prefixed commands, like PING to client, or PASS/SERVER on
+       server registration
+
+2000-04-25  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/ircd_snprintf.c (doprintf): implement %H for possible
+       future expansion (channel numerics?)
+
+       * include/ircd_snprintf.h: added documentation to # to explain use
+       with %C; added documentation for : to explain use with %C; added
+       documentation for %H for channels
+
+       * ircd/whocmds.c: use send_reply
+
+       * ircd/userload.c: use sendcmdto_one
+
+       * ircd/uping.c: use sendcmdto_one
+
+       * ircd/send.c: use new flags to %C format string; ':' prefixes
+       client name with a colon for local connects, '#' uses
+       nick!user@host form for local connects
+
+       * ircd/s_user.c: use send_reply, sendto_opmask_butone,
+       sendcmdto_one, sendcmdto_serv_butone, sendcmdto_flag_butone
+
+       * ircd/s_serv.c: use sendcmdto_one, sendto_opmask_butone
+
+       * ircd/s_bsd.c: use sendto_opmask_butone, send_reply,
+       sendcmdto_one
+
+       * ircd/s_auth.c: use sendto_opmask_butone
+
+       * ircd/res.c: use sendcmdto_one
+
+       * ircd/ircd_snprintf.c (doprintf): minor bug fixes and some
+       debugging assertions
+
+2000-04-24  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/support.c: dumpcore is no longer used, so get rid of it
+
+       * ircd/parse.c: use send_reply, sendcmdto_one
+
+       * ircd/map.c: use send_reply
+
+       * ircd/listener.c: use send_reply
+
+       * ircd/jupe.c: use sendto_opmask_butone, send_reply
+
+       * ircd/ircd_reply.c: use send_reply
+
+       * ircd/ircd.c: use sendto_opmask_butone
+
+       * ircd/gline.c: use sendto_opmask_butone, send_reply
+
+       * ircd/ircd_snprintf.c (doprintf): make it deal with incompletely
+       registered clients; make FLAG_ALT print nick!user@host; make
+       FLAG_COLON print :blah
+
+       * ircd/class.c (report_classes): use send_reply instead of
+       sendto_one
+
+       * ircd/hash.c (m_hash): replace sendto_one with sendcmdto_one
+
+       * ircd/IPcheck.c (ip_registry_connect_succeeded): replace
+       sendto_one with sendcmdto_one
+
+2000-04-21  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/send.c: clean up logic in sendcmdto_channel_butone; use
+       MyConnect() instead of IsServer() in sendcmdto_flag_butone; define
+       sendcmdto_match_butone
+
+       * include/send.h: declare sendcmdto_match_butone
+
+2000-04-20  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/jupe.c: update to use send_reply()
+
+       * ircd/gline.c: update to use send_reply()
+
+       * include/ircd_reply.h: declare send_reply
+
+       * ircd/ircd_reply.c (send_reply): send_error_to_client, but for
+       replies; uses ircd_snprintf
+
+       * ircd/send.c: added comments to redirect searchers to appropriate
+       sendcmdto_* function; moved new functions to end of file; added
+       explanatory comments; reordered arguments; defined new functions
+       mentioned below
+
+       * ircd/m_jupe.c: reorder arguments to sendcmdto_* functions
+
+       * ircd/m_gline.c: reorder arguments to sendcmdto_* functions
+
+       * ircd/jupe.c: reorder arguments to sendcmdto_* functions
+
+       * ircd/gline.c: reorder arguments to sendcmdto_* functions
+
+       * include/send.h: reorder arguments, add explanatory comments,
+       declare new functions sendcmdto_flag_butone, sendto_opmask_butone,
+       and vsendto_opmask_butone
+
+2000-04-19  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/send.c: define sendcmdto_channel_butone, wrote a simplified
+       vsendto_op_mask that uses '*' instead of the receiving client
+       nickname
+
+       * include/send.h: declare sendcmdto_channel_butone; takes a skip
+       argument that allows you to skip (or not to skip) deaf users,
+       users behind bursting servers, and non channel operators
+
+2000-04-17  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/send.c: new sendcmdto_channel_butserv -- note that old
+       sendto_channel_butserv has a subtle bug; also wrote
+       sendcmdto_common_channels.
+
+       * include/send.h: declare new sendcmdto_* functions
+
+       * ircd/jupe.c: support local deactivations of jupes
+
+       * ircd/gline.c: support local deactivations of glines
+
+       * include/jupe.h: JUPE_LDEACT allows jupes to be locally
+       deactivated; if they aren't locally deactivated, then it slaves to
+       the net-wide activation status; JupeIsRemActive() tests only
+       whether the jupe is active everywhere else
+
+       * include/gline.h: GLINE_LDEACT allows glines to be locally
+       deactivated; if they aren't locally deactivated, then it slaves to
+       the net-wide activation status; GlineIsRemActive() tests only
+       whether the gline is active everywhere else
+
+       * ircd/gline.c: detect overlapping G-lines; if an existing, wider
+       gline expires after the new one will, we drop the new one,
+       otherwise we add the G-line after that one (so the wide one will
+       apply first); if the new one contains an existing G-line and if it
+       will expire after the existing one, we drop the existing one to
+       save memory
+
+       * ircd/m_gline.c (mo_gline): opers could issue remote local
+       glines when CONFIG_OPERCMDS was off; fixed
+
+2000-04-16  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/m_jupe.c (mo_jupe): allow target argument to be dropped if
+       this is a local JUPE
+
+       * ircd/gline.c: add flags argument to gline_activate and
+       gline_deactivate for future expansion
+
+       * ircd/m_gline.c: pass flags to gline_activate and
+       gline_deactivate
+
+       * include/gline.h: add flags argument to gline_activate and
+       gline_deactivate
+
+       * ircd/jupe.c: add flags argument to jupe_activate and
+       jupe_deactivate for future expansion
+
+       * include/jupe.h: add flags argument to jupe_activate and
+       jupe_deactivate
+
+       * ircd/m_jupe.c: pass a flags argument to jupe_add instead of
+       local, active; pass flags to jupe_activate and jupe_deactivate
+
+       * include/gline.h: remove dead code
+
+       * ircd/gline.c: make gline expire times relative to CurrentTime,
+       since that should be monotonically increasing, instead of
+       TStime(), which can be set backwards, and which can therefore
+       cause an expire time to increase; make local glines be removed
+       instead of just deactivated; don't let gline_find() look for
+       user@host glines if the mask being looked up is a channel mask
+
+       * ircd/send.c (vsendcmdto_one): forgot to account for the case
+       where origin is a server and destination is a user
+
+       * ircd/jupe.c: make jupe expire times relative to CurrentTime,
+       since that should be monotonically increasing, instead of
+       TStime(), which can be set backwards, and which can therefore
+       cause an expire time to increase; make local jupes be removed
+       instead of just deactivated
+
+       * ircd/ircd_snprintf.c: d'oh, thanks for catching that; short for
+       limit is fine.  any other warnings I should know about?
+
+2000-04-15  Thomas Helvey <tomh@inxpress.net>
+
+       * ircd/*.c: const correctness and type safety cleanups to
+       get code to compile with C++ compiler. Still has
+       signed/unsigned comparison warnings.
+
+2000-04-15  Greg Sikorski <gte@atomicrevs.demon.co.uk>
+
+       * ircd/userload.c: change <sys/time.h> include to <time.h> for
+         portability.
+
+2000-04-14  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/m_gline.c (mo_gline): d'oh, target isn't a numeric; use %C
+       and convert acptr...
+
+       * ircd/s_user.c: move gline_lookup function call into
+       register_user, where it'll have a username to lookup!
+
+       * ircd/m_gline.c: modify to utilize new sendcmdto_* series of
+       functions; also stuff send_error_to_client into return clauses
+
+       * ircd/m_jupe.c: modify to utilize new sendcmdto_* series of
+       functions; also use send_error_to_client where that makes sense
+
+       * ircd/jupe.c: modify to utilize new sendcmdto_* series of
+       functions; also use send_error_to_client where that makes sense
+
+       * ircd/gline.c: modify to utilize new sendcmdto_* series of
+       functions; also fix gline_lookup() to deal properly with remote
+       clients--boy, do struct Client and struct User need to be cleaned
+       up!
+
+       * ircd/ircd_snprintf.c (doprintf): a dest of &me is a server,
+       too...
+
+       * ircd/send.c: wrote sendcmdto_one(), vsendcmdto_one(), and
+       sendcmdto_serv_butone(), all utilizing the %v conversion of
+       ircd_snprintf()
+
+       * include/send.h: define IRC_BUFSIZE, max size of a message;
+       declare sendcmdto_one(), vsendcmdto_one(), and
+       sendcmdto_serv_butone()
+
+       * include/msg.h: define all the CMD_* constants needed to utilize
+       the new sendcmdto_* series of functions
+
+       * ircd/Makefile.in (SRC): list ircd_snprintf.c; run make depend
+
+       * ircd/gline.c: remove old, dead code.
+
+       * ircd/m_gline.c (mo_gline): disallow setting of global G-lines
+       unless CONFIG_OPERCMDS is enabled; disallow listing of all G-lines
+       (don't advertise proxies); remove dead code
+
+       * ircd/parse.c: oper handler for JUPE only lists jupes unless
+       CONFIG_OPERCMDS is enabled
+
+       * ircd/m_jupe.c (mo_jupe): don't compile mo_jupe() if
+       CONFIG_OPERCMDS is not enabled; we'll disable it in parse.c
+
+       * ircd/m_opmode.c (mo_opmode): if CONFIG_OPERCMDS is not enabled,
+       always return ERR_DISABLED
+
+       * ircd/m_clearmode.c (mo_clearmode): if CONFIG_OPERCMDS is not
+       enabled, always return ERR_DISABLED
+
+       * ircd/s_err.c: add error message to indicate disabled commands
+
+       * include/numeric.h (ERR_DISABLED): to indicate disabled commands
+
+       * doc/Configure.help: add documentation for CONFIG_OPERCMDS
+
+       * config/config-sh.in: add CONFIG_OPERCMDS, default both it and
+       CONFIG_NEW_MODE to 'y' for now
+
+       * ircd/gline.c (gline_list): fix a minor formatting bogon
+
+       * BUGS: since I fixed that bug, might as well mark it fixed.
+
+       * ircd/m_join.c: look up badchans with GLINE_EXACT
+
+       * ircd/m_gline.c: fix parc count problems; look up existing
+       G-lines with GLINE_EXACT; only set new lastmod when
+       activating/deactivating existing glines if old lastmod was not 0
+
+       * ircd/gline.c: forgot to copy the gline reason over; don't
+       propagate a gline with 0 lastmod if origin is user; add
+       GLINE_EXACT to force exact matching of gline mask
+
+       * ircd/ircd_snprintf.c (doprintf): forgot to deal with the zero
+       flag properly
+
+       * ircd/s_conf.c (find_kill): gline_find() takes a char *userhost,
+       but gline_lookup() actually takes a client--d'oh.
+
+2000-04-13  Thomas Helvey <tomh@inxpress.net>
+       * ircd/IPcheck.c: Back port BLMet's bugfix from 2.10.10
+
+2000-04-13  Greg Sikorski <gte@atomicrevs.demon.co.uk>
+
+       * ircd/whocmds.c: Don't make idle flag default in /who, to prevent:
+         "/who * x"
+         "Gte3 H*iwg Gte@212.49.240.217 :1 :0 I am the one that was."
+         (Found by Plexus).
+
+       * ircd/whocmds.c: Change idle time calc from socket idle to user
+         idle.
+
+2000-04-13  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * config/aclocal.m4 (unet_CHECK_TYPE_SIZES): check size of void *,
+       too, for ircd_snprintf.c
+
+       * include/ircd_snprintf.h: documentation for ircd_(v)snprintf, in
+       comments; mostly descended from the Linux manpage for printf, but
+       also documenting the extensions.
+
+       * ircd/ircd_snprintf.c: NULL dest is equivalent to going to a
+       client; make 'q' be the same as 'L'; remove __inline__; only
+       define EXTENSION if HAVE_LONG_LONG is defined
+
+       * include/handlers.h: declare m_gline()
+
+       * ircd/parse.c: gline can be called by users, but it only lists
+       the glines.
+
+       * ircd/s_user.c (set_nick_name): resend gline if a remote server
+       introduces a glined client
+
+       * ircd/s_serv.c (server_estab): burst glines, too
+
+       * ircd/gline.c: fix up all the expire times to be offsets;
+       simplify gline_resend()
+
+       * ircd/m_gline.c: begin coding replacements for ms_gline(),
+       mo_gline(), and m_gline()
+
+       * ircd/gline.c (gline_add): allow *@#channel to work correctly;
+       also, prohibit local BADCHANs if LOCAL_BADCHAN not defined
+
+2000-04-13  Greg Sikorski <gte@atomicrevs.demon.co.uk>
+
+       * tools/Bouncer/*: Add comments/documentation/tags.
+       * tools/Bouncer/*: Add debug defines, make task fork().
+
+2000-04-12  Thomas Helvey <tomh@inxpress.net>
+       * ircd/s_err.c: Cleanup s_err.c make one table so we
+       don't have to do anything tricky to get an error string.
+
+2000-04-12  Greg Sikorski <gte@atomicrevs.demon.co.uk>
+       * Add port bouncer for http (x/w)
+
+2000-04-12  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/s_conf.c (find_kill): replaced call to find_gline() with a
+       call to gline_find(); also used GlineReason() instead of direct
+       reference to structure member
+
+       * ircd/m_join.c (m_join): replace bad_channel() calls with calls
+       to gline_find(name, GLINE_BADCHAN), and also check to see if gline
+       is active
+
+       * ircd/channel.c: nothing seems to be called anywhere...
+
+       * ircd/s_err.c: update a couple of replies to dovetail with new
+       semantics
+
+       * ircd/gline.c: begin complete re-implementation of gline.c along
+       the lines of the final design of jupe.c
+
+       * include/gline.h: begin complete re-implementation of gline.c
+       along the lines of the final design of jupe.c
+
+       * ircd/channel.c (mode_process_clients): fix "Deop of +k user on
+       %s by %s" message...
+
+       * ircd/ircd_snprintf.c: my new snprintf()-like functions
+
+       * include/ircd_snprintf.h: my new snprintf()-like functions
+
+2000-04-11  Thomas Helvey <tomh@inxpress.net>
+       * ircd/IPcheck.c: removed old dead code
+       * ircd/s_user.c (send_user_info): removed non-standard
+          user not found message for userhost/userip
+
+2000-04-11  Greg Sikorski <gte@atomicrevs.demon.co.uk>
+
+       * ircd/s_err.c: Added missing quotes to ERR_DONTCHEAT numeric.
+       * doc/p10.html: Work on chapter 4.
+
+2000-04-10  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/channel.c (mode_parse_client): fix coredump on /mode
+       #foobar +o nosuchnick
+
+2000-04-10  Perry Lorier  <Isomer@coders.net>
+       * BUGS: Added bug.
+
+2000-04-09  Thomas Helvey <tomh@inxpress.net>
+       * include/IPcheck.h: fix prototype
+       * ircd/s_user.c: fix usage of IPcheck_remote_connect
+       * ircd/IPcheck.c: removed unused args
+
+2000-04-09  Thomas Helvey <tomh@inxpress.net>
+       * include/IPcheck.h: add proto for IPcheck_expire
+
+       * ircd/IPcheck.c: Rewrote
+
+       * ircd/ircd.c: Add IPcheck_expire to main message loop
+
+       * ircd/s_user.c: Redo target hashing, refactor target code
+
+       * include/numeric.h: Cleaned up numerics, added which ones are
+       in use by other networks and what they are in use for.
+
+       * ircd/channel.c: cleaned can_join(), allow anyone through anything
+       if /invited, simplified the function.  Opers overusing OPEROVERRIDE
+       will get a message explaining to them not to cheat.
+
+       * ircd/m_join.c: cleaned up the various join functions, should be
+       a lot more efficient.  Still needs work.  Now assumes that s<->s
+       won't send it a JOIN 0.  Service coders - note this and tread with
+       care.
+
+       * ircd/m_stats.c: added Gte-'s stats doc patch.
+
+       * ircd/m_version.c: /version now returns the 005 numeric as well.
+       as requested by Liandrin.
+
+
+2000-04-07  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/m_clearmode.c: add include for support.h for write_log()
+
+       * configure: move ircd/crypt/* to tools/*
+
+2000-04-06  Thomas Helvey <tomh@inxpress.net>
+       * ircd/s_auth.c: Shorten auth connect timeout to 60 seconds
+          set client host to server alias if connection from localhost
+
+2000-04-06  Perry Lorier <isomer@coders.net>
+       * ircd/ircd.c: Fix core during pinging (oops)
+       
+2000-04-06  Perry Lorier <isomer@coders.net>
+       * ircd/send.c: fixed wrong ident being sent to channels bug.
+       * include/numerics.h: Updated some of the numerics from other
+       networks.  Flagged some as 'unused' by undernet.
+
+2000-03-30  Perry Lorier <isomer@coders.net>
+       * ircd/ircd.c: Lets see if this helps the ping problem at all.
+       * ircd/whocmds.c, /doc/readme.who: Added %l specifier to get idle
+       time for local clients. (as requested), extended who now returns all
+       the flags (@+!) so you can tell the complete state of a client.
+
+2000-03-30  Thomas Helvey <tomh@inxpress.net>
+       * m_rping.c m_rpong.c: add Gte's rping/rpong fixes
+
+2000-03-30  Perry Lorier <isomer@coders.net>
+       * ircd/parse.c: oops, missed opers.
+
+2000-03-30  Perry Lorier <isomer@coders.net>
+       * ircd/parse.c: fixed mystifying ping bug thats been plaguing us
+       for so long.  Remember: m_ping MUST be in the parse array. :)
+
+2000-03-30  Perry Lorier <isomer@coders.net>
+       * ircd/ircd.c: test in check_pings was wrong.  I move that we
+       disallow cvs commit after 10pm localtime....
+
+2000-03-30  Perry Lorier <isomer@coders.net>
+       * ircd/m_pong.c: Fix it for servers too.
+
+2000-03-30  Perry Lorier <isomer@coders.net>
+       * ircd/m_pong.c: Fix ping timeout bugs
+
+2000-03-30  Perry Lorier <isomer@coders.net>
+       * ircd/channel.c: Bans had CurrentTime in their when field instead
+       of TStime()
+
+2000-03-31  Thomas Helvey <tomh@ixpress.net>
+       * ircd/numnicks.c (SetXYYCapacity): fix for extended
+       numerics.
+
+2000-03-30  Perry Lorier <isomer@coders.net>
+       * ircd/m_nick.c: send kills both ways so when we add nick change
+       on collision we don't desync the network.
+
+       * ircd/map.c: Fixup the map a bit more.
+
+2000-03-31  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/m_clearmode.c (do_clearmode): Log the CLEARMODE to OPATH
+
+       * ircd/m_opmode.c: Log the mode changes to OPATH
+
+       * ircd/channel.c (modebuf_flush_int): Log the mode changes to
+       OPATH
+
+       * include/channel.h (MODEBUF_DEST_LOG): Log the mode changes to
+       OPATH
+
+       * doc/Configure.help: help text for CONFIG_LOG_OPMODE / OPATH
+
+       * config/config-sh.in: added OPATH for opmode log file
+
+       * ircd/m_clearmode.c (do_clearmode): updated uses of
+       modebuf_mode_string() for the new usage
+
+       * ircd/channel.c: added flag MODE_FREE and an int argument to
+       modebuf_mode_string() to indicate that the string must be free'd;
+       updated calls to modebuf_mode_string() for the new usage; called
+       collapse(pretty_mask()) on the ban string and use allocated memory
+       for it; added ban list length accounting; fixed a number of small
+       bugs in ban processing
+
+       * include/channel.h: added flag MODE_FREE and an int argument to
+       modebuf_mode_string() to indicate that the string must be free'd
+
+       * ircd/m_clearmode.c (do_clearmode): made sure clearmode removed
+       keys and limits that are set
+
+2000-03-30  Perry Lorier <isomer@coders.net>
+       * ircd/ircd.c: rewrote check_pings() for maintainability
+       and speed.  Also changed quit msg's so they don't have
+       redundant nick[host] info in them.
+
+       * ircd/send.c: Changed write errors to report what error
+       occured (if possible).
+
+       * ircd/gline.c: added gline comment to the quit.
+
+       * ircd/m_server.c: Added suggestions to server quits mentioning
+       what went wrong so the admin can fix it earlier instead of asking
+       questions...
+
+       * ircd/map.c: Changed m_map() to hide numerics, show a * beside
+       servers that aren't fully burst yet.  And show '(--s)' for servers
+       where its not sure.
+
+       * doc/example.conf: Fixed wrapped U:
+
+2000-03-30  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/m_mode.c (ms_mode): implemented a new m_mode in terms of
+       mode_parse() (version selectable at compile time)
+
+       * ircd/m_clearmode.c (mo_clearmode): clean_channelname(parv[1])
+
+       * ircd/m_opmode.c (mo_opmode): clean_channelname(parv[1])
+
+       * config/config-sh.in: add new config option to enable new m_mode
+       implementation
+
+       * doc/Configure.help: add documentation for new config option
+       CONFIG_NEW_MODE
+
+       * ircd/channel.c (mode_parse_client): /opmode #foobar -o -- 461
+       MODE -v : Not enough parameters
+
+       * ircd/m_clearmode.c (do_clearmode): do_clearmode() would remove
+       +k and +l even if they weren't set...
+
+       * ircd/m_opmode.c: implement the OPMODE command using mode_parse()
+
+       * ircd/channel.c: make mode_process_clients() clear the DEOPPED
+       flag; fix +s+p exclusivity; add MODE_ADD/MODE_DEL to flag list
+       for; test the 0-th member, not the i-th member, of the client
+       change state stuff
+
+       * ircd/m_clearmode.c (do_clearmode): use the new
+       mode_invite_clear() function
+
+       * ircd/channel.c: cleared up all the compile-time warnings and
+       errors
+
+       * include/channel.h: added declarations for mode_ban_invalidate()
+       and mode_invite_clear()
+
+       * ircd/channel.c: finished mode_parse(), then broke it up into a
+       dozen or so helper functions to make the code easier to read
+
+2000-03-29  Thomas Helvey <tomh@inxpress.net>
+       * ircd/ircd.c: refactor server initialization a bit, use
+       getopt for parsing command line, refactor init_sys, main,
+       and other bits.
+
+       * ircd/s_bsd.c: add functions for initialization to clean
+       up logic a bit and remove duplicated code.
+
+       * include/ircd.h: add struct for server process related
+       variables.
+
+2000-03-29  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/channel.c: initial definition of mode_parse(); flags to
+       prevent doing the same thing multiple times; helper method
+       send_notoper() to send a "Not oper"/"Not on channel" notice
+
+       * include/channel.h: declare mode_parse() and helper flags
+
+       * ircd/channel.c (modebuf_flush_int): fiddled with timestamp
+       sending to match the current action of set_mode() closely enough
+       that hopefully there won't be major conflicts
+
+       * ircd/channel.c (modebuf_flush_int): consolidated the mode string
+       building logic, reversed the order of the arguments to mode
+       commands to have '-' preceed '+'
+
+2000-03-29  Thomas Helvey <tomh@inxpress.net>
+       * ircd/s_bsd.c (add_connection): don't disable socket options
+       let OS tune itself and allow important performance tweaks to 
+       work.
+
+2000-03-28  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/channel.c (modebuf_flush_int): use %d, not %-15d; I got
+       confused by set_mode, which is doing some really weird logic;
+       guess what I'm going to rewrite next?  ;)
+
+2000-03-28  Kevin L. Mitchell  <klmitch@emc.com>
+
+       * include/channel.h: added MODE_SAVE for the bounds checking stuff
+       in modebuf_flush
+
+       * ircd/channel.c: make modebuf_flush into modebuf_flush_int and
+       make it do bounds checking on the buffer; all modes are sent only
+       if the all parameter is 1; modebuf_flush is the exported wrapper
+
+       * include/channel.h: add BOUNCE, renumber flags to get a little
+       more space
+
+       * ircd/channel.c (modebuf_flush): don't overload HACK2, add
+       BOUNCE; send DESYNCH message
+
+2000-03-27  Kevin L. Mitchell  <klmitch@emc.com>
+
+       * ircd/m_clearmode.c (do_clearmode): only mark the modes the
+       channel actually has in effect for deletion
+
+       * ircd/channel.c: added explanatory comments to all added
+       functions; made flushing take place at the correct place even if
+       the MODEBUF_DEST_DEOP flag is set; rewrote build_string() helper
+       to bash some stupid bugs; made modebuf_flush() return if ModeBuf
+       is empty, fixed the apparent source, removed some bogus string
+       termination code, properly terminate the mode strings, add support
+       for HACK2 and HACK3, made limit strings not be sent if the limit
+       is being removed, changed where '+' and '-' come from in sent
+       strings, added support for DEOP flag, set up bouncing code for
+       HACK2
+
+       * ircd/Makefile.in: ran make depend
+
+       * include/channel.h: added new defines for future functionality,
+       made modebuf_flush() return int so I can use tail recursion
+
+       * ircd/m_clearmode.c: add msg.h to includes; other misc cleanups
+       to make it all compile
+
+       * ircd/m_opmode.c: add msg.h to includes...
+
+       * ircd/m_clearmode.c: implemented mo_clearchan()/ms_clearchan()
+
+       * ircd/channel.c (modebuf_flush): realized I forgot to
+       nul-terminate addbuf/rembuf properly...
+
+       * ircd/m_clearmode.c (do_clearmode): wrote do_clearmode()...
+
+       * ircd/channel.c (modebuf_flush): correct sendto_server_butone to
+       sendto_serv_butone--blah^2
+
+       * ircd/send.c (sendto_serv_butone): stupid comments confused me
+
+       * ircd/channel.c (modebuf_flush): if there are no mode changes to
+       propagate, we're done...
+
+       * ircd/channel.c (modebuf_flush): duh; it's sendto_server_butone,
+       not sendto_all_butone
+
+       * ircd/m_clearmode.c: define skeleton for m{o,s}_clearmode
+
+       * ircd/m_opmode.c: define skeleton for m{o,s}_opmode
+
+       * ircd/Makefile.in (SRC): added m_opmode() and m_clearmode() to
+       the list
+
+       * ircd/parse.c: added messages for opmode and clearmode
+
+       * include/handlers.h: added declarations for mo_opmode(),
+       ms_opmode(), mo_clearmode(), and ms_clearmode()
+
+       * include/msg.h: define MSG_OPMODE, TOK_OPMODE, MSG_CLEARMODE, and
+       TOK_CLEARMODE
+
+       * include/channel.h (MODEBUF_DEST_OPMODE): Define the
+       MODEBUF_DEST_OPMODE flag
+
+       * ircd/channel.c (modebuf_flush): added new flag,
+       MODEBUF_DEST_OPMODE; causes channel MODE/HACK(4) notice to appear
+       to originate from source's server (or source itself, if
+       IsServer(source)); also causes a server-level MODE to be sent as
+       OPMODE instead
+
+       * include/channel.h: defined MODEBUF_DEST_SERVER,
+       MODEBUF_DEST_HACK4
+
+       * ircd/channel.c: Add another argument to build_string() to handle
+       numeric nicks; implemented MODEBUF_DEST_SERVER to send MODEs to
+       servers; implemented MODEBUF_DEST_HACK4 to cause HACK(4) notices
+       to be sent out
+
+2000-03-27  Perry Lorier <isomer@coders.net>
+
+       * ircd/s_bsd.c: fixed missing 'u' typo.
+
+2000-03-26  Kevin L. Mitchell  <klmitch@emc.com>
+
+       * ircd/channel.c: implement modebuf_init(), _mode(), _mode_uint(),
+       _mode_string(), _mode_client(), _flush(); also implemented a
+       simple build_string()
+
+       * include/channel.h: added definition of ModeBuf, modebuf_*
+       manipulation functions, and a couple of helper macros
+
+2000-03-24 Thomas Helvey <tomh@inxpress.net>
+  * numicks.c: convert extended numerics to use original mask version
+  * numnicks.h: ""
+  * s_user.c:
+2000-03-23 Thomas Helvey <tomh@inxpress.net>
+  * Merge in changes from production
+2000-03-22 Thomas Helvey <tomh@inxpress.net>
+  * numicks.c: Tweak to numnick generator to reduce possibility of duplicates.
+  * rfc1459.unet: Add Maniac's documentation for /names 0
+* Fix misc. jupe bugs that somehow made it into the tree
+* Escape /names 0 to mean /names --Maniac
+* Don't core when server asks for info --Maniac 
+* Add Kev's jupe patch --Bleep
+* Add Maniacs squit patch --Bleep
+* Merge in u2_10_10_beta07 changes --Bleep
+* Merge in u2_10_10_beta06 changes --Bleep
+* Start ircu2.10.11 development, beta branch u2_10_10 --Bleep
+#-----------------------------------------------------------------------------
diff --git a/doc/history/ChangeLog.12 b/doc/history/ChangeLog.12
new file mode 100644 (file)
index 0000000..734e05f
--- /dev/null
@@ -0,0 +1,11526 @@
+2009-07-30  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/s_user.c (register_user): Move the default-usermodes call
+       to set_user_mode() to before SetUser(), so that the former does
+       not increment the UserStats fields.  Add back the explicit
+       adjustments to UserStats for invisible and opered clients.
+
+2009-07-05  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/s_user.c (register_user): Use correct parc for
+       set_user_mode().  Do not increment UserStats fields here, because
+       set_user_mode() handles that.
+
+2009-07-05  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/m_gline.c (ms_gline): Fix the sense of the test for
+       strtoul() when parsing G-line lifetimes -- zero indicates failure.
+
+2009-07-05  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/channel.c (mode_parse_client): Ignore anything after a
+       colon when the mode is CHFL_VOICE or the mode is being removed.
+
+2009-07-04  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/s_auth.c (find_conf_client): New function.
+       (preregister_user): Use it to avoid assigning a second conf class
+       on client connection.
+       (auth_ping_timeout): Send the "T" message only if we do not kill
+       the client (and thus send a "D" message).
+       (auth_find_classs_conf): Do not allow IAuth to select a disabled
+       class.  Unlink new conf items from GlobalConfList.
+       (iauth_cmd_done_client): Handle failures from attach_conf().
+       (iauth_parse): Behave decently when a client is killed by the
+       message handler.
+
+       * tools/iauth-test (%handlers): Add entries to help test this.
+
+2009-07-04  Michael Poole <mdpoole@troilus.org>
+
+       * include/channel.h (RevealDelayedJoinIfNeeded): Declare.
+
+       * ircd/channel.c (RevealDelayedJoinIfNeeded): Implement.
+
+       * ircd/ircd_relay.c (relay_channel_message): Only reveal the user
+       if he passes the check_target_limit() test.
+       (relay_channel_notice): Likewise.
+
+       * ircd/m_wallchops.c (m_wallchops): Likewise.
+
+       * ircd/m_wallvoices.c (m_wallvoices): Likewise.
+
+       * ircd/s_user.c (check_target_limit): Micro-optimize to only check
+       the user's channel list for invites if we are about to deny it.
+
+2009-03-25  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/ircd.c (main): Unconditionally set +6 flag on self.
+
+2009-03-25  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/s_auth.c (iauth_cmd_hostname): Properly assign the spoofed
+       hostname (yea, even as the "real" host) in the hurry state.
+
+       * tools/iauth-test: Add reminder about perl's RTMIN signal and a
+       new handler to exercise the N command in the hurry state.
+
+2009-03-25  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/channel.c (mode_parse): Add Doxygen comment.  When bouncing
+       a mode from a desynced U-lined server, do not set the modes or
+       send the change as a HACK(4) message.
+
+2009-03-17  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/send.c (sendcmdto_match_butone): Move match_it() to the end
+       of the if() to minimize the number of expensive function calls.
+
+2009-03-17  Michael Poole <mdpoole@troilus.org>
+
+       * patches/diffs/antispambot.diff: Forward port a patch by Dianora
+       to add rudimentary spam bot detection to ircu.
+
+2009-02-08  Michael Poole <mdpoole@troilus.org>
+
+       * include/client.h (ClearHub): New macro.
+
+       * ircd/ircd.c (main): Set IPv6 flag on &me if appropriate.
+
+       * ircd/ircd_features.c (feature_notify_hub): New function.
+       (features[]): Register it for FEAT_HUB.
+
+       * ircd/ircd_parser.y (connectblock): Do not default maxlinks to
+       65535 unless "hub" is specified.
+       (clientblock): Reset maxlinks on cleanup.
+
+2009-02-08  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/channel.c (clean_channelname): Delete this function; it is
+       no longer used, and had the same length-off-by-one bug.
+
+       * ircd/m_join.c (m_join): Use > instead of >= with CHANNELLEN.
+
+       * tests/ircd.conf: Set CHANNELLEN to make it easier to test this.
+
+       * tests/bug-2328334.cmd: New file for regression testing.
+
+2009-02-08  Michael Poole <mdpoole@troilus.org>
+
+       * include/numeric.h (ERR_INVALIDKEY): Define new numeric.
+
+       * ircd/s_err.c (ERR_INVALIDKEY): Give it a text string.
+
+       * ircd/channel.c (is_clean_key): Rename from clean_key(), and make
+       this function responsible for sending error messages to the client
+       when necessary.
+       (mode_parse_key): Update to match the new is_clean_key() behavior.
+       (mode_parse_upass): Likewise.
+       (mode_parse_apass): Likewise.
+
+       * tests/channel-keys.cmd: New file for regression testing.
+
+2009-02-08  Michael Poole <mdpoole@troilus.org>
+
+       * include/gline.h (gline_forward_deactivation): Undeclare.
+
+       * ircd/m_gline.c (mo_gline): Remove the special case to call
+       gline_forward_deactivation().
+
+       * ircd/gline.c (gline_add): Mention if the new G-line is already
+       deactivated.
+       (gline_forward_deactivation): Delete implementation.
+
+       * tests/glines.cmd: Update the expected output to match.
+
+2009-01-12  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/m_topic.c (do_settopic): Just before sending the topic out,
+       check to see if the user is join-delayed and should be shown.
+
+       * ircd/m_wallchops.c (m_wallchops): Allow this command to expose
+       join-delayed users.
+       (ms_wallchops): Likewise.
+
+       * ircd/m_wallvoices.c (m_wallvoices): Allow this command to expose
+       join-delayed users.
+       (ms_wallvoices): Likewise.
+
+2009-01-12  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/channel.c (modebuf_mode_uint): Fix bouncing of limit changes.
+
+2009-01-12  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/gline.c (count_users): Accept "flags" mask to limit count
+       to local users.
+       (gline_add): Pass the flags to count_users().
+
+2009-01-12  Michael Poole <mdpoole@troilus.org>
+
+       * include/gline.h (gline_forward_deactivation): Declare.
+
+       * ircd/gline.c (count_users): Use ipmask-based checks too.
+       (gline_add): Require flags to have exactly one of the GLINE_GLOBAL
+       and GLINE_LOCAL bits set.
+       (gline_forward_deactivation): Implement new function.
+       (gline_find): Only require the GLINE_LOCAL flag to be set in the
+       gline structure; infer GLINE_GLOBAL when it is cleared.  (This
+       matches the value and usage of GLINE_MASK.)
+
+       * ircd/m_gline.c (ms_gline): Default lastmod to the known lastmod
+       time for GLINE_LOCAL_{DE,}ACTIVATE.
+       (mo_gline): Check that expiration times parse as expected.  Reject
+       "*" as a target for GLINE_LOCAL_{DE,}ACTIVATE.  Require reason and
+       expiration time for new G-lines.  Allow deactivation of an unknown
+       G-line without creating it ("so-and-so ... creating new G-line" is
+       a confusing message for a deactivation).
+
+       * tests/glines.cmd: New test script for G-line parsing tests.
+
+       * tests/ircd.conf: Enable CONFIG_OPERCMDS for glines.cmd.
+
+       * tests/ircd-2.conf: Likewise.
+
+       * tests/readme.txt: Add section on command syntax.
+
+       * tests/test-driver.pl: Report line numbers more clearly.
+       Fix (somewhat kludgily) the brokenness of consecutive "expect"
+       lines, as demonstrated by the numeric 219 and 281 expects in
+       glines.cmd.
+
+2008-11-17  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/m_kick.c (ms_kick): Properly handle crossing net rider and
+       normal KICKs (in the case where we get the normal kick first).
+
+2008-11-17  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/match.c (match): Fix an error in backtracking (apparently
+       exacerbated by escapes).
+
+       * ircd/test/ircd_match_t.c: Update headers and make sure we have a
+       mmap() anonymous request flag.
+       (test_match): New function.
+       (do_match_test): Use it instead of calling match() directly.
+
+2008-09-07  Perry Lorier <isomer@undernet.org>
+       
+       * ircd/m_kill.c: Remove the . from the end of the nickname in kill
+       messages to make cut and pasting easier.
+
+2008-03-20  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/ircd_string.c (ircd_aton_ip4): Reject strings with more
+       than 3 dots in them.
+
+       * ircd/test/ircd_in_addr_t.c (test_addrs): Update the expected
+       parsing for a bare IPv4 address to a IPv4-mapped address.
+       (test_masks): Add a test for the ircd_string.c change.
+
+2008-03-20  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * include/client.h: IsLocOp() now checks to see if its MyUser() as
+       well; IsAnOper() uses IsOper() and IsLocOp() instead of directly
+       testing the flags
+
+2008-03-15  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/s_bsd.c (init_connection_limits): Remove errant apostrophe.
+       Print text error message when unable to set max FDs.
+
+2008-03-15  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/s_user.c (set_user_mode): Check for end of argument list
+       when processing 'r' modes.
+
+2008-01-09  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * include/patchlevel.h (PATCHLEVEL): bump patchlevel
+
+2008-01-02  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/m_burst.c (ms_burst): surround protocol_violation() and
+       break in braces to do what Jan Krueger was trying to do...
+
+2008-01-03  Jan Krueger  <jast@heapsort.de>
+
+       * ircd/m_burst.c: prevent leaking the next nick into the current one's
+       oplevel. Add protocol_violation when an invalid nick flag appears.
+
+2007-12-28  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/channel.c: add MODE_REGISTERED, mapped to +R; arrange to
+       only have it settable or clearable by remote users or /opmode
+
+       * include/supported.h (FEATURESVALUES2): update to include 'R'
+       channel mode
+
+       * include/channel.h: add MODE_REGISTERED, update infochanmodes to
+       include 'R' channel mode
+
+2007-12-13  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/m_gline.c (ms_gline): if we got an activate or deactivate
+       for a global G-line we never heard of, and we cannot create it
+       because no expire time was sent, manually propagate the G-line
+       instead of trying to call gline_add()
+
+       * ircd/gline.c (make_gline): never allow a G-line to be created
+       with a 0 expire time
+
+2007-12-03  Michael Poole <mdpoole@troilus.org>
+
+       * include/patchlevel.h (PATCHLEVEL): Bump for u2.10.12.12 release.
+
+2007-12-03  Michael Poole <mdpoole@troilus.org>
+
+       * doc/Makefile.in (DATAROOTDIR): Define.
+       (DATADIR): Likewise.
+       
+2007-11-30  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/version.c.SH: correct invalid syntax in shell case/esac
+
+       * ircd/ircd_lexer.l: provide an implementation of yywrap() so we
+       no longer have to link against -lfl
+
+       * configure.in: drop tests on LEXLIB and don't add it to the list
+       of libs
+
+       * ircd/gline.c (gline_add): apply too-many-users test to realname
+       G-lines *only* when the origin is my user (or a user, for
+       remote-local G-lines)
+
+2007-11-28  Michael Poole <mdpoole@troilus.org>
+
+       * include/patchlevel.h (PATCHLEVEL): Bump for pre12 development.
+
+2007-11-28  Michael Poole <mdpoole@troilus.org>
+
+       * include/patchlevel.h (PATCHLEVEL): Bump for u2.10.12.11 release.
+
+2007-11-28  Michael Poole <mdpoole@troilus.org>
+
+       * tests/test-driver.pl (drv_default): Fix expect for numeric
+       responses that have non-trivial parameters.
+       (check_expect): Simplify (and fix) sender name check.
+
+       * tests/bug-1640796.cmd: Update expect NNN for new POE behavior
+       and part to not try to part the channel named "leaving".
+
+       * tests/bug-1674539.cmd: Update expect NNN for new POE behavior.
+
+       * tests/bug-1840011.cmd: New test script.
+       
+2007-11-28  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/channel.c (mode_ban_invalidate): Clarify Doxygen comments.
+       (apply_ban): Only block narrower bans if the wider ban is active.
+
+2007-11-24  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/m_names.c (do_names): Don't try to re-initialize the start
+       of buf[] for each line.  It's done the first time around and that
+       can be reused safely.
+
+2007-11-17  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/m_stats.c (m_stats): Properly assign param before it is
+       used in the hunt_server_cmd() call.
+       
+2007-11-17  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/s_auth.c (iauth_disconnect): Avoid destroying invalid
+       sockets.
+       (iauth_stderr_callback): Disconnect iauth child if stderr has
+       EOF (in case stdin notification is delayed somehow).
+       
+2007-11-04  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/umkpasswd.c (sum): Typecast buffer to avoid a warning about
+       the parameter type being passed to strlen().
+       
+2007-11-04  Michael Poole <mdpoole@troilus.org>
+
+       * doc/example.conf: Document /LIST M as controlled by list_chan.
+
+       * include/channel.h (LISTARG_SHOWMODES): Define.
+
+       * ircd/hash.c (list_next_channels): Handle it.
+
+       * ircd/m_list.c (show_usage): Document 'M' flag.
+       (param_parse): Recognize 'M' as LISTARGS_SHOWMODES.
+
+2007-11-04  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/m_list.c (param_parse): Reverse comparison direction when
+       converting from minutes to time_t, and which bound is set (so that
+       T<time_t works correctly).  Also switch is_time cases so that 'T'
+       and 'C' work as documented.  Remove a "break" after a "return".
+
+       (m_list): Remove a "break" after a "return".
+
+2007-10-29  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/ircd_lexer.l (YY_INPUT): Redefine to use fbgets().
+       (init_lexer): Return a value to indicate failure.  Use fbopen().
+       (deinit_lexer): New function.
+
+       * ircd/s_conf.c (read_configuration_file): Update extern
+       declarations.  Bail if init_lexer() fails.  Call deinit_lexer()
+       rather than directly munging yyin.
+
+2007-10-29  Michael Poole <mdpoole@troilus.org>
+
+       * include/gline.h: Delete declaration of gline_propagate().
+
+       * include/whocmds.h: Delete declaration of count_users().
+
+       * ircd/whocmds.c (count_users): Move to gline.c as a static.
+
+       * ircd/gline.c (whocmds.h): Remove #include.
+       (gliter): Document boolean trickiness.  Add missing trickiness
+       when gl_flags has bits set besides GLINE_ACTIVE.
+       (make_gline): Get rid of now-unused "after" variable and the
+       comments related to overlapping G-lines.
+       (gline_propagate): Make static.
+       (count_users): Move from whocmds.c as a static function.
+       (count_realnames): New function.
+       (gline_add): Require a force to hit lots of users with a realname
+       G-line.
+
+2007-09-05  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/m_gline.c (ms_gline): Remove dead branch when 4 < parc < 5.
+       (mo_gline): Consistently use the last argument as the reason.
+
+2007-09-05  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/Makefile.in: Fix dependencies for version.h generation.
+
+2007-08-20  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/send.c (sendwallto_group_butone): Move a feature_bool()
+       call out of a loop.  Convert HasFlag() uses to appropriate macros
+       from client.h.
+
+2007-08-20  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/ircd_string.c (ircd_aton_ip4): Allow a sequence of *.* at
+       the end of an IPv4 mask.
+       (ipmask_parse): Likewise for *:* at the end of IPv6 masks.
+
+       * ircd/test/ircd_in_addr_t.c (test_masks): Add tests for this.
+
+2007-08-20  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/s_user.c (register_user): Update inv_clients and opers
+       counts.  Call client_set_privs() for local users.
+       (set_nick_name): Do not call client_set_privs() for remote users.
+       (set_user_mode): Move oper and invisible client checks inside the
+       IsRegistered() section.
+
+2007-08-14  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/channel.c (DONE_*): Split key changes into _ADD and _DEL.
+       (mode_parse_key): Check both, to properly handle -k+k changes.
+       (mode_parse_upass): Likewise, for -U+U.
+       (mode_parse_apass): Liekwise, for -A+A (in case that ever happens).
+       (mode_parse): Update which "done" flag is checked during a wipeout.
+
+2007-08-13  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/s_user.c (whipser): CNOTICEs should not trigger away
+       messages, only CPRIVMSGs.
+
+2007-08-13  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/m_who.c (m_who): Reorder responses and change the
+       ERR_QUERYTOOLONG parameter to be consistent with m_whois().
+       
+2007-08-13  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/s_user.c (register_user): Initialize umodev[] in a
+       C89-compatible way.  (gcc 4.1.2 warned about it.)
+
+2007-08-13  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/m_names.c (do_names): Add NAMES_DEL to comment.  Avoid use
+       of strcat().  Get rid of ms_names(), which was basically a copy of
+       m_names(), and merge the "showingdelayed" changes into m_names().
+       Replace the recursion with iteration.
+
+       * ircd/parse.c (msgtab): Use m_names(), not ms_names().
+
+2007-08-08  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/s_auth.c (report_iauth_conf): Remove end-of-stats message;
+       m_stats() already does that.
+
+       (report_iauth_stats): Likewise.
+
+2007-08-08  Michael Poole <mdpoole@troilus.org>
+
+       * include/res.h (irc_in_addr_is_ipv4): Fix classification of
+       addresses like 0.0.0.0.
+
+2007-07-21  Perry Lorier <isomer@undernet.org>
+
+       * ircd/s_user.c: Move set_nick_name() to use set_user_mode(),
+       set_user_mode() now interprets +r usermodes properly (and ignores
+       them from non servers).  This fixes a problem where remote users
+       weren't being counted properly anymore.
+
+2007-07-20  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/m_gline.c: create abs_expire() macro to convert an expire
+       timestamp from the network into an absolute time, if needed;
+       rename expire_off to expire globally, since it now represents an
+       absolute expiration time; use expire - CurrentTime in gline
+       forwarding statements; in ms_gline(), use abs_expire() to convert
+       network expiration timestamp into absolute timestamp; in
+       mo_gline(), add CurrentTime to oper-provided expiration offset to
+       convert to absolute timestamp
+
+       * ircd/gline.c: assume expire and lifetime arguments to
+       gline_add() and gline_modify() are already absolute timestamps;
+       send lifetime parameter as an absolute timestamp, but leave expire
+       timestamp as relative as first part of a 2-phase update
+
+2007-07-12  Perry Lorier <isomer@undernet.org>
+       Reconsider how we manage modes before registration, to avoid stats
+       getting out of sync.
+
+       * ircd/s_user.c (set_user_mode): Add new parameter to set_user_mode to
+       ignore some modes.
+       (register_user): Use set_user_mode to parse default usermode for
+       users.
+
+       * ircd/m_user.c: Add extra parameter to set_user_mode call
+
+       * ircd/s_auth.c: Add extra parameter to set_user_mode call
+
+       * ircd/m_mode.c: Add extra parameter to set_user_mode call
+
+       * ircd/s_misc.c: Verify stats are consistant.
+
+       * include/s_user.h: Change prototype, add flag definitions.
+
+       * ircd/m_lusers.c (m_users): Assert that we're generating sane stats,
+       include "unknowns" in the total user connections to avoid negative
+       wrap arounds.
+
+2007-07-12  Perry Lorier <isomer@undernet.org>
+       
+       * ircd/m_user.c (m_luser): Fix broken RFC 2812 on connect user mode 
+       setting
+
+2007-05-28  Michael Poole <mdpoole@troilus.org>
+
+       * include/numeric.h (ERR_INPUTTOOLONG): New numeric.
+
+       * ircd/s_bsd.c (read_packet): Use it.
+
+       * ircd/s_err.c (replyTable): Give it a format string.
+
+2007-05-20  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/m_burst.c (ms_burst): Do not let bursting servers join a
+       user to a channel more than once.
+
+2007-05-20  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/ircd_features.c (feature_set): Report new value of feature
+       for /set.
+       (feature_reset): Likewise, for /reset.
+
+2007-05-20  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/m_burst.c (netride_modes): Return -1 if someone tries to
+       remove modes in the burst.
+       (ms_burst): Check for, and handle, that protocol violation.
+
+2007-05-20  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/m_privs.c (mo_privs): Report "no such nickname" for unknown
+       nicks in the list.  (Unfortunately, the nick is lost before ms_privs.)
+
+2007-05-20  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/listener.c (show_ports): Actually hide hidden ports from
+       clients that should not see them.
+
+2007-05-20  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/s_err.c (ERR_DONTCHEAT): Add apparently missing %s.
+       
+2007-05-20  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/m_connect.c (mo_connect): Return an error to a locop who
+       tries to do a remote connect.
+
+2007-05-20  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/parse.c (msgtab): Make SETTIME consistent with other
+       oper commands, in using m_not_oper for non-opered clients.
+
+2007-05-20  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/ircd_parser.y (pseudoblock): Forbid pseudo commands that
+       are not all alphabetic characters.
+
+2007-05-20  Michael Poole <mdpoole@troilus.org>
+
+       * configure.in (maxcon): Check that maximum connections is
+       sufficiently large to avoid underflow in MAXCLIENTS.
+       
+2007-05-20  Michael Poole <mdpoole@troilus.org>
+
+       * include/supported.h (FEATURES2): Remove extra space.
+
+       * ircd/m_admin.c (m_admin): Only check server mask against our
+       name, so that it cannot leak information about other linked
+       servers.
+
+       * ircd/m_version.c (m_version): Likewise.
+       
+2007-04-15  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/m_gline.c: fix minor typo in code that forwards remote
+       local activations/deactivations: %c takes characters, not
+       pointers!
+       (mo_gline): fix similar typo in code forwarding remote local
+       G-lines by opers
+
+2007-04-10  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/ircd_parser.y (iauth): Avoid problems related to MyFree's
+       multiple evaluation of its argument.
+
+2007-04-10  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/m_gline.c (ms_gline): lastmod must be non-zero
+
+2007-04-04  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/s_conf.c (rehash): Restart resolver after reading the
+       config file; this un-breaks the resolver after /rehash if the
+       ircd.conf contains no "dns server = <ipstring>;" lines.
+
+2007-04-01  J. R. Lenz <ralf@starshadow.com>
+
+       * ircd/s_user.c (register_user): Check for host-hiding when fully
+       registering a user.  [Comment added by Entrope.]
+
+2007-03-31  Michael Poole <mdpoole@troilus.org>
+
+       * doc/readme.iauth (IAuth M): Document new command.
+
+       * ircd/m_user.c (m_user): Recognize RFC 2812 mode request and a
+       saner usermode request.
+
+       * ircd/s_auth.c (iauth_cmd_usermode): New command.
+       (iauth_parse): Dispatch to it.
+
+       * ircd/s_user.c (set_user_mode): Only broadcast usermode changes
+       for registered clients.
+
+       * tools/iauth-test (127.0.1.3): Test the new M command.
+
+2007-03-31  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/m_mode.c (m_mode): Check and report target/source
+       violations before calling set_user_mode().
+       (ms_mode): Likewise.
+
+       * ircd/s_user.c (set_user_mode): Remove those checks from here.
+
+2007-03-31  Michael Poole <mdpoole@troilus.org>
+
+       * include/ircd_events.h (struct Generators): Convert elements to
+       be struct GenHeader*.
+       (timer_next): Update to match.
+
+       * ircd/ircd_events.c (timer_enqueue): Update to match.
+       (signal_callback): Likewise.
+       (timer_init): Remove a typecast with something slightly safer.
+       (timer_run): Update to deal with new type of Generator.g_timer.
+       (signal_add): Likewise.
+       (socket_add): Likewise.
+       
+2007-03-28  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/m_asll.c (ms_asll): Count hits and report at the end, so
+       that a client is told whether any match (and has a hint that only
+       directly linked servers are checked).
+       (mo_asll): Likewise.
+
+2007-03-26  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/s_stats.c (m_stats): Move check for STAT_FLAG_LOCONLY (and
+       the assignment to "param") to the hunted server.
+
+2007-03-26  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/s_auth.c (iauth_parse): Check for missing arguments when
+       parsing the iauth message.
+
+       * tests/bug-1685648.cmd: New file to test this.
+
+       * tests/iauth-test: New file to exercise the code path.
+
+       * tests/ircd.conf: Use the iauth-test helper program.
+
+2007-03-26  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/m_silence.c (forward_silences): Do not try twice to process
+       silences that were both added and deleted.
+
+2007-03-26  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/ircd_parser.y (portblock): Restore old behavior for Port
+       blocks with no host listed.
+
+2007-03-26  Michael Poole <mdpoole@troilus.org>
+
+       * doc/readme.iauth (iauth I): Fix example and syntax.
+
+2007-03-18  Michael Poole <mdpoole@troilus.org>
+
+       * acinclude.m4 (unet_NONBLOCKING): Properly quote function name.
+       (unet_SIGNALS): Likewise.
+       (unet_CHECK_TYPE_SIZES): Likewise.
+       (AC_LIBRARY_NET): Likewise.
+
+2007-03-18  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/m_gline.c (mo_gline): add permissions checks I kept
+       forgetting to add--remote local modifications require
+       FEAT_CONFIG_OPERCMDS and PRIV_GLINE, local G-lines require
+       PRIV_LOCAL_GLINE, and global G-line changes (excluding local
+       activation/deactivation) require FEAT_CONFIG_OPERCMDS and
+       PRIV_GLINE
+
+2007-03-17  Michael Poole <mdpoole@troilus.org>
+
+       * doc/example.conf (CRule): Document the support for multiple
+       server masks in a single CRule block.
+       (Port): Document the optional additional field for vhost entries.
+       Document the support for multiple vhost entries in a single Port
+       block.
+
+       * ircd/ircd_parser.y (USE_IPV4): Shift up by 16 bytes.
+       (USE_IPV6): Likewise.
+       (portblock): Iterate over hosts rather than using the single host.
+       (portitem): Add portvhostnumber alternative production.
+       (portnumber): Check port number here.  If valid, combine address
+       family and port number in "port" variable.  If a port-less item
+       exists in "hosts", set its port number.
+       (portvhost): Prepend mask to "hosts" list.
+       (portvhostnumber): New production.
+       (cruleblock): Iterate over hosts rather than using the single
+       host.
+       (cruleserver): Prepend server mask to "hosts" list.
+
+2007-03-17  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/listener.c (add_listener): Only try to create IPv6 sockets
+       for IPv6-compatible addresses; likewise for IPv4.
+
+2007-03-17  Michael Poole <mdpoole@troilus.org>
+
+       * doc/example.conf (Operator): Update documentation to mention
+       more than one host entry is allowed.
+       (Motd): Likewise.
+
+       * ircd/ircd_parser.y (hosts): New file-scope variable.
+       (free_slist): New helper function.
+       (operblock): Iterate over hosts instead of using the single host.
+       (operhost): Prepend the mask to hosts.
+       (motdblock): Iterate over hosts instead of using the single host.
+       (motdhost): Prepend the mask to hosts.
+       (motdfile): Fix possible leak of "pass" string (the filename).
+
+       * ircd/s_conf.c (conf_parse_userhost): Stop freeing the host
+       string; operblock (the only caller) frees it now.
+
+2007-03-17  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/list.c (free_link): Only decrement the in-use count of
+       links if we free a link.
+
+2007-03-17  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/s_err.c: update replies to handle new fields in
+       RPL_STATSGLINE and RPL_GLIST--new fields indicate G-line lastmod,
+       G-line lifetime, and local activation status
+
+       * ircd/m_gline.c: update function documentation for ms_gline();
+       move test for server to before mask processing; don't look up
+       remote server too early; add code to process local activations and
+       deactivations early in ms_gline(); implement adding and destroying
+       local G-lines; don't try to locally activate or deactivate G-lines
+       that don't exist; add code to keep track of which fields were
+       available to ms_gline(); implement G-line modification and
+       creation; remove old ms_gline() code; convert
+       sendwallto_group_butone() calls to Debug() calls; reimplement
+       mo_gline() to take into account new syntax
+
+       * ircd/gline.c: change gl_rexpire to gl_lifetime to better reflect
+       its meaning; make sure to set gl_state to GLOCAL_GLOBAL when
+       G-line expires; add lifetime parameter to make_gline(); disable
+       overlapping G-line check; initialize gl_lifetime from lifetime
+       parameter; initialize gl_state to GLOCAL_GLOBAL; update
+       gline_propagate() to send lifetime parameter; add lifetime
+       parameter to gline_add(); remove some old code in gline_add();
+       figure out lifetime to set on new G-line; remove test for
+       make_gline() returning NULL, since it should never do so now; add
+       modify_gline() for modifying global G-lines; add gline_destroy()
+       for destroying local G-lines; update gline_burst() to send
+       lifetime parameter; update gline_resend() to send lifetime
+       parameter; update gline_list() to add lastmod, lifetime, and local
+       status indicators; update gline_stats() to send lastmod, lifetime,
+       and local status indicators; count BADCHANs in
+       gline_memory_count()
+
+       * include/gline.h: add enum GlineLocalState for keeping track of
+       local state changes to global G-lines; store state in struct
+       Gline; document enum GlineAction; add GLINE_EXPIRE,
+       GLINE_LIFETIME, and GLINE_REASON flags to indicate the presence of
+       those fields to gline_modify(); add GLINE_UPDATE mask for checking
+       for the above flags; update GlineIsActive() to take into account
+       new gl_state field in struct Gline; add lifetime to gline_add();
+       add gline_modify() for modifying existing global G-lines, and
+       gline_destroy() for destroying local G-lines
+
+       * doc/readme.gline: update documentation to reflect changes made
+       to G-line command syntax
+
+2007-03-17  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/umkpasswd.c (parse_arguments): Exit cleanly rather than
+       aborting on unrecognized arguments.  It isn't nice to core on
+       "umkpasswd --help"..
+
+2007-03-16  Michael Poole <mdpoole@troilus.org>
+
+       * doc/example.conf (Class): Move the "Recommended client classes"
+       comment to a better place (and stop recommending them).  Clarify
+       what maxlinks does.  Make it clear that Operator password entries
+       only support umkpasswd formats.
+       
+2007-03-16  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/ircd.c (parse_command_line): Emit a warning if using -x
+       when DEBUGMODE is disabled.
+
+2007-03-16  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/s_conf.c (find_conf_exact): Treat maxlinks == 0 as being
+       unlimited here, to match attach_conf()'s behavior.
+
+2007-03-16  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/s_conf.c (find_kill): check FEAT_DISABLE_GLINES prior to
+       checking for a G-line matching a new user
+
+       * ircd/m_gline.c (ms_gline): rework ms_gline() to handle new
+       command syntax--although it can parse the new syntax, it doesn't
+       yet perform the actions demanded by that syntax
+
+       * ircd/ircd_features.c: trap-door feature FEAT_DISABLE_GLINES to
+       disable G-lines
+
+       * ircd/gline.c: create gliter() macro which performs an iteration
+       over all G-lines in a specified G-line list; initialize record
+       expire in make_gline() (to be redone); check FEAT_DISABLE_GLINES
+       in do_gline(); add and document what happens if GLINE_LOCAL is
+       passed to gline_find()
+
+       * include/ircd_features.h: trap-door feature FEAT_DISABLE_GLINES
+       to disable G-lines; intended use: accidental G-line of *@*
+
+       * include/gline.h: add rexpire (record expiration time) field to
+       gline description structure; add GlineAction enumeration (still
+       undocumented) to describe actions that may be performed on G-lines
+
+2007-03-09  Michael Poole <mdpoole@troilus.org>
+
+       * include/patchlevel.h (PATCHLEVEL): Bump for .pre11 development.
+
+2007-03-09  Michael Poole <mdpoole@troilus.org>
+
+       * include/patchlevel.h (PATCHLEVEL): Bump for u2.10.12.10 release.
+
+2007-03-05  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/m_privs.c (ms_privs): Use the correct source when
+       forwarding the PRIVS request.
+
+       * tests/bug-1674539.cmd: New file to test for this.
+
+       * tests/test-driver.pl: Recognize "oper" command from scripts.
+
+2007-03-05  Michael Poole <mdpoole@troilus.org>
+
+       * tests/ircd.conf: Make into a hub.
+
+       * tests/ircd-2.conf: New file, for a second server.
+
+       * tests/ircd-3.conf: Configuration for a third server.
+
+2007-03-04  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/whocmds.c (count_users): Fix length of ipbuf.  (Spotted by
+       paulr.)
+
+2007-02-28  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/os_generic.c (sockaddr_from_irc): Zero out socket address
+       before setting family, and regardless of whether we have an
+       irc_sockaddr template.
+
+2007-02-25  Michael Poole <mdpoole@troilus.org>
+
+       * doc/example.conf: Document new options for General block.
+       
+       * include/res.h (clear_nameservers): Declare new function.
+       (add_nameserver): Declare previously static function.
+
+       * include/s_bsd.h (VirtualHost_dns_v4): Declare.
+       (VirtualHost_dns_v6): Likewise.
+
+       * ircd/ircd_lexer.l (DNS): Recognize new token.
+
+       * ircd/ircd_parser.y (DNS): Declare new token.
+       (generalitem): Allow new items for dns vhost(s) and dns servers.
+       (generaldnsvhost): New production.
+       (generaldnsserver): New production.
+
+       * ircd/ircd_res.c (VirtualHost_dns_v4): New variable.
+       (VirtualHost_dns_v6): Likewise.
+       (clear_nameservers): New function.
+       (restart_resolver): Scan specified servers so we only try to open
+       DNS client sockets that we need.
+
+       * ircd/ircd_reslib.c (irc_nscount): Remove redundant initializer.
+       (irc_res_init): Only read the resolver config file if there are no
+       nameservers provided.
+       (add_nameserver): Make non-static.  Remove off-by-one check
+       against IRCD_MAXNS.
+
+       * ircd/s_conf.c (read_configuration_file): Clear nameserver list
+       before reading the config file.
+
+2007-01-27  Jeannot Langlois <jeannot12@linuxmail.org>
+
+       * doc/example.conf (Features): Illustrate URLREG feature.
+
+       * doc/readme.features (URLREG): Define new feature.
+
+       * include/ircd_features.h (Feature): Add FEAT_URLREG.
+
+       * ircd/ircd_features.c (features): Set the default value.
+
+       * ircd/m_join.c (m_join): For ERR_NEEDREGGEDNICK, include the
+       URLREG value as a format argument.
+
+       * ircd/s_err.c (replyTable): Update ERR_NEEDREGGEDNICK
+       appropriately.
+
+2007-02-03  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/ircd_reply.c (protocol_violation): Avoid reusing the
+       va_list in vd.
+
+       * ircd/send.c (sendcmdto_channel_butone): Warn against using %v in
+       the pattern -- that will cause incorrect behavior.
+       (sendwallto_group_butone): Likewise.
+       (sendcmdto_match_butone): Likewise.
+
+2007-01-22  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/channel.c (find_delayed_joins): New function.
+       (modebuf_flush): Handle +D-D and related cases.
+       (mode_parse_mode): It is too early to handle +D here, so don't.
+       (CheckDelayedJoins): Use find_delayed_joins().
+
+2007-01-22  Michael Poole <mdpoole@troilus.org>
+
+       * tests: New subdirectory for test framework.
+
+       * tests/ircd.conf: Helper file for testing.
+
+       * tests/readme.txt: Simple documentation of test framework.
+
+       * tests/test-driver.pl: Testing script interpreter.
+
+2007-01-22  Michael Poole <mdpoole@troilus.org>
+
+       * doc/example.conf: Fix potentially confusing comment about ip
+       mask syntax.
+
+2007-01-22  Michael Poole <mdpoole@troilus.org>
+
+       * INSTALL: Mention source directory naming; update the reference
+       to the config file converter (hah); update CVS directions.
+
+2007-01-22  Michael Poole <mdpoole@troilus.org>
+
+       * include/supported.h: Move parameters from FEATURES1 to FEATURES2
+       so that neither ISUPPORT line has more than 15 parameters.  (Some
+       clients are picky about this.)
+
+2007-01-21  Michael Poole <mdpoole@troilus.org>
+
+       * include/patchlevel.h (PATCHLEVEL): Bump for pre10 development.
+
+2007-01-20  Michael Poole <mdpoole@troilus.org>
+
+       * include/patchlevel.h (PATCHLEVEL): Bump for 2.10.12.09 release.
+
+2007-01-15  Michael Poole <mdpoole@troilus.org>
+
+       * doc/readme.iauth (U): Document extended fields.
+
+       * include/s_auth.h (auth_set_user): Declare new parameters.
+
+       * ircd/m_user.c (m_user): Pass new parameters.
+
+       * ircd/s_auth.c (auth_set_user): Accept new parameters.  When
+       using Undernet extensions, forward them to the iauth process.
+
+2007-01-14  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/os_generic.c (os_recv_nonb): Set errno to zero when
+       returning IO_FAILURE due to a closed connection.
+
+2006-12-31  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/m_mode.c (ms_mode): Bounce modes from deopped members.
+
+2006-12-30  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/ircd_string.c (ircd_strncpy): Make sure the output buffer
+       is terminated.  We don't rely on the arguable strncpy semantics.
+
+2006-12-30  Michael Poole <mdpoole@troilus.org>
+
+       * include/struct.h (struct Server): Add asll_last field.
+
+       * ircd/ircd.c (check_pings): Add check for asll_last.  When a
+       server doesn't ping, use an old-style ping rather than AsLL ping.
+
+       * ircd/m_pong.c (ms_pong): Use ClearPingSent() rather than
+       ClrFlag().  Set asll_last to current time.
+       (mr_pong): Use ClearPingSent() rather than ClrFlag().
+       (m_pong): Likewise.
+
+       * ircd/s_bsd.c (completed_connection): Likewise.
+       (read_packet): Likewise.  Update cli_lasttime for servers in
+       addition to clients.
+
+2006-01-13  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/m_burst.c (ms_burst): Properly handle member mode :ov.
+
+2006-01-13  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/m_create.c (ms_create): Add channel name to the protocol
+       violation notice for a redundant CREATE.
+
+2006-01-13  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/s_user.c (set_nick_name): Use user's account name rather
+       than the account parameter, in case the parameter contains a colon
+       (i.e. "account:1234" format).
+
+2006-01-13  Michael Poole <mdpoole@troilus.org>
+
+       * doc/readme.who: Document 'd' user-matching flag.
+
+2006-12-18  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/m_jupe.c (mo_jupe): Fix which privilege is tested.
+
+2006-12-07  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/listener.c (show_ports): Update to show '4' and/or '6' as
+       flags in response, with a '-' suffix if either one fails to open.
+
+2006-12-07  Michael Poole <mdpoole@troilus.org>
+
+       * doc/example.conf (Port): Document the method to select IPv4 or
+       IPv6 restriction for a port.
+
+       * include/listener.h (LISTEN_IPV4): New listener flag.
+       (LISTEN_IPV6): New listener flag.
+       (struct Listener): Split 'fd' and 'socket' fields into two each.
+
+       * ircd/ircd_lexer.l (gb): Move to be alphabetical.
+       (gigabytes): Likewise.
+       (ipv4): New token.
+       (ipv6): Likewise.
+       Adapted word matcher to handle digits in the non-leading character.
+
+       * ircd/ircd_parser.y (USE_IPV4): New macro.
+       (USE_IPV6): Likewise.
+       (TOK_IPV4): New token.
+       (TOK_IPV6): Likewise.
+       (address_family): New non-terminal rule.
+       (portblock): Default to listening on both IPv4 and IPv6.
+       (portnumber): Add address_family element and use it.
+       (portvhost): Likewise.
+
+       * ircd/listener.c (make_listener): Adjust for newly split fields
+       in struct Listener.
+       (inetport): Likewise.  Adjust return value as well.
+       (add_listener): Update to handle both IPv4 and IPV6 support.
+       (close_listener): Likewise.
+       (accept_connection): Because each listener has two sockets, it is
+       no longer safe to free the listener when one is destroyed -- so
+       don't.  Also accept() on the file descriptor from the incoming
+       event rather than on a fixed fd.
+
+       * ircd/os_generic.c (os_socket): For platforms with IPV6_V6ONLY,
+       enable it for AF_INET6 sockets rather than disabling it for
+       unspecified sockets.
+
+2006-12-06  Michael Poole <mdpoole@troilus.org>
+
+       * include/listener.h (enum ListenerFlag): New enum.
+       (struct Listener): Convert "active", "hidden" and "server" to a
+       flagset.
+       (add_listener): Convert "is_server" and "is_hidden" arguments to
+       use the same flagset structure.
+
+       * ircd/ircd_parser.y (listen_flags): New variable.
+       (general_vhost): Consolidate references to $3 to use a variable.
+       (portblock): Use listen_flags instead of tconn and tping.
+       (portserver): Likewise.
+       (porthidden): Likewise.
+
+       * ircd/listener.c (show_ports): Use new field in Listener.
+       (set_listener_options): New function.
+       (inetport): Use it.
+       (add_listener): Use new field in Listener.  When reusing an extant
+       listener, call set_listener_options() so the options are updated.
+       (mark_listeners_closing): Use new field in Listener.
+       (close_listeners): Use new helper macro to check activeness.
+       (release_listener): Likewise.
+       (accept_connection): Likewise.
+
+       * ircd/s_bsd.c (report_error): Use the standard snotice rate
+       limiting here.
+       (add_connection): Use new helper macro to check serverness.
+
+2006-11-04  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/m_nick.c (m_nick): If we get NICK on a server port, tell
+       the client to go away.
+
+2006-11-04  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/version.c.SH: Skip version.c.
+
+2006-11-04  Michael Poole <mdpoole@troilus.org>
+
+       * doc/readme.who: Document new 'o' field flag.
+
+       * include/whocmds.h (WHO_FIELD_OPL): New flag.
+
+       * ircd/channel.c (send_channel_modes): Rename feat_oplevels to
+       send_oplevels and determine it automatically.
+       (modebuf_flush_int): Pass along oplevel if it's less than
+       MAXOPLEVEL.
+       (mode_process_clients): Allow oplevels to be inherited for -A
+       channels.  Inherit the opper's oplevel if >= MAXOPLEVEL.
+
+       * ircd/m_who.c (m_who): Recognize 'o' flag as WHO_FIELD_OPL.
+
+       * ircd/whocmds.c (do_who): Send oplevel for WHO_FIELD_OPL, but
+       only show up to the requester's own oplevel.
+
+2006-10-21  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/convert-conf.c (finish_connects): Fix error display for
+       missing C: lines when an H: line is present.
+
+2006-08-02  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/ircd_parser.y (connectblock): Check for too-long password.
+       (operblock): Comment why we don't check password length.  Move
+       PRIV_PROPAGATE test earlier (so a buggy edit, rehash, /oper will
+       not crash).
+       (clientblock): Check for too-long password.
+
+2006-08-02  Michael Poole <mdpoole@troilus.org>
+
+       * include/channel.h (struct Ban): Fix typo in doxygen comment.
+
+2006-07-09  Michael Poole <mdpoole@troilus.org>
+
+       * include/patchlevel.h (PATCHLEVEL): Bump for pre09.
+
+2006-07-09  Michael Poole <mdpoole@troilus.org>
+
+       * include/patchlevel.h (PATCHLEVEL): Bump for 2.10.12.08 release.
+
+2006-07-05  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/s_auth.c (auth_freelist): New static variable.
+       (check_auth_finished): Move call to destroy_auth_request().
+       (destroy_auth_request): Prepend auth request to freelist.
+       (start_auth): Use struct from auth freelist if possible.
+
+2006-06-30  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/ircd_parser.y (iauth*): Avoid leaking program name string.
+
+2006-06-30  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/s_auth.c (check_auth_finished): Free auth structure when
+       done with it.
+       (sendto_iauth): Free message buffer when done with it.
+
+2006-06-26  Michael Poole <mdpoole@troilus.org>
+
+       * include/patchlevel.h (PATCHLEVEL): Bump for pre08.
+
+2006-06-26  Michael Poole <mdpoole@troilus.org>
+
+       * include/patchlevel.h (PATCHEVEL): Bump for release.
+
+2006-06-17  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/m_pass.c (mr_pass): Only back 'len' up when it's safe.
+
+2006-06-08  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/m_whois.c (do_whois): Prefix '*' to names of secret (local)
+       channels for locops as well as global opers.
+
+2006-06-08  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/m_gline.c (ms_gline): Use final argument as G-line reason.
+
+2006-06-08  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/gline.c (gline_stats): Show activation state in /stats g.
+
+       * ircd/s_err.c (RPL_STATSGLINE): Update format string to match.
+
+2006-06-07  Michael Poole <mdpoole@troilus.org>
+
+       * doc/example.conf: Document the list_chan privilege.
+
+       * ircd/ircd_lexer.l: Recognize the token.
+
+       * ircd/ircd_parser.y: Treat it appropriately.
+
+2006-06-07  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/s_auth.c (auth_ping_timeout): If the client never had an
+       auth request, kill them on ping timeout.
+
+2006-06-05  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/s_auth.c (auth_timeout_callback): Clear AR_DNS_PENDING when
+       destroying the lookup and reporting DNS failure.
+
+2006-05-28  Michael Poole <mdpoole@troilus.org>
+
+       * doc/readme.features (MAXBANS): Update default value.
+       (NICKLEN): Likewise.
+       (HIS_STATS_*): Sort alphabetically.
+
+       * ircd/m_stats.c (m_stats): Describe the intention so that there
+       are not further questions about local opers and remote /stats.
+       Fix places that use cptr instead of sptr.
+
+2006-05-24  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/s_auth.c (auth_dns_callback): Be more careful about
+       handling failed DNS lookups.  Use a more standard function to
+       disconnect clients for IP mismatches.
+       (start_auth): Use a more standard function to disconnect clients
+       for peer or local socket address lookup failures.
+
+2006-05-17  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/s_auth.c (auth_ping_timeout): Fix off-by-one error.
+
+2006-05-17  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/Makefile.in (install-*): Install convert-conf.  Install
+       umkpasswd when ${BINDIR}/ircd is not a symlink.
+
+2006-05-15  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/s_auth.c (check_auth_finished): Only check passwords on
+       user ports.
+
+2006-05-14  Michael Poole <mdpoole@troilus.org>
+
+       * doc/example.conf (Connect): Mention the vhost option.
+
+2006-05-08  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/m_pong.c (mr_pong): Move cli_lasttime update from here...
+
+       * ircd/s_auth.c (auth_set_pong): ... to here.
+
+2006-05-07  Michael Poole <mdpoole@troilus.org>
+
+       * include/s_auth.h (auth_ping_timeout): Declare new function.
+
+       * ircd/ircd.c (check_pings): Move auth timeout logic into that new
+       function.
+
+       * ircd/s_auth.c (HeaderMessages): Insert new message.
+       (auth_ping_timeout): Define new function.
+       (auth_timeout_callback): Remove "hurry" notification from here.
+
+2006-05-07  Michael Poole <mdpoole@troilus.org>
+
+       * include/s_auth.h (destroy_auth_request): Remove second argument.
+
+       * ircd/list.c (free_client): Update to match.
+
+       * ircd/s_auth.c (check_auth_finished): Remove second argument and
+       update call to destroy_auth_request().
+       (send_auth_query): Update call to destroy_auth_request().
+       (destroy_auth_request): Remove second argument.
+       (auth_timeout_callback): Send timeout failure messages here
+       instead.  Update call to check_auth_finished().
+       (auth_dns_callback): Update call to check_auth_finished().
+       (start_auth): Likewise.
+       (auth_set_pong): Likewise.
+       (auth_set_user): Likewise.
+       (auth_set_nick): Likewise.
+       (auth_cap_done): Likewise.
+       (iauth_parse): Likewise.
+
+2006-05-06  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/s_auth.c (AuthRequestFlag): Add AR_PASSWORD_CHECKED.
+       (check_auth_finished): Move password check out of iauth-only part
+       and use AR_PASSWORD_CHECKED to make sure we only check it once.
+
+2006-04-28  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/s_auth.c (AuthRequest): Clarify comment on 'timeout' field.
+       (check_auth_finished): Fix timeout update.
+       (destroy_auth_request): Only delete timer if it is active.
+       (auth_timeout_callback): Do not disconnect client on timeout, so
+       that the user can finish sending NICK/USER or doing iauth.
+
+2006-04-28  Michael Poole <mdpoole@troilus.org>
+
+       * doc/example.conf (Admin): Fix documentation of which line can be
+       listed twice.
+
+       * ircd/ircd_parser.y (adminblock): Allow admin information to be
+       changed via /rehash.
+
+2006-04-06  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/s_auth.c (start_auth): Add client to list after getting
+       endpoint names (which can apparently fail for some reason).
+
+2006-04-06  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/ircd_snprintf.c: Use SIZEOF_LONG_LONG (which is 0 for
+       unknown types) instead of the never-defined HAVE_LONG_LONG.
+
+2006-04-06  Michael Poole <mdpoole@troilus.org>
+
+       * doc/example.conf (IAuth): Update to reflect new syntax.
+
+       * doc/readme.who: Fix typo in metasyntactic variable name.
+
+2006-04-04  Michael Poole <mdpoole@troilus.org>
+
+       * include/patchlevel.h: Update for pre07.
+
+2006-04-04  Michael Poole <mdpoole@troilus.org>
+
+       * include/patchlevel.h: Update for u2.10.12.06 release.
+
+2006-04-03  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/channel.c (bmatch): If ipmask_check() indicates old_ban is
+       a CIDR-wise superset of new_ban, check whether new_ban is a
+       text-wise superset of old_ban.
+
+2006-03-31  Michael Poole <mdpoole@troilus.org>
+
+       * tools/iauth-test (send_server_notice): Use a colon prefix before
+       the message.
+       (%handlers): Likewise.
+
+2006-03-24  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/ircd_signal.c (alloc_crec): Zero-fill returned
+       ChildRecord structs.
+
+       * ircd/jupe.c (make_jupe): Zero-fill newly allocated jupes.
+
+       * ircd/list.c (make_link): Zero-fill returned SLink structs.
+
+       * ircd/whowas.c (whowas_init): Delete function.
+       (whowas_alloc): Rewrite to follow the more common pattern and to
+       zero-fill returned Whowas structs.
+
+2006-03-23  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/s_auth.c: rewrite iauth_read(), spliting out the parsing
+       into iauth_parse(); change parsing to separate parameters and deal
+       with the ':' sentinel; send sentinel in multi-word parameters; fix
+       iauth_cmd_config() and iauth_cmd_stats() to clear the 'next'
+       pointer in the SLink structure; fix buffering in
+       iauth_read_stderr(); remove carriage returns from STDERR contents
+       as well
+
+       * doc/readme.iauth: fix a minor typo in comments for 'd' and 'N'
+       server messages
+
+2006-03-18  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/convert-conf.c (finish_features): Do not emit a feature
+       setting that has no values.
+
+2006-03-18  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/channel.c (mode_parse_key): Outside of burst, allow
+       overwriting of keys by a service when a key is already set.
+       (mode_parse_upass): Likewise.  Instead, ignore new Upass during
+       burst if it is lexicographically greater than the current one.
+       (mode_parse_apas): Likewise for Apass, but only allow overwiting
+       an existing Apass in a BURST.
+
+2006-03-18  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/channel.c (modebuf_flush_int): Fix typo about changing
+       oplevels.  Send correct channel TS for modes to other servers.
+       (mode_parse): Accept timestamps on modes from users on other
+       servers.  If the received timestamp is too large, handle that.
+
+       * ircd/m_create.c (ms_create): Mention the CREATE-during-burst
+       case and handle it.
+
+       * ircd/m_mode.c (ms_mode): Put back HACK(3) when oplevels are off.
+
+2006-03-14  Wouter Coekarts <wouter@coekaerts.be>
+
+       * ircd/s_err.c (RPL_STATSILINE): Add two %s to the first field.
+
+       * ircd/s_stats.c (stats_configured_links): Use the new %s's to
+       show username masks for I: lines that have them.
+       (stats_access): Likewise.
+
+2006-03-13  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/msgq.c (msgq_vmake): Try to clear msgbuf freelist after
+       killing clients, so that that case does not lead immediately to a
+       server panic.
+       (msgq_count_memory): Report total buffer text used as a way to
+       determine whether the BUFFERPOOL value is marginal.
+
+2006-03-02  Michael Poole <mdpoole@troilus.org>
+
+       * include/ircd_osdep.h (os_socket): New parameter.
+
+       * include/res.h (irc_in_addr_unspec): New macro.
+
+       * ircd/ircd_res.c (restart_resolver): Set family appropriately.
+
+       * ircd/listener.c (inetport): Let os_ library pick socket family.
+
+       * ircd/os_generic.c: Do not #define _XOPEN_SOURCE on FreeBSD 5+.
+       (sockaddr_from_irc): New parameter.
+       (os_sendto_nonb): Use new parameter to sockaddr_from_irc().
+       (os_socket): New parameter.  Try to turn off IPV6_V6ONLY on
+       sockets that listen on unspecified addresses.
+       (os_connect_nonb): Use new parameter to sockaddr_from_irc().
+
+       * ircd/s_auth.c (start_auth_query): Let os_ library pick socket
+       family.
+
+       * ircd/s_bsd.c (connect_inet): If we pick the IPv4 vhost, specify
+       family for os_socket() as AF_INET.
+
+       * ircd/uping.c (uping_init): Set socket family appropriately.
+       (uping_server): Likewise.
+       (uping_end): Fix format strings (the ms_* fields are int, not
+       long, and this causes bad results on LP64 machines).
+
+2006-02-22  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/m_silence.c (apply_silence): Refuse to apply silences for
+       local users that are broader than an IPv4 /16 or an IPv6 /32,
+       unless they match every host indiscriminately.
+
+2006-02-22  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/s_auth.c (check_auth_finished): Give non-iauth clients
+       connection classes, too.
+       (auth_close_unused): Remove redundant check for iauth != NULL.
+       (report_iauth_conf): Check iauth != NULL before deref'ing it.
+       (report_iauth_stats): Likewise.
+
+2006-02-22  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/s_auth.c: fix macros to not dereference a NULL pointer when
+       iauth is not connected
+
+2006-02-17  Alex Badea <vamposdecampos@gmail.com>
+
+       * ircd/s_auth.c (auth_set_username): Check if the last
+       character of the username is alphanumeric, instead of the
+       '\0' terminator.
+       
+       * ircd/m_pong.c (mr_pong): Parse cookie with strtoul(),
+       since atol() causes signedness problems.
+
+2006-02-15  Michael Poole <mdpoole@troilus.org>
+
+       * include/res.h (NXDOMAIN): Define.
+
+       * ircd/ircd_res.c (res_readreply): Treat NXDOMAIN just like
+       SERVFAIL.  Patch courtesy of Dianora.
+
+       * tools/iauth-test (Carp): This doesn't actually use Carp.
+
+2006-02-15  Michael Poole <mdpoole@troilus.org>
+
+       * doc/example.conf: Include new HIS_STATS_IAUTH feature.
+
+       * doc/readme.features: Document the feature.
+
+       * doc/readme.iauth: Rewrite to reflect the new progressive iauth
+       protocol, based on IRCnet's iauth.
+
+       * doc/snomask.html: Document SNO_AUTH server notice flag.
+
+       * include/client.h (FLAG_IAUTHED): Delete.
+       (con_cookie): Delete.
+       (con_unreg): Delete.
+       (con_auth): Make comment capitalization consistent.
+       (con_iauth): Delete.
+       (CLIREG_*): Delete.
+       (cli_unreg): Delete.
+       (cli_cookie): Delete.
+       (cli_iauth): Delete.
+       (con_unreg): Delete.
+       (con_iauth): Delete.
+       (IsIAuthed): Delete.
+       (SetIAuthed): Delete.
+       (SNO_AUTH): New server notice flag.
+       (SNO_ALL): Update to include SNO_AUTH.
+       (SNO_OPER): Update to include SNO_AUTH.
+
+       * include/ircd_auth.h: Delete file.
+
+       * include/ircd_features.h (HIS_STATS_IAUTH): New feature.
+
+       * include/s_auth.h: Rewrite almost everything for new auth system.
+
+       * include/s_user.h (COOKIE_VERIFIED): Delete.
+       (register_user): Remove redundant nick and username arguments.
+
+       * ircd/ircd_auth.c: Delete file.
+
+       * ircd/ircd_features.c (HIS_STATS_IAUTH): New feature.
+
+       * ircd/ircd_lexer.l (PROGRAM): New token in grammar.
+
+       * ircd/ircd_log.c (masks): Add SNO_AUTH flag.
+
+       * ircd/ircd_parser.y (stringlist): Simplify production.
+       (iauthblock): Revise to only include a PROGRAM production.
+
+       * ircd/list.c (make_client): Do not assign to deleted field.
+
+       * ircd/m_cap.c (cap_ls): Use auth_cap_start() instead of
+       cli_unreg().
+       (cap_req): Likewise.
+       (cap_end): Use auth_cap_done() instead of cli_unreg().
+
+       * ircd/m_pass.c (mr_pass): Merge arguments to PASS.  Use
+       auth_set_password() to notify iauth of password.
+
+       * ircd/m_pong.c (mr_pong): Use auth_set_pong() instead of
+       cli_cookie() and cli_unreg().
+
+       * ircd/m_user.c (m_user): Use auth_set_user() instead of
+       cli_unreg(), etc.
+
+       * ircd/s_auth.c: Rewrite most of the infrastructure for the new
+       auth system.
+
+       * ircd/s_conf.c (rehash): Call auth_*() instead of iauth_*().
+
+       * ircd/s_misc.c (exit_one_client): Do not use iauth_exit_client().
+       (exit_client): Use auth_send_exit() instead.
+
+       * ircd/s_stats.c (statsinfo): Include iauth and iauthconf.
+
+       * ircd/s_user.c (clean_user_id): Delete (moved into s_auth.c).
+       (register_user): Remove nick and username parameters; move conf
+       interactions and username validation to s_auth.c.
+       (set_nick_name): Use auth_set_nick() instead of cli_cookie(),
+       cli_unreg(), etc.
+
+       * tools/iauth-test: Implementation of iauth for testing purposes.
+
+2006-02-15  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/ircd_snprintf.c (doprintf): Fix typecast for %hu.
+
+2006-02-15  Michael Poole <mdpoole@troilus.org>
+
+       * include/ircd_signal.h (SigChldCallBack): New typedef.
+       (register_child): Declare.
+       (unregister_child): Declare.
+       (reap_children): Declare.
+
+       * ircd/ircd_signal.c (alloc_crec): New function.
+       (release_crec): New function.
+       (register_child): New function.
+       (do_unregister_child): New function.
+       (unregister_child): New function.
+       (sigchld_callback): New function.
+       (setup_signals): Hook SIGCHLD.
+       (reap_children): New function.
+
+       * ircd/ircd.c (server_restart): Call reap_children() on exit.
+
+2006-02-15  Michael Poole <mdpoole@troilus.org>
+
+       * include/ircd_osdep.h (os_socketpair): Declare.
+
+       * ircd/os_generic.c (is_blocked): New local function.
+       (os_*): Use is_blocked() instead of cut-and-pasted code.
+       (os_socketpair): New function.
+
+2006-02-15  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/match.c (match): Fix backtracking bug after an escape
+       (reported by Michael, I think).
+
+2006-02-04  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/ircd.c (try_connections): Scan all Connect blocks for the
+       earliest hold time (suggested by Michael).
+
+2006-02-04  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/m_join.c (m_join): Remove #if 0 code and update comment.
+
+       * ircd/m_mode.c (ms_mode): Remove self-op support.
+
+2006-01-12  Michael Poole <mdpoole@troilus.org>
+
+       * include/patchlevel.h (PATCHLEVEL): Update for 2.10.12.pre06.
+
+2006-01-12  Michael Poole <mdpoole@troilus.org>
+
+       * include/patchlevel.h (PATCHLEVEL): Update for release.
+
+2006-01-11  Michael Poole <mdpoole@troilus.org>
+
+       * doc/Makefile.in: Make install target VPATH-safe.
+
+       * doc/example.conf: Comment out example IAuth block.
+
+       * ircd/m_burst.c (ms_burst): Change isdigit() to IsDigit(),
+       silencing a warning on Solaris.
+
+2006-01-09  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/s_user.c (register_user): Do not send +r flag to user when
+       they first connect.
+
+2006-01-09  Michael Poole <mdpoole@troilus.org>
+
+       * include/ircd_features.h (FEAT_ZANNELS): Actually, put it back.
+
+       * ircd/ircd_features.c (FEAT_ZANNELS): Likewise.
+
+2006-01-06  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/channel.c (mode_process_clients): Do not reveal zombies who
+       are being opped (MODE and KICK crossed).  Reported by coekie.
+
+2006-01-06  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/m_join.c (ms_join): Wipe out all modes (not just chanops)
+       when replacing a resurrected channel.
+
+       * ircd/convert-conf.c (dupstring): Fix probable off-by-one size
+       passed to memcpy().
+
+2006-01-03  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/channel.c (modebuf_flush_int): Also send timestamp when &me
+       originates the MODE going to other servers (currently just when a
+       client joins a zannel or uses an A/U password).
+
+2006-01-02  Michael Poole <mdpoole@troilus.org>
+
+       * include/ircd_features.h (FEAT_ZANNELS): Remove.
+
+       * ircd/channel.c (sub1_from_channel): Remove reference to
+       FEAT_ZANNELS.
+
+       * ircd/ircd_features.c (FEAT_ZANNELS): Remove.
+
+       * ircd/m_destruct.c (ms_destruct): Do not try to remove a destruct
+       event for channels that do not have them (created by BURSTing a
+       zannel but not yet destroyed by EOB).
+
+2005-12-31  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/m_whowas.c (m_whowas): Mention that IP is untracked in WHOWAS.
+       Spotted by Progs.
+
+2005-12-30  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/m_topic.c: Remove block comment about sptr, cptr, etc.
+       (do_settopic): Add doxygen comment. Move permissions checks..
+       (m_topic): .. to here.  Update doxygen comment.
+       (ms_topic): Update doxygen comment here too.
+
+2005-12-30  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/s_conf.c (conf_debug_iline): Fix display of null passwords.
+
+2005-12-30  Michael Poole <mdpoole@troilus.org>
+
+       * RELEASE.NOTES: Mention removal of HIS_STATS_h.
+
+       * ircd/convert-conf.c (removed_features): Add AUTOHIDE,
+       HIS_DESYNCS and TIMESEC.
+       (get_connect): Do not downcase connection name on insert.
+       (do_feature): Do not upcase feature name (cf HIS_STATS_k).
+
+2005-12-30  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/engine_devpoll.c (engine_loop): Remove bogus assert.
+
+2005-12-31  Perry Lorier <isomer@undernet.org>
+
+       * convert-conf.c: Skip with a warning, H:'s that are missing a
+       corresponding C:
+
+2005-12-28  Michael Poole <mdpoole@troilus.org>
+
+       * ircd-patch: Do not use [ for test, and do not use $[] for expr.
+       (Solaris /bin/sh, among others, have problems with those.)
+
+2005-12-23  Michael Poole <mdpoole@troilus.org>
+
+       * config.guess: Update to current version.
+
+       * config.sub: Likewise.
+
+2005-12-23  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/m_join.c: get rid of MAGIC_REMOTE_JOIN_TS; perform the
+       deop-other-users loop only when creation < channel timestamp or
+       when the channel in question happens to be a zannel; actually deop
+       users, don't just say we are and not do it
+
+       * ircd/m_create.c (ms_create): get rid of MAGIC_REMOTE_JOIN_TS
+
+       * include/channel.h: get rid of MAGIC_REMOTE_JOIN_TS
+
+2005-12-13  Michael Poole <mdpoole@troilus.org>
+
+       * configure.in: Define a macro when compiling on Solaris.
+
+       * ircd/ircd_crypt_native.c (_XOPEN_SOURCE): Turn down to 500 so
+       that Solaris doesn't complain that SUSv3 requires C99.
+
+       * ircd/os_generic.c (_XOPEN_SOURCE): Likewise, but leave it at 600
+       on non-Solaris platforms so that IPv6 stays supported.
+
+2005-12-13  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/m_join.c (ms_join): Prevent net rides allowed by moving the
+       channel timestamp backwards in time without deopping current ops.
+       (Reported by Wouter Coekaerts.)
+
+2005-12-13  Michael Poole <mdpoole@troilus.org>
+
+       * doc/example.conf: Remove extraneous "Other" Client block.
+
+       * ircd/convert-conf.c (finish_operators): Fix operator precedence
+       bug.
+
+       * ircd/ircd_parser.y (clientclass): Fix typo in error message.
+
+2005-11-27  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/Makefile.in (version.c): version.c also depends on
+       version.h, patchlevel.h and source files.
+
+2005-11-27  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/m_join.c (m_join): Count a join to a new channel as a
+       target change.
+
+2005-11-19  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/s_stats.c (stats_servers_verbose): Display IPv6 support
+       flag with the other per-server flags.
+
+2005-11-19  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/convert-conf.c (finish_features): Only emit "Features {"
+       once in the converted configuration file.  Display the original
+       input line for each feature line in the output.
+
+2005-11-18  Michael Poole <mdpoole@troilus.org>
+
+       * include/patchlevel.h (PATCHLEVEL): Update for pre05.
+
+2005-11-18  Michael Poole <mdpoole@troilus.org>
+
+       * include/patchlevel.h (PATCHLEVEL): Update for release.
+
+2005-11-15  Brian Cline <brian.cline@gmail.com>
+
+       * doc/example.conf: Add new line for HIS_MODEWHO feature.
+
+       * doc/readme.features: Document new HIS_MODEWHO feature.
+
+       * include/ircd_features.h: Declare new HIS_MODEWHO feature.
+
+       * ircd/channel.c (modebuf_flush_int): Use new HIS_MODEWHO feature
+       to show or hide the server name that performed a channel mode change.
+
+       * ircd/ircd_features.c: Place new HIS_MODEWHO setting in the feature
+       table and give it a default value of true, which will hide the
+       originating server name.
+
+2005-11-16  Michael Poole <mdpoole@troilus.org>
+
+       * doc/example.conf (Features): Mention ZANNELS default.
+
+       * doc/readme.features: Document OPLEVELS and ZANNELS.
+
+2005-11-17  Carlo Wood <run@alinoe.com>
+
+       * include/ircd_features.h (Feature): Add ZANNELS.
+       * ircd/ircd_features.c (FeatureDesc): idem.
+       * ircd/channel.c (sub1_from_channel): Don't keep zannels
+       around when ZANNELS and OPLEVELS are FALSE.
+       * ircd/m_destruct.c (ms_destruct): Use JOIN instead of
+       CREATE to recreate a non-empty channel after DESTRUCT.
+
+2005-11-16  Michael Poole <mdpoole@troilus.org>
+
+       * tools/convert-conf.py: Delete obsolete code.
+
+2005-11-16  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/m_names.c (m_names): Fix handling of NAMES #a,#b.
+       (ms_names): Likewise.
+
+2005-11-15  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/m_nick.c (ms_nick): Clarify message when an older nick
+       overrules a newer nick.  When killing a client for a nick
+       collision, make sure to use the numnick as the first argument.
+
+2005-11-14  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/channel.c (member_can_send_to_channel): After prodding from
+       reed, always allow remote users to send to a channel.  He also
+       pointed out a bug in the first version of this change.
+
+2005-11-14  Carlo Wood <run@alinoe.com>
+
+       * ircd/channel.c (modebuf_flush_int): Fix test for limitdel.
+       (modebuf_mode_uint): Make sure the limit is included as an
+       argument when necessary (and only when necessary) in a bounce.
+
+       * ircd/m_destruct.c (ms_destruct): Generate a mode bounce instead
+       of burst to resynchronize a non-empty destructed channel.
+
+2005-11-14  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/channel.c (find_no_nickchange_channel): Disallow nick
+       changes by voiceless no-account users on a +r channel.
+
+2005-11-14  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/m_kick.c (ms_kick): Fix test for whether a client's own
+       server is kicking him.
+
+2005-11-13  Michael Poole <mdpoole@troilus.org>
+
+       * include/patchlevel.h (PATCHLEVEL): Bump for pre04.
+
+2005-11-13  Michael Poole <mdpoole@troilus.org>
+
+       * include/patchlevel.h (PATCHLEVEL): Update for release.
+
+2005-11-13  Carlo Wood <run@alinoe.com>
+
+       * ircd/m_create (ms_create): Accept CREATE for zannels.
+
+       * ircd/m_join.c (m_join): MODE +o for a zannel must come from the
+       server for compatibility with older versions.
+
+2005-11-12  Michael Poole <mdpoole@troilus.org>
+
+       * include/patchlevel.h (PATCHLEVEL): Bump for pre03.
+
+2005-11-12  Michael Poole <mdpoole@troilus.org>
+
+       * include/patchlevel.h (PATCHLEVEL): Update for release.
+
+2005-11-11  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/ircd_res.c (proc_answer): Follow CNAME when doing A
+       and AAAA lookups as well as PTR.
+
+2005-11-07  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/channel.c (mode_parse_client): Allow clients to specify
+       oplevel in MODE #channel +o.
+       (mode_process_clients): Allow oplevel 999 to deop another 999.
+
+       * ircd/kick.c (m_kick): Allow oplevel 999 to kick another 999.
+
+2005-10-31  Michael Poole <mdpoole@troilus.org>
+       (Based on a patch by Romain Bignon <progs@ir3.org>)
+
+       * ircd/channel.c: Some modes (currently only WASDELJOINS) should
+       not be propagated to remote servers.
+
+2005-10-30  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/channel.c (mode_parse_apass): Move all send_reply() errors
+       inside an if (MyUser(state->sptr)) test.
+
+       * ircd/m_join.c (m_join): Reorganize zannel join check to match
+       surrounding code.
+
+2005-10-30  Carlo Wood <run@alinoe.com>
+
+       * ircd/channel.c (sub1_from_channel): Delay destruction for -A
+       channels.  They become zombie channels (zannels).
+       (mode_parse_upass): Add duration to ERR_NOMANAGER message.
+       (mode_parse_apass): Likewise.  Unconditionally set the member who
+       sets Apass as oplevel 0.  Clear Upass when clearing Apass.
+       (joinbuf_join): Remove code to pass oplevel in JOIN.
+
+       * ircd/m_burst.c (ms_burst): Handle zannels.
+
+       * ircd/m_join.c (m_join): Handle a join to a zannel.  If the user
+       is joining with ops and/or an oplevel, send those.
+       (ms_join): Stop trying to parse oplevels in JOIN.  Copy join
+       timestamp when a user joins a zannel.
+
+       * ircd/m_mode.c (ms_mode): Never generate HACK3.  Silently allow a
+       user to op himself if he is the only one in a channel.
+
+       * ircd/s_err.c (ERR_UPASSSET): Remove extra space.
+       (ERR_UPASSNOTSET): Likewise.
+       (ERR_NOMANAGER): Add field for channel lifetime.
+
+2005-10-30  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/m_join.c (m_join): Fix check for OVERRIDE when the real
+       channel key is OVERRIDE.  (Reworked patch from a1kmm.)
+
+2005-10-30  Michael Poole <mdpoole@troilus.org>
+
+       * .cvsignore: Add autom4te.cache.
+
+       * ircd/.cvsignore: Add convert-conf.
+
+       * ircd/test/.cvsignore: Add ircd_match_t.
+
+       * patches/.cvsignore: Add marks.
+
+2005-10-28  Alex Badea  <vamposdecampos@gmail.com>
+
+       * ircd/m_kick.c (ms_kick): Fix format string typo (bug #1339538)
+
+2005-10-17  Diane Bruce  <db@db.net>
+
+       * ircd/ircd_res.c: Don't send retries if the client did
+       not resolve (SERVFAIL); this fixes a bug causing a flurry
+       of retries in this case
+
+2005-10-14  Michael Poole <mdpoole@troilus.org>
+
+       * include/patchlevel.h (PATCHLEVEL): Update to pre02.
+
+2005-10-14  Michael Poole <mdpoole@troilus.org>
+
+       * doc/readme.cvs: Document tag name consistently with the release
+       name.
+
+       * include/patchlevel.h (PATCHLEVEL): Bump patchlevel for release
+       of 2.10.12.01.
+
+2005-10-12  Michael Poole <mdpoole@troilus.org>
+
+       * doc/example.conf: Update documentation to match this change.
+
+       * ircd/client.c (client_set_privs): Make default global oper
+       privileges match what was in 2.10.11.
+
+2005-10-11  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/os_generic.c (os_get_rusage): Make conditional on DEBUGMODE
+       to mitigate bug #1313429.
+
+2005-10-12  Perry Lorier <isomer@undernet.org>
+
+       * include/s_stats.h: Add new "Local" only flag to /stats.
+
+       * ircd/m_stats.c: Consult it.
+
+       * ircd/s_stats.c: Use the flag.
+
+2004-01-04  Kevin L Mitchell  <klmitch@mit.edu>
+
+       * ircd/s_numeric.c (do_numeric): fix a crash when a numeric is
+       sent to a channel...
+
+2005-10-06  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/m_join.c (m_join): Report too-long channel names as
+       non-existent.
+
+2005-10-05  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/m_names.c (m_names): Fix format string when forwarding
+       /names -D to other servers.
+       (ms_names): Likewise.  Add support for remote /names -D.
+
+2005-10-05  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/class.c (do_find_class): Fix bug from previous commit.
+
+       * ircd/ircd_parser.y (clientblock): Allow setting Client port.
+
+       * ircd/s_conf.c (check_limit_and_attach): Merge into attach_iline.
+       (attach_iline): Only set FLAG_DOID when we are sure we will attach
+       this Client block to the client. [Credit: Jukka Ollila and others]
+
+2005-10-04  Michael Poole <mdpoole@troilus.org>
+       [Based on a patch by Jukka Ollila]
+
+       * include/class.h (find_class): Rename to do_find_class().
+
+       * ircd/class.c (class_delete_marked): Keep invalid classes in list
+       until next rehash.
+       (add_class): Use new parameter to do_find_class() to allow a class
+       to be "resurrected".
+       (find_class): Rename.
+       (report_classes): Use 'y' instead of 'Y' when reporting invalid
+       classes.
+
+2005-10-01  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/m_kick.c (ms_kick): If the kick target is join-delayed,
+       only send the KICK to the kicker.  Spotted by Cesar_.
+
+2005-10-01  Michael Poole <mdpoole@troilus.org>
+
+       * include/patchlevel.h (PATCHLEVEL): Update to pre1.
+
+       * ircd/class.c (init_class): Only set default class's ->next
+       pointer when first allocating it.
+
+2005-09-30  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/m_who.c (m_who): Handle matchsel & WHO_FIELD_ACC when
+       matching users.
+
+2005-09-30  Michael Poole <mdpoole@troilus.org>
+
+       * include/patchlevel.h: Update for release.
+
+2005-09-28  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/m_kick.c (ms_kick): Use correct oplevel when bouncing a
+       chanop being kicked.
+
+2005-09-26  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/whocmds.c (do_who): Fix uninitialized variable warning
+       about 'chan'.
+
+2005-09-26  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/parse.c (del_msg_element): Only delete empty subtrees, and
+       leave subtrees that may still contain data.
+
+2005-09-26  Michael Poole <mdpoole@troilus.org>
+
+       * include/channel.h (struct ModeBuf): Add mbm_oplevel to args
+       array.
+       (MB_OPLEVEL): New corresponding macro.
+       (modebuf_mode_client): Add corresponding argument.
+
+       * ircd/channel.c (modebuf_flush_int): Adjust worst-case buffer
+       usage to include :999 suffix.  Change format for oplevel passing.
+       (modebuf_mode_client): Set oplevel field in mbuf args array.
+       (struct ParseState): Add oplevel field to cli_change array.
+       (mode_parse_client): Accept and record oplevel suffix from
+       servers; fix it up if we're bouncing a deop.
+       (mode_process_clients): If a valid oplevel was parsed, use it.
+
+       * ircd/m_burst.c (ms_burst): Pass oplevel to modebuf_mode_client().
+
+       * ircd/m_clearmode.c (do_clearmode): Likewise.
+
+       * ircd/m_create.c (ms_create): Likewise.
+
+       * ircd/m_kick.c (ms_kick): Likewise.
+
+2005-09-23  Michael Poole <mdpoole@troilus.org>
+
+       * include/whocmds.h (WHOSELECT_DELAY): Define new constant.
+
+       * ircd/m_who.c (m_who): Accept 'd'/'D' as a way to set
+       WHOSELECT_DELAY, just like 'o' for WHOSELECT_OPER.  Do not skip
+       join-delayed users if WHOSELECT_DELAY is set.
+
+       * ircd/whocmds.c (do_who): Remember membership for shared channel
+       if one exists.  Use it when displaying flags, adding '<' for
+       join-delayed users.
+
+2005-09-22  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/channel.c (mode_parse_key): Only accept the new key when
+       the current one is empty or "greater" than the new one.
+       (mode_parse_upass): Likewise, for upass.
+       (mode_parse_apass): Likewise, for apass.
+
+2005-09-22  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/gline.c (gline_checkmask): Add missing digit in mask length
+       check.
+
+2005-09-21  Michael Poole <mdpoole@troilus.org>
+
+       * doc/example.conf: Remove confused and outdated references to
+       Martians.
+
+2005-09-20  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/Makefile.in: Regenerate "make depend" dependencies.
+
+       * ircd/test/Makefile.in: Likewise.
+
+2005-09-16  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/m_join.c (last0): fix problem leading to protocol
+       violations on certain combinations of /join 0 from remote servers
+       (probably from local users, too) [bug #1291029]; remove redundant
+       !IsChannelChar() check
+
+2005-09-14  Michael Poole <mdpoole@troilus.org>
+
+       * doc/readme.cvs: Document the branching scheme for 2.10.12.
+
+2005-09-14  Michael Poole <mdpoole@troilus.org>
+
+       * include/patchlevel.h (PATCHLEVEL): Increment to reflect the
+       pre-release code freeze.
+
+2005-09-14  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/channel.c (find_ban): Fix the sense of another check.
+
+2005-09-13  Michael Poole <mdpoole@troilus.org>
+
+       * include/channel.h (clean_channelname): Remove prototype.
+
+       * ircd/m_invite.c (m_invite): Do not clean channel name; just
+       reject invalid channel names.
+
+       * ircd/m_join.c (m_join): Likewise.
+
+       * ircd/m_mode.c (m_mode): Do not clean channel name.
+
+       * ircd/m_names.c (m_names): Likewise.
+
+       * ircd/m_opmode.c (mo_opmode): Likewise.
+
+2005-09-13  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/channel.c (find_ban): Revert to older style of comparison,
+       fixing the sense of one check.  Spotted by Alex Badea.
+
+2005-09-13  Alex Badea <vamposdecampos@gmail.com>
+
+       * ircd/ircd.c (try_connections): modify autoreconnect logic to
+       allow FEAT_CONNECTFREQUENCY to be smaller than Class connectfreq
+
+2005-09-13  Alex Badea <vamposdecampos@gmail.com>
+
+       * ircd/s_conf.c (close_mappings): NULL out GlobalServiceMapList,
+       otherwise the linked list has an invalid ending sentinel on rehash
+
+2005-09-12  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/channel.c (find_ban): Compare ban mask against hostname
+       even when it looks like an IP, to match things like *!*@1.* when
+       users have a hostname like 1.2.3.example.com.
+
+2005-09-12  Michael Poole <mdpoole@troilus.org>
+
+       * RELEASE.NOTES: Note the resolution of ambiguous ipmasks.
+
+       * ircd/ircd_string.c (ipmask_parse): Implement it.
+
+2005-09-12  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/m_join.c (m_join): If we find an empty key, null out the
+       key pointer.
+
+2005-09-11  Michael Poole <mdpoole@troilus.org>
+
+       * RELEASE.NOTES: Mention the side benefits of this change.
+
+       * include/ircd_string.h (ipmask_parse): Declare function here.
+       (ircd_aton): Becomes a special case of ipmask_parse().
+
+       * include/match.h (check_if_ipmask): Undeclare function.
+       (ipmask_parse): Remove function prototype from this file.
+
+       * ircd/ircd_string.c (ircd_aton_ip4): Add nullable pbits parameter
+       to accept ipmask length.  Rework to fill that in.
+       (ircd_aton): Rework into...
+       (ipmask_parse): this function, which knows how to fill in its own
+       pbits parameter.
+
+       * ircd/m_burst.c (ms_burst): Rely on make_ban() to set the ban
+       flags correctly, to avoid call to check_if_ipmask().
+
+       * ircd/match.c (ipmask_parse_ipv4): Delete function.
+       (check_if_ipmask): Likewise.
+       (ipmask_parse): Delete this version in favor of ircd_string.c's.
+
+       * ircd/test/ircd_in_addr_t.c (ipmask_test): New struct type.
+       (test_masks): New array of ipmask_test.
+       (test_ipmask): Function to run one of those tests.
+       (main): Call test_ipmask().
+
+2005-09-11  Alex Badea <vamposdecampos@gmail.com>
+
+       * ircd/m_ping.c (ms_ping, mo_ping): misplaced chunk of code
+       (probably during the forward port) which broke AsLL; fixed.
+
+2005-09-01  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/gline.c (make_gline): Remove debug output from when IPv6
+       support was being debugged.
+       (do_gline): Likewise.
+       (gline_lookup): Likewise, plus remove redundant code.
+
+2005-09-01  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/channel.c (joinbuf_join): Ignore joinbuf type when joining
+       0, since no other call passes a null channel.
+
+       * ircd/m_join.c: Remove comment discussing argument meanings.
+       (last0): Make this also handle the JOIN 0 logic, doxyfy.
+       (join0): Merge into last0.
+       (m_join): Doxygenate.  Remove check for join0.  Further
+       reorganize, so new versus old channel handling are moved to just
+       one place each within this function.
+       (ms_join): Doxygenate.  Remove check for join0.
+
+2005-09-01  Michael Poole <mdpoole@troilus.org>
+
+       * RELEASE.NOTES: Bump revision date and highlight this change.
+
+       * include/channel.h (MAGIC_OPER_OVERRIDE): Remove.
+       (can_join): Remove declaration.
+
+       * ircd/channel.c (compall): Remove.
+       (can_join): Remove.
+
+       * ircd/m_join.c (m_join): Remove redundant check for control
+       characters (clean_channelname() will get them). Reorganize initial
+       flags calculation.  Accept channel keys like RFC 1459 says; this
+       requires the old compall()/can_join() logic to modify 'keys', so
+       inline the code and reorganize it.
+
+2005-08-30  Michael Poole <mdpoole@troilus.org>
+
+       * include/channel.h (PASSLEN): Remove; use KEYLEN instead.
+
+       * ircd/channel.c (mode_parse_upass): Likewise.
+       (mode_parse_apass): Likewise.
+       The inconsistency (in clean_key()) was reported by Reed.
+
+2005-08-30  Michael Poole <mdpoole@troilus.org>
+
+       * RELEASE.NOTES: Document +D and +d channel modes.
+
+2005-08-29  Michael Poole <mdpoole@troilus.org>
+
+       * include/numeric.h (ERR_NOMANAGER_LONG): Undefine.
+       (ERR_NOMANAGER_SHORT): Rename to ERR_NOMANAGER.
+
+       * ircd/s_err.c (replyTable): Change to reflect that.
+
+       * ircd/channel.c (clean_key): New function.
+       (mode_parse_key): Use it, and check that keys do not start with :.
+       (mode_parse_upass): Likewise, and adjust for ERR_NOMANAGER.
+       (mode_parse_apass): Likewise.
+       The key and password changes fix bugs reported by coekie.
+
+2005-08-27  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/channel.c (add_user_to_channel): Use SetOpLevel() instead
+       of assigning directly to member->oplevel.
+       (mode_parse_apass): Likewise.
+       (mode_process_clients): Users opped by outsiders should get
+       oplevel 1, since they are not channel managers.
+
+       * ircd/m_burst.c (ms_burst): Use SetOpLevel() instead of assigning
+       directly to member->oplevel.
+
+2005-08-25  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/channel.c (member_can_send_to_channel): At coekie's
+       suggestion, disallow channel manager talking after Apass is set,
+       so they set and use Upass sooner.
+
+       * ircd/class.c (init_class): Default class should have 1 link.
+       (report_classes): Return links count minus one to match old output.
+
+       * ircd/m_trace.c (do_trace): Fix links count here, too (spotted by
+       Reed).
+
+2005-08-25  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/channel.c (mode_parse): Accept +A/+U from servers
+       regardless of FEAT_OPLEVELS.
+
+2005-08-24  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/ircd.c (parse_command_line): Mention epoll engine when run
+       with -v.
+
+2005-08-24  Michael Poole <mdpoole@troilus.org>
+
+       * include/patchlevel.h (PATCHLEVEL): Increment.
+
+       * ircd/channel.c (joinbuf_join): Double check that oplevel is 0 or
+       1 when propagating JOIN <level>:#channel, to avoid PV on receiver.
+
+       * ircd/engine_epoll.c: Add system call numbers for more CPU types.
+
+       * ircd/ircd_log.c (log_open): Remove NFS-oriented alarm() calls;
+       anyone who writes logs over NFS is mental.  (Thanks to D. Bruce.)
+
+2005-08-21  Michael Poole <mdpoole@troilus.org>
+
+       * include/s_conf.h (free_mapping): Declare new function.
+
+       * ircd/ircd_parser.y (pseudoblock): Use it.
+
+       * ircd/s_conf.c (free_mapping): Define it.
+       (close_mappings): New function.
+       (rehash): Call close_mappings() before reading file.
+
+       * ircd/m_kill.c (do_kill): Revert 2005-08-18 change.
+
+2005-08-19  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/parse.c (tok_tree): Re-add token tree structure.
+       (initmsgtree): Populate it.
+       (parse_server): Prefer it to full message tree.
+
+2005-08-18  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/m_kill.c (do_kill): When FEAT_HIS_KILLWHO, change apparent
+       source of KILLs to &his instead of &me.
+
+2005-08-16  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/channel.c (mode_parse_ban): Avoid overwriting part of
+       newban->banstr[] when the source is a server.  (Spotted by jcq.)
+
+2005-08-16  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/channel.c (joinbuf_join): Switch to &his instead of &me for
+       announcements to local users in a channel.
+
+       * ircd/m_burst.c (ms_burst): Likewise.
+
+       * ircd/m_invite.c (m_invite): Likewise.
+       (ms_invite): Likewise.
+
+       * ircd/m_kick.c (ms_kick): Likewise.
+
+       * ircd/m_topic.c (do_settopic): Another &me -> &his change for
+       HIS, and use that apparent source for the channel localcast.
+
+2005-08-16  Jukka Ollila <jaollila@niksula.hut.fi>
+
+       * ircd/s_user.c (hide_hostmask): Use HIS_SERVERNAME instead of the
+       real thing for the post-mode-x rejoin.
+
+2005-08-15  Michael Poole <mdpoole@troilus.org>
+
+       * include/supported.h (FEATURESVALUES2): Add +d channel mode.
+
+       * ircd/IPcheck.c (ip_registry_new_entry): Clarify that this is not
+       a varadic function.  (Suggested by Ian Kumlien.)
+
+       * ircd/convert-conf.c (finish_operators): Likewise.
+
+       * ircd/listener.c (close_listeners): Likewise.
+
+       * ircd/channel.c (CheckDelayedJoins): Use HIS server name to
+       remove channel mode +d.
+
+2005-08-12  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/channel.c (pretty_mask): Recognize ':' as unique to the
+       host part of a ban mask.
+
+2005-08-03  Jan Krueger <jast@heapsort.de>
+
+       * ircd/m_kick.c (m_kick): Send JOIN prior to confirming KICK on
+       invisible member.
+
+2005-08-08  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/channel.c (find_ban): For non-IPmask bans, match the ban
+       string against the string form of the client's IP address.
+
+2005-07-16  Michael Poole <mdpoole@troilus.org>
+
+       * configure.in: Apply a test for socklen_t that Reed found.
+
+       * configure: Regenerate.
+
+2005-07-16  Michael Poole <mdpoole@troilus.org>
+
+       * RELEASE.NOTES: Mention that 2.10.11 does not support oplevels.
+
+       * README.FreeBSD: Remove (merged into README).
+
+       * README.Solaris: Remove (merged into README).
+
+       * README: Merge in the above; also update for 2.10.12.
+
+       * doc/example.conf: Change mention of K-lines to say Kill blocks
+       instead.
+
+       * doc/iauth.txt: Remove (out of date).
+
+       * doc/readme.features: Update to reflect that 2.10.11 is not the
+       current release.  Change mention of various config lines to use
+       the equivalent config entries or blocks instead.
+
+       * doc/readme.log: Likewise.
+
+       * doc/api/features.txt: Change F-line mentions to say Feature
+       entry instead.
+
+       * doc/api/modebuf.txt: Change U-line mention to say Uworld entry.
+
+       * doc/api/motd.txt: Change T-line mentions to say Motd entry.
+
+2005-07-15  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/ircd_features.c (feature_init): Always call
+       feature_notify_server*() so that 'his' is initialized.
+
+       * ircd/m_whois.c (do_whois): Unswap sense of comparison to choose
+       between user->server and &his.
+
+2005-07-14  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/channel.c (mode_parse_apass): Update oplevels when setting
+       or removing the +A password.  Partial credit goes to Reed Loden.
+
+2005-07-14  Michael Poole <mdpoole@troilus.org>
+
+       * include/ircd_features.h: Declare new "his" pseudo-server to hold
+       FEAT_HIS_SERVERNAME and FEAT_HIS_SERVERINFO in a convenient place.
+
+       * ircd/ircd_features.c: Initialize and update it.
+
+       * ircd/channel.c (modebuf_flush_int): Use it as the apparent
+       source for opmodes and server mode changes (also when the source
+       is me).
+
+       * ircd/m_burst.c (ms_burst): Use it as the apparent source for net
+       rider kicks.
+
+       * ircd/m_whois.c (do_whois): Use it to simplify code here.
+
+       * ircd/s_misc.c (exit_client): Use it as the apparent killer.
+
+2005-07-14  Michael Poole <mdpoole@troilus.org>
+
+       * doc/example.conf (General): Update comment about vhost to match
+       the code change below.
+
+       * ircd/ircd_parser.y (generalvhost): Accept vhost="*"; as a
+       synonym for the default behavior (for backwards compatibility).
+       Spotted by Kev.
+
+       * ircd/channel.c (sub1_from_channel): Remove stale code and
+       comment, replacing with an up-to-date comment.  Spotted by skx.
+
+2005-07-11  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/engine_select.c: Remove outdated comment about USE_POLL.
+
+       * ircd/parse.c (msgtab): #if out CAP handler until we have caps.
+
+       * RELEASE.NOTES: Remove mention of capabilities for now.
+
+2005-07-11  Stephan Peijnik <speijnik@gmail.com>
+
+       * ircd/gline.c (gline_add): It's only a protocol violation when a
+       server issues a "whacky" gline.  If it's an oper, only tell opers
+       with SNO_GLINE.
+
+       * ircd/ircd_auth.c (iauth_protocol_violation): Likewise, the whole
+       network is not likely to care about IAuth PVs, so only tell opers
+       with SNO_CONNEXIT.
+
+2005-07-11  Michael Poole <mdpoole@troilus.org>
+
+       * doc/readme.features: Document FEAT_CHANNELLEN.
+
+       * doc/example.conf: Give an example of it.
+
+       * ircd/m_join.c (ms_join): Do not clean channel names from remote
+       servers, to avoid desynchs.
+
+       * ircd/m_names.c (ms_names): Likewise.
+
+2005-07-11  Stephan Peijnik <speijnik@gmail.com>
+
+       * include/ircd_features.h: Declare new FEAT_CHANNELLEN.
+
+       * include/supported.h: Add it to the ISUPPORT display.
+
+       * ircd/channel.c (clean_channelname): Impose the lower limit
+       between FEAT_CHANNELLEN and CHANNELLEN.
+
+       * ircd/ircd_features.c: Define FEAT_CHANNELLEN.
+
+2005-07-11  Reed Loden <reed@reedloden.com>
+
+       * include/sys.h: Move FD_SETSIZE redefinition to engine_select.c.
+
+       * ircd/s_bsd.c: Move FD_SETSIZE sanity check to engine_select.c
+       Remove unused #include <sys/poll.h>.
+
+       * ircd/engine_select.c: Put FD_SETSIZE redefinition and sanity
+       checks here, since they are not used elsewhere in the daemon.
+       [Order slightly changed by Michael Poole to compile.]
+
+2005-07-03  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/convert-conf.c: New file.
+
+       * ircd/Makefile: Compile it.
+
+2005-06-27  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/s_bsd.c (add_connection): Split logic for server versus
+       client listeners; only do IPcheck for client connections.
+
+       * ircd/s_serv.c (server_estab): There is no longer a need to
+       remove IPcheck reference, so don't.
+
+2005-06-27  Michael Poole <mdpoole@troilus.org>
+
+       * include/client.h (struct Connection): Remove con_dns_reply (and
+       associated macros).
+
+       * include/res.h (gethost_byname): Change calling signature to
+       clarify memory ownership.
+       (gethost_byaddr): Likewise.
+
+       * include/s_bsd.h (release_dns_reply): Remove function.
+
+       * ircd/hash.c: #include "match.h" to quash warning.
+
+       * ircd/ircd_auth.c (struct IAuth): Remove i_query field.
+       (iauth_dns_callback): Adjust for new gethost_byname signature.
+       (iauth_reconnect): Likewise.
+
+       * ircd/ircd_res.c (struct reslist): Make elements of query field
+       inline rather than in a contained structure.
+       (make_request): Reflect removal of DNSQuery.
+       (do_query_name): Likewise.
+       (do_query_number): Likewise.
+       (make_dnsreply): Remove now-unused function.
+       (timeout_resolver): Adjust to new callback signature.
+       (delete_resolver_queries): Reflect removal of DNSQuery.
+       (gethost_byname): Update to new signature.
+       (gethost_byaddr): Likewise.
+       (res_readreply): Reflect removal of DNSReply.
+
+       * ircd/list.c (dealloc_connection): con_dns_reply no longer
+       exists, so do not free it.
+
+       * ircd/s_auth.c (auth_verify_hostname): constify.
+       (auth_dns_callback): Adjust to new callback signature.
+       (start_auth): Adjust to new gethost_byaddr() signature.
+
+       * ircd/s_bsd.c (connect_dns_callback): Adjust to new callback
+       signature.
+       (release_dns_reply): Remove unused function.
+       (connect_server): Adjust to new gethost_byname() signature.
+
+       * ircd/s_conf.c (conf_dns_callback): Adjust to new callback
+       signature.
+       (conf_dns_lookup): Adjust to new gethost_byname() signature.
+       (attach_iline): Use cli_sockhost() instead of DNS reply.
+       (conf_check_server): Simplify use of DNS results.
+
+       * ircd/s_serv.c (server_estab): Remove call to removed function.
+
+       * ircd/s_user.c (register_user): Remove call to removed function.
+
+2005-06-27  Michael Poole <mdpoole@troilus.org>
+
+       * include/s_misc.h (get_sockhost): Remove the unused (and
+       deceptively named) get_sockhost().
+
+       * ircd/s_misc.c (get_sockhost): Likewise.
+
+2005-06-25  Andrew Miller  <a1kmm@amxl.com>
+
+       * ircd/ircd_crypt.c (ircd_crypt): strdup is not allowed, change to
+       DupStr so memdebug works.
+
+       * doc/debug_memleak_gc.patch : Update to gc6.5
+       
+2005-06-24  Andrew Miller  <a1kmm@amxl.com>
+       * ircd/m_invite.c (m_invite): Don't propagate invites to local channels.
+       
+2005-06-21  Andrew Miller  <a1kmm@amxl.com>
+
+       * ircd/m_list.c (param_parse): Add support for channel wildcards.
+       * ircd/m_list.c (show_usage): Document the new format.
+       * ircd/hash.c (list_next_channels): Check channel wildcard in list.
+       * include/channel.h (ListingArgs): Add the wildcard member.
+
+2005-06-19  Andrew Miller  <a1kmm@amxl.com>
+
+       * ircd/ircd_res.c (proc_answer): Deal with unexpected record types more
+       gracefully.
+
+       * ircd/ircd_res.c (res_readreply): Check res_ourserver before walking
+       the pending request list, to make DoS attacks harder.
+
+       * ircd/m_invite.c (m_invite): Give no such channel rather than not on
+       channel when the channel being invited to does not exist.
+       
+2005-06-18  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/s_debug.c (count_memory): Consolidate several lines; make
+       initial letter capitalization consistent.
+
+2005-06-19  Andrew Miller  <a1kmm@amxl.com>
+
+       * ircd/s_stats.c: Remove the "debug only" label on memusage stats,
+       since it no longer applies.
+
+2005-05-16  Michael Poole <mdpoole@troilus.org>
+
+       * include/channel.h (struct Ban): Make 'who' and 'banstr' direct
+       arrays, rather than pointers.
+
+       * ircd/channel.c (bans_alloc): New variable to count number of ban
+       structures allocated.
+       (bans_inuse): New variable to count number of ban structures
+       currently in use.
+       (set_banmask): Adapt to changes in struct Ban.
+       (make_ban): Likewise, and update ban counts.
+       (free_ban): Likewise.
+       (bans_send_meminfo): New function.
+       (apply_ban): Adapt to changes in struct Ban.
+       (mode_parse_ban): Likewise.
+       (mode_process_bans): Likewise.
+       (mode_parse): Likewise.
+       (RevealDelayedJoin): Fix brace placement.
+       (CheckDelayedJoins): Fix brace placement and whitespace.
+
+       * ircd/list.c (struct liststats): Add new fields to eliminate the
+       separate count variables.
+       (init_list): Adapt to those changes.
+       (alloc_client): Likewise.
+       (dealloc_client): Likewise.
+       (alloc_connection): Likewise.
+       (dealloc_connection): Likewise.
+       (make_server): Likewise.
+       (remove_client_from_list): Likewise.
+       (verify_client_list): Likewise.
+       (make_link): Likewise.
+       (free_link): Likewise.
+       (send_liststats): New function.
+       (send_listinfo): Rewrite to use new struct liststats layout.
+
+       * ircd/m_burst.c (ms_burst): Adapt to changes in struct Ban.
+
+       * ircd/m_clearmode.c (do_clearmode): Adapt to changes in struct
+       Ban.
+
+       * ircd/s_stats.c (stats_meminfo): Define unconditionally and call
+       bans_send_meminfo().
+       (statsinfo): Always give access to stats_meminfo.
+
+2005-06-16  Michael Poole <mdpoole@troilus.org>
+
+       * include/ircd_string.h: Include necessary <string.h> header.
+
+       * ircd/test/.cvsignore: Ignore log output files.
+
+       * ircd/test/Makefile.in: Remove log output files.
+
+       * ircd/test/kill-block-1.cmd: Add sleeps to try to trigger Kills.
+
+       * ircd/test/run-tests.sh: Switch sense of argument.  Send an IRC
+       debug dump to log files.
+
+2005-06-13  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/s_user.c (make_user): Unconditionally increment userCount.
+       (free_user): Unconditionally decrement it here.
+
+       * ircd/s_conf.c (make_conf): Unconditionally increment
+       GlobalConfCount.
+       (free_conf): Unconditionally decrement it here.
+
+       * ircd/s_debug.c (count_memory): Fix termination condition for
+       ban-walking loop.  Add missing "e" to "members".
+
+
+2005-06-10  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/match.c (check_if_ipmask): Strings that contain '?' cannot
+       be true IP masks.
+
+2005-05-30  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/test/Makefile.in: Add LDFLAGS variable for profiling purposes.
+
+       * ircd/test/ircd_match_t.c: Test recovery from backtracking.
+
+       * ircd/test/channel-1.cmd: Modify to improve code coverage.
+
+       * ircd/test/client-1.cmd: Likewise.
+
+       * ircd/test/gline-1.cmd: Likewise.
+
+       * ircd/test/ircd-t1.conf: Likewise.
+
+       * ircd/test/stats-1.cmd: Likewise.
+
+       * ircd/test/run-tests.sh: Explicitly start ircds.  Add new test scripts.
+
+       * ircd/test/test-driver.pl: Silently handle more signals from IRC.
+
+       * ircd/test/commands-1.cmd: New test script.
+
+       * ircd/test/feature-1.cmd: New test script.
+
+       * ircd/test/jupe-1.cmd: New test script.
+
+       * ircd/test/kill-block-1.cmd: New test script.
+
+       * ircd/test/ircd-t1-2.conf: New configuration file for test scripts.
+
+       * ircd/test/ircd-t2.conf: Likewise.
+
+2005-05-30  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/s_debug.c (count_memory): Use count_listener_memory() to
+       report memory used by listener structures.
+
+2005-05-30  Michael Poole <mdpoole@troilus.org>
+
+       * include/class.h (get_con_freq): Remove unused function.
+
+       * include/list.h (find_user_link): Remove unused function.
+
+       * include/class.c (get_con_freq): Remove.
+
+       * ircd/list.c (find_user_link): Remove.
+
+       * include/string.h (string_is_hostname, string_is_address,
+       strnChattr): Remove unused functions.
+       (init_string): Remove function that becomes a noop.
+
+       * ircd/string.h (init_string): Remove.
+       (string_is_hostname, string_is_address, strnChattr): Likewise.
+
+       * ircd/ircd.c (main): Remove call to init_string().
+
+2005-05-30  Michael Poole <mdpoole@troilus.org>
+
+       * include/numeric.h (RPL_TRACELOG, RPL_MYPORTIS,
+       RPL_NOTOPERANYMORE): Undefine unused numeric replies.
+
+       * ircd/s_err.c (replyTable): Fix format fields for certain numeric
+       arguments.  Remove some unused entries.
+
+       * ircd/s_stats.c (stats_configured_links): Move invariant
+       parameters to message format string.
+
+2005-05-30  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/client.c (privtab): Add missing LIST_CHAN privilege, move
+       WIDE_GLINE to reflect its enumerated value.
+
+       * ircd/s_debug.c (count_memory): Use user_count_memory() function
+       to count User structs in-use.
+
+       * ircd/m_server.c (mr_server): Change "C:line" to "Connect block".
+
+       * ircd/s_bsd.c (connect_server): Likewise.
+
+       * ircd/s_conf.c (conf_check_server): Likewise.
+
+       * ircd/s_err.c (replyTable): Change "O-lines" to "Operator block".
+
+2005-05-30  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/match.c (match): Rewrite to handle globs that end in an
+       escaped wildcard (and hopefully clarify the code).
+
+       * ircd/test/Makefile.in: Add new ircd_match_t test program.
+
+       * ircd/test/ircd_match_t.c: New file.
+
+       * ircd/test/test_stub.c: Emite newlines after log and debug
+       messages.
+
+2005-05-25  Reed Loden <reed@reedloden.com>
+
+       * ircd/s_err.c (replyTable): Allow for the specification of 'O' or
+       'o' in RPL_STATSOLINE.
+
+       * ircd/s_stats.c (stats_configured_links): In /stats o/O, display
+       'O' if either the oper block or the connection class has
+       PRIV_PROPAGATE (global oper) and 'o' if neither has PRIV_PROPAGATE
+       (local oper).
+
+2005-05-30  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/IPcheck.c: Add Debug()s to try to track why the connected
+       count underflows.
+
+       * ircd/m_endburst.c (ms_endofburst): Avoid dereferencing 'chan'
+       after it may be freed (in sub1_from_channel).
+
+       * ircd/s_user.c (register_user): Rearrange code to reduce number
+       of "if (MyConnect(sptr))" checks.
+
+2005-05-12  Michael Poole <mdpoole@troilus.org>
+
+       * configure.in: Do not try to outsmart the default CFLAGS.
+       Simply add parameters explicitly requested by the user.
+
+       * configure: Regenerate.
+
+       * ircd/ircd_crypt_native.c: Use _XOPEN_SOURCE 600 (which is
+       used in os_generic.c) to get crypt() on NetBSD.
+
+2005-05-11  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/ircd.c: if debugging is enabled (both DEBUGMODE defined and
+       -x given), reserve fd 2 for the use of the debugging log;
+       otherwise, some engines may attempt to use fd 2, which would end
+       up getting closed by debug_init() (actually, by
+       log_debug_reopen(), called by log_debug_init(), called by
+       debug_init())
+
+2005-08-10  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/channel.c (joinbuf_join): Do not send a MODE +o when a
+       local user creates a channel.
+
+       * ircd/umkpasswd.c (crypt_pass): Allocate the proper amount of
+       memory for the tagged output string.
+
+       * ircd/test/test-driver.pl: Add -vhost=... option.
+
+       * ircd/test/ircd-t1.conf: Add new Operator blocks.
+
+       * ircd/test/*.cmd: Rearrange and add more coverage tests.
+
+2005-08-09  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/ircd_parser.y: Move error tokens to top level of parse, and
+       make ';' a synchronizing token for them.  This avoids crashes in
+       situations like missing ';' between two Kill blocks.  Move several
+       ';'s earlier for earlier detection of syntax errors.
+
+       * ircd/motd.c (motd_memory_count): Use size_t for memory counts to
+       match the format strings used for those variables.
+
+       * ircd/msgq.c (msgq_histogram): tmp.sizes[] is an array of
+       unsigned int, not unsigned long; use correct format string.
+
+       * ircd/s_stats.c (stats_crule_list): Restore display of 'D' vs 'd'
+       based on crule type, rather than query type.
+       (statsinfo): Remove STAT_FLAG_VARPARAM from the "modules" and
+       "help" stats, which don't use the varparam.
+
+       * ircd/test/test-driver.pl: Interpreter for test scripts.b
+
+       * ircd/test/ircd-t1.conf: Configuration file for test scripts.
+
+       * ircd/test/*.cmd: New test scripts for test-driver.pl.
+
+2005-05-08  Jukka Ollila <jaollila@niksula.hut.fi>
+       (Adapted slightly by Michael Poole.)
+
+       * ircd/os_generic.c (sockaddr_to_irc): Change to use v4compat
+       addresses event when !defined(IPV6).
+
+2005-05-07  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/channel.c (joinbuf_join): Be smarter about what source to
+       use when opping a user that joins a channel.
+
+2005-05-04  Reed Loden <reed@reedloden.com>
+
+       * ircd/m_trace.c (do_trace): Show the real nickname instead of the
+       numnick.
+
+2005-05-02  Jan Krueger <jast@heapsort.de>
+
+       * ircd/channel.c (member_can_send_to_channel): if the channel can only
+       be joined by users with accounts (+r), do not allow users without
+       accounts to speak.
+
+2005-05-07  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/numnicks.c (base64toip): Fix bugs in parsing IPv6
+       addresses.
+       * ircd/test/ircd_in_addr_t.c (test_addrs): Add new entry.
+       (test_address): Test base64toip() as well.
+
+2005-05-05  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/s_user.c (umode_str): Only clear the operator flag when not
+       propagating; never set it.
+
+2005-05-04  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/channel.c (joinbuf_join): Include channel manager flag in
+       determination of oplevel.  If opping the user for a non-local
+       non-create, include oplevel in message to other servers.  Send
+       "MODE +o <client>" to local users whenever opping the client.
+
+       * ircd/m_join.c (m_join): Remove logic that moved into
+       joinbuf_join().
+       (ms_join): Look for level 0 and 1 joins from remote servers
+       and adjust value of 'flags' appropriately.
+
+2005-05-04  Michael Poole <mdpoole@troilus.org>
+
+       * include/numeric.h: Remap oplevel numerics to new range.
+
+       * ircd/s_err.c: Likewise.
+
+2005-05-03  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/s_stats.c (stats_access): Update to use new CONF_CLIENT
+       fields, fixing crash found by nighty.
+
+2005-05-02  Michael Poole <mdpoole@troilus.org>
+
+       * include/numeric.h (ERR_UPASS_SAME_APASS): New error message when
+       trying to set +U pass to the same as the +A pass.
+
+       * ircd/channel.c (mode_parse_upass): Use it.
+
+       * ircd/ircd_auth.c (iauth_exit_client): Only send ExitUser if
+       there is an active IAuth connection, fixing PR#1193808.
+       (iauth_dispose_request): Only delete the timer if it is active.
+
+       * ircd/m_invite.c (m_invite): Always forward the invite in the
+       correct direction, and then skip it as 'one' if announcing.
+       (ms_invite): Likewise.
+
+       * ircd/numnicks.c (base64toip): Do not interpret AAAAAA as
+       ::ffff:0.0.0.0; keep it as ::.
+
+       * ircd/s_err.c (replyTable): Add ERR_UPASS_SAME_APASS.
+
+2005-05-01  Michael Poole <mdpoole@troilus.org>
+
+       * doc/readme.log: Document IAUTH log target, remove docs for
+       OLDLOG log target.
+
+       * include/ircd_log.h: Add LS_IAUTH target, remove LS_OLDLOG.
+
+       * ircd/ircd_log.c (logDesc): Likewise.
+
+       * ircd/engine_epoll.c (engine_loop): Handle EPOLLHUP for all
+       sockets (e.g. when connecting) and do not generate read/write
+       events in the same pass as error or EOF events.
+
+       * ircd/ircd_auth.c: Convert old sendto and debug messages to use
+       the LS_IAUTH log target.  Consistently use IAUTH_CONNECTED flag
+       instead of comparing fd to -1.
+       (iauth_reconnect): If already connected, disconnect and schedule a
+       reconnect later, since an immediate reconnect can cause assertion
+       failure in the event engine.  Also schedule a reconnect when the
+       connection attempt fails.
+       (iauth_read): Reconnect on IO_FAILURE.
+       (iauth_sock_callback): Disconnect and schedule a reconnect on both
+       error (after reporting the error) and EOF.
+       (iauth_start_client): Record the IAuth request in the client.
+       (iauth_exit_client): Report the client exit.
+
+       * ircd/s_misc.c (exit_one_client): Fix formatting.
+
+2005-04-30  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/ircd_auth.c (iauth_connect): Initialize (but do not add)
+       timer here and set fd to -1.
+       (iauth_schedule_reconnect): Rewrite to handle previously
+       initialized timer.
+       (iauth_reconnect): If server is connected, disconnect first.
+       Update socket generator fd before calling socket_add().
+       (iauth_read): When reading 0 bytes (EOF), reconnect.
+
+2005-04-27  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/ircd_parser.y: Report non-existent class names as errors
+       earlier, and do not fall back to "default" for Client blocks.
+
+2005-04-25  Reed Loden  <reed@reedloden.com>
+
+       * ircd/ircd_lexer.l: Add missing header to squash a warning.
+
+2005-04-25  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/s_user.c (register_user): Replace call with set_user_mode()
+       with a direct parsing of user modes.  To match this, revert the
+       initial display of usermode to how it was done before.
+
+2005-04-24  Michael Poole <mdpoole@troilus.org>
+
+       * doc/example.conf: Document new autoconnect field of Connect.
+
+       * include/s_conf.h: Add CONF_AUTOCONNECT and field for it.
+
+       * ircd/ircd.c (try_connections): Skip non-autoconnect servers.
+
+       * ircd/ircd_lexer.l: Recognize autoconnect token.
+
+       * ircd/ircd_parser.y: Add autoconnect= option to Connect block.
+
+       * ircd/m_invite.c (m_invite): Avoid sending channel timestamp to
+       user being invited.
+       (ms_invite): Likewise.
+
+       * ircd/s_user.c (register_user): Show class name rather than
+       pointer-as-integer.
+
+2005-04-24  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/ircd_parser.y: Rewrite so each error condition gets its own
+       error message, and so that invalid parameters are printed out.
+
+2005-04-23  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/channel.c (apply_ban): Consistently free newban->banstr
+       when the function fails.
+       (mode_process_bans): Free banstr for all BAN_DEL bans.
+
+       * ircd/ircd_parser.y: Fix a few memory leaks from previous commit.
+
+2005-04-23  Michael Poole <mdpoole@troilus.org>
+
+       * include/patchlevel.h: Bump to being a beta.
+
+       * ircd/ircd_lexer.l (QSTRING): Return a copy of the string so that
+       parser actions don't have to be immediately after a QSTRING.
+
+       * ircd/ircd_parser.y (FNAME): Remove unused token.
+       (QSTRING): Adjust for QSTRING being an already-copied version.
+
+2005-04-23  Michael Poole <mdpoole@troilus.org>
+
+       * doc/example.conf (UWorld): Illustrate new config extension.
+
+       * ircd/ircd_parser.y (uworldblock): Do the expected thing when
+       multiple name= entries are present.
+
+2005-04-22  Michael Poole <mdpoole@troilus.org>
+
+       * RELEASE.NOTES: Silence exceptions use ~, not -.  Oops!
+
+       * doc/example.conf: Fix typo in example Kill block.
+
+       * ircd/channel.c (mode_parse_ban): Use correct test for flag_p.
+
+       * ircd/m_silence.c (apply_silence): Make mask pretty so that later
+       processing does not convert * to @ (and match no one).
+
+2005-04-21  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/m_userip.c (userip_formatter): /userip should *never*
+       report the user's real IP unless its answering the user
+       him/herself
+
+       * ircd/m_userhost.c (userhost_formatter): /userhost should *never*
+       report the user's real host unless its answering the user
+       him/herself
+
+2005-04-20  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/ircd.c (parse_command_line): Update usage text.
+
+       * ircd/numnicks.c (base64toip): Use v4mapped address range instead
+       of v4compat address range, fixing IPv4-based /who.
+
+2005-04-19  Michael Poole <mdpoole@troilus.org>
+
+       * configure.in: When --enable-profile, add -pg to LDFLAGS.
+
+       * configure: Regenerate.
+
+2005-04-19  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/match.c (check_if_ipmask): Fix brown-paper-bag typo.
+
+       * ircd/s_conf.c (conf_debug_iline): Look for matching Kill blocks
+       once a matching Client block is found.
+
+       * ircd/m_whowas.c (m_whowas): Change strcmp() to ircd_strcmp().
+
+2005-04-18  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/match.c (check_if_ipmask): Do not interpret masks that
+       start with . or / as IP-based host masks.
+
+2005-04-17  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/channel.c (mode_process_clients): Only prohibit deops of
+       users with the same or higher oplevel where apass is set.
+       Likewise, when opping users, give them MAXOPLEVEL for non-apass
+       channels.
+       (joinbuf_join): Give new ops MAXOPLEVEL for non-apass channels.
+
+       * ircd/m_kick.c (m_kick): Only prohibit kicks of users with the
+       same or higher oplevel where apass is set.
+
+       * ircd/s_user.c (register_user): Fix order of server version vs
+       various mode strings.
+
+       * tools/linesync/linesync.sh: Add revision id field.
+
+2005-04-17  Michael Poole <mdpoole@troilus.org>
+
+       * tools/linesync/linesync.sh: Fix typo comment.  Check for
+       multiple blocks per line in the linesync input.
+
+2005-04-17  Dan <daniel@undernet.org>
+
+       * tools/linesync/linesync.sh: Update to support new syntax and to
+       avoid rehashing the ircd when the config is the same.
+
+       * tools/linesync/linesync.conf: Update allowed conf items.
+
+2005-04-16  Michael Poole <mdpoole@troilus.org>
+
+       * doc/example.conf (Kill): Document newly supported syntax.
+
+       * include/s_conf.h (DenyConf): Split realname mask into its own
+       field.  Remove the unused DENY_FLAGS_{IP,REALNAME}.
+
+       * ircd/ircd_parser.y (Kill): Only require one of usermask,
+       hostmask, realmask to be set for a valid block.
+       (killitem): Add new production killusername.
+
+       * ircd/s_conf.c (conf_erase_deny_list): Free realmask field.
+       (find_kill): Rearrange slightly to clarify control flow.
+
+       * ircd/s_err.c (RPL_STATSKLINE): Stick usermask before hostmask,
+       so the old usermask field can be adopted for realname mask.  Add
+       double quotes around the realmask field.
+
+       * ircd/s_stats.c (report_deny_list): Do so.
+       (stats_klines): Likewise.
+
+2005-04-17  Perry Lorier <isomer@undernet.org>
+       
+       * tools/convert-conf.py: Fix lots of conversion problems with
+       oper privielges (now they are converted), 
+       features (deprecated features commented out, most converted to
+       priviliges), 
+       realname klines (also add host= lines)
+       quarintines (generate blocks for them), 
+       connect blocks (don't generate empty port config lines)
+       etc...
+
+2005-04-16  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/gline.c (do_gline): Fix typo when activating IP-based
+       G-lines.
+
+2005-04-16  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/class.c (free_class): Free default_umode field.
+
+       * ircd/ircd_parser.y (classblock): Free default_umode field before
+       overwriting it.
+
+       * ircd/s_conf.c (free_conf): Free username, origin_name, hub_limit
+       fields.
+       (find_kill): Realname Kill blocks no longer have $R at the start,
+       so do not skip over the first two characters of the mask.
+
+2005-04-15  Michael Poole <mdpoole@troilus.org>
+
+       * doc/example.conf (Operator): Properly qualify plaintext password.
+       (Quarantine): Document (new) syntax.
+
+       * ircd/ircd.c: Add <sys/time.h> to make <sys/resource.h> compile
+       correctly on BSDs.
+
+       * ircd/ircd_parser.y (qconf): Remove global variable.
+       (killuhost): Null terminate username when present.
+       (quarantineblock): Replace with a syntax that works.
+
+       * ircd/s_stats.c: #include <querycmds.h> for UserStats.
+       (stats_server_verbose): Reinstate check for UserStats.
+
+2005-04-09  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/ircd.c: conditionally include sys/resource.h; otherwise,
+       RLIMIT_CORE will not be defined and so set_core_limit() will never
+       be defined, much less run.
+
+       * configure.in: add sys/resource.h to the list of headers to
+       search for
+
+       * configure: regenerate configure
+
+       * config.h.in: rerun autoheader to add HAVE_SYS_RESOURCE_H to
+       config.h.in
+
+2005-04-08  Michael Poole <mdpoole@troilus.org>
+
+       * include/s_conf.h (conf_debug_iline): Declare new function.
+
+       * ircd/ircd.c (dbg_client): New file-scoped variable.
+       (parse_command_line): Set it from the new -c option.
+       (main): If dbg_client is set during chkconf, use it.
+
+       * ircd/ircd_string.c (ircd_aton): Generate IPv4-mapped addresses,
+       not IPv4-compatible addresses, to match ipmask_parse().
+
+       * ircd/m_whowas.c (m_whowas): Split display of real host to a
+       separate line, in hopes of not confusing opers in the future.
+
+       * ircd/s_conf.c (conf_debug_iline): Implement new function.
+
+2005-04-06  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/m_burst.c (ms_burst): Clear channel manager bit when wiping
+       out locally opped and voiced channel members.
+
+2005-04-06  Michael Poole <mdpoole@troilus.org>
+
+       * include/numeric.h (RPL_APASSWARN): Replace with three distinct
+       values.
+       (ERR_NOMANAGER_LONG): Assign new numeric.
+       (ERR_NOMANAGER_SHORT): Assign new numeric.
+
+       * ircd/channel.c (parse_mode_upass): Adapt to new formats for
+       ERR_NOTMANAGER separation.
+       (parse_mode_apass): Likewise.  Also adapt to RPL_APASSWARN split.
+
+       * ircd/s_err.c (RPL_APASSWARN): Replace with three message
+       strings, to avoid embedding long message strings in the logic
+       implementation.
+       (ERR_NOTMANAGER): Likewise (but not the same strings).
+
+2005-04-06  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/ircd_parser.y (clientblock): Use the password field.
+
+       * ircd/s_user.c (register_user): Allow aconf->password to be a
+       single digit, since per-IP limit is now in a separate field.
+
+2005-04-06  Michael Poole <mdpoole@troilus.org>
+
+       * acinclude.m4 (unet_PIPE_CFLAGS): Remove; -pipe is obsolete in
+       current gcc releases and is slower than files for previous
+       releases on most OSes.
+
+       * configure.in (AC_PREREQ): Bump to 2.59 because of AS_HELP_STRING.
+       (unet_PIPE_CFLAGS): Remove use of macro.
+
+       * aclocal.m4: Regenerate.
+
+       * configure: Likewise.
+
+2005-04-04  Michael Poole <mdpoole@troilus.org>
+
+       * configure.in: For developers' ease, allow passing an option to
+       configure to persistently set optimization CFLAGS.
+
+       * configure: Regenerate.
+
+2005-04-04  Michael Poole <mdpoole@troilus.org>
+
+       * doc/example.conf (Jupe): Make the default Jupe block follow
+       CFV-0255.  (Thanks to FrankP for pointing me at this and to DinTn
+       for getting me a copy of the CFV.)
+
+2005-04-04  Michael Poole <mdpoole@troilus.org>
+
+       * include/capab.h (CAPFL_STICKY): Define.
+       (CAPLIST): Remove the entries used for testing.
+
+       * include/client.h (Connection): Clarify comment about the
+       distinction between con_capab and con_active.
+
+       * ircd/m_cap.c: Add doxygen comments and replace the long
+       discussion of m_handler functions with an xref to it.
+       (send_caplist): Add new parameters and change the terminal vs
+       non-terminal line distinction to make compliant with current draft
+       specification.
+       (cap_empty): Rename to cap_ls().
+       (cap_req): Track modified capabilities bitwise, so that the
+       responding ACK contains all the appropriate flags.
+       (cap_ack): Add comment explaining why there is no response.
+       (cap_clear): Build and send a list of cleared capabilities, as
+       required by the current draft.
+       (cap_list): Send capability list using LIST subcommand.
+       (cmdlist): Add handler for LS subcommand.  Remove entries for the
+       empty and LSL subcommands, which are no longer allowed.
+       (m_cap): Require at least one argument from user.
+
+2005-04-01  Michael Poole <mdpoole@troilus.org>
+
+       * include/s_conf.h (SMAP_FAST): Define.
+       (s_map): Add 'flags' field.
+
+       * ircd/ircd_lexer.l: Recognize 'FAST' token.
+
+       * ircd/ircd_parser.y (FAST): New token.
+       (pseudoitem): Add pseudoflags alternative.
+       (pseudoflags): New production, recognizing FAST token.
+
+       * ircd/parse.c (register_mapping): Set MFLG_SLOW conditionally.
+       Remove outdated comment.
+
+2005-04-01  Michael Poole <mdpoole@troilus.org>
+
+       * include/handlers.h (ms_privs): Declare.
+
+       * include/msg.h (TOK_PRIVS): Assign token.
+       (CMD_PRIVS): Define.
+
+       * ircd/m_privs.c: Add doxygen comments and replace the long
+       discussion of m_handler functions with an xref to it.
+       (mo_privs): Forward requests for non-local users
+       to their own server.
+       (ms_privs): Implement.
+
+       * ircd/parse.c (PRIVS): Dispatch to ms_privs when a server sends
+       the message.
+
+2005-03-30  Michael Poole <mdpoole@troilus.org>
+
+       * include/client.h (struct Client): Explain where cli_username
+       comes from.
+
+       * include/struct.h (struct User): Explain where this username
+       comes from, too
+
+       * ircd/ircd_res.c (timeout_resolver): Update parameter name in
+       Doxygen comment, too.
+
+       * ircd/s_misc.c (get_client_name): Reorganize to have less
+       indentation and behave like 2.10.11 when client is not idented.
+
+2005-03-29  Michael Poole <mdpoole@troilus.org>
+
+       * doc/example.conf: Remove no-longer-used HIS_STATS_h.
+
+       * doc/readme.features: Likewise.
+
+       * include/ircd_features.h: Likewise.
+
+       * ircd/ircd_features.c: Likewise.
+
+2005-03-20  Reed Loden <reed@reedloden.com>
+
+       * include/ircd_features.h: Alphabetize HIS_STATS_? features.
+
+       * ircd/ircd_features.c: Likewise.
+
+2005-03-29  Michael Poole <mdpoole@troilus.org>
+       (The previously unapplied part of another patch (by Carlo Wood?).)
+
+       * ircd/m_part.c (ms_part): Remove a check that should already be
+       done by the user's own server.
+
+2005-03-29  Michael Poole <mdpoole@troilus.org>
+
+       * doc/example.conf: Add HIS_STATS_J entry.
+
+       * doc/readme.features: Likewise.
+
+2005-03-25  Reed Loden <reed@reedloden.com>
+
+       * include/hash.h: Add needed prototypes for new
+       stats_nickjupes() function.
+
+       * include/ircd_features.h: Add FEAT_HIS_STATS_J.
+
+       * include/numeric.h: Add RPL_STATSJLINE (222) for new nick
+       jupes stats. Correct a typo in a comment.
+
+       * ircd/hash.c: Add stats_nickjupes() function to report all
+       nick jupes to an oper. Because of the nature of hash tables,
+       there is no way to sort this list so the results look weird.
+
+       * ircd/ircd_features.c: Add FEAT_HIS_STATS_J (default: TRUE).
+
+       * ircd/s_err.c: Add RPL_STATSJLINE (222) for new nick jupes
+       stats.
+
+       * ircd/s_stats.c: Add RPL_STATSJLINE (222) for new nick jupes
+       stats. Make 'j' case sensitive. Modify the comment for stats
+       uworld.
+
+2005-03-27  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/m_burst.c (ms_burst): Do not send numeric oplevels in a -A
+       channel when forwarding a channel burst line.
+
+2005-03-25  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/m_server.c (set_server_flags): New function.  Unlike the
+       old code, this recognizes the IPv6 flag.  (Spotted by Reed.)
+       (mr_server): Use the new function.
+       (ms_server): Likewise.  Also don't show "Net junction:" message if
+       any closer server is still bursting (also spotted by Reed).
+       Finally, forward the +6 flag to other servers.
+
+       * ircd/s_serv.c (server_estab): Forward the +6 flag here, too.
+
+       * ircd/s_bsd.c (client_sock_callback): Re-set cli_error() after it
+       may be cleared by completed_connection().
+
+2005-03-23  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/m_burst.c (ms_burst): Remove limit and keys when a channel
+       is wiped out during burst.
+
+2005-03-22  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/ircd_res.c (check_resolver_timeout): I give up.  Use the
+       kludgy earlier version of the timeout fix.
+
+2005-03-22  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/channel.c (send_channel_modes): Fix test for when to send
+       membership mode suffix, to avoid sending it more than once.
+
+2005-03-22  Michael Poole <mdpoole@troilus.org>
+       (Many thanks to nex and Reed for helping hunt this down and
+       doing the testing of various patches.)
+
+       * ircd/ircd_events.c (timer_chg): Properly change a timer that is
+       in the middle of executing its expiration event.
+
+       * ircd/ircd_res.c (check_resolver_timeout): Simplify the test for
+       whether to use timer_chg() or timer_add().
+       On second thought, use timer_add() unconditionally; the server
+       connection loop does.
+       (timeout_resolver): Do not try to re-schedule the DNS timeout
+       unless it is the expiration event.
+       (do_query_number): Properly initialize request->state.
+       (res_readreply): Mention the response code that was bad.
+
+2005-03-22  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/engine_kqueue.c (engine_delete): The kernel removes
+       close()'d FDs from the activity list, so don't try to remove the
+       FD here (the caller may have already close()'d it).
+
+2005-03-20  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/IPcheck.c: Fix typos in comments and strings to reduce
+       future slumming for credit.
+
+       * ircd/channel.c, ircd/crule.c, ircd/engine_epoll.c: Likewise.
+       * ircd/fileio.c, ircd/hash.c, ircd/ircd.c: Likewise.
+       * ircd/ircd_auth.c, ircd/ircd_crypt.c: Likewise.
+       * ircd/ircd_crypt_native.c, ircd/ircd_crypt_smd5.c: Likewise.
+       * ircd/ircd_features.c, ircd/ircd_log.c: Likewise.
+       * ircd/ircd_parser.y, ircd/ircd_res.c: Likewise.
+       * ircd/ircd_reslib.c, ircd/ircd_string.c, ircd/list.c: Likewise.
+       * ircd/m_burst.c, ircd/m_clearmode.c, ircd/m_destruct.c: Likewise.
+       * ircd/m_invite.c, ircd/m_ison.c, ircd/m_kill.c: Likewise.
+       * ircd/m_server.c, ircd/m_squit.c, ircd/m_topic.c: Likewise.
+       * ircd/m_who.c, ircd/m_whois.c, ircd/m_whowas.c: Likewise.
+       * ircd/match.c, ircd/msgq.c, ircd/numnicks.c: Likewise.
+       * ircd/os_generic.c, ircd/parse.c, ircd/s_auth.c: Likewise.
+       * ircd/s_bsd.c, ircd/s_conf.c, ircd/s_debug.c: Likewise.
+       * ircd/s_misc.c, ircd/s_numeric.c, ircd/s_serv.c: Likewise.
+       * ircd/s_stats.c, ircd/s_user.c, ircd/table_gen.c: Likewise.
+       * ircd/umkpasswd.c, ircd/uping.c, ircd/whowas.c: Likewise.
+
+       * ircd/test/test_stub.c: Make exit_client() argument list
+       consistent with that in s_misc.c so doxygen is not confused.
+
+2005-03-20  Michael Poole <mdpoole@troilus.org>
+       (Thanks to Reed Loden for pointing these out.)
+
+       * ircd/channel.c: Fix typos in comments.
+
+       * ircd/m_create.c: Likewise.
+
+       * ircd/m_list.c: Likewise.
+
+       * ircd/m_names.c: Likewise.
+
+       * ircd/numnicks.c: Likewise.
+
+       * ircd/s_bsd.c: Likewise.
+
+2005-03-20  Michael Poole <mdpoole@troilus.org>
+       (Thanks to Reed Loden for pointing these out.)
+
+       * doc/Configure.help: Remove outdated file.
+
+       * doc/exaconf.2: Likewise.
+
+       * doc/snomask.html: Add missing <tr>, SNO_AUTO, SNO_DEBUG, and
+       update SNO_OPERDEFAULT list.
+
+       * tools/mkpasswd.c: Remove outdated file (use ircd/umkpasswd
+       instead).
+
+       * tools/Makefile.crypt: Remove outdated file.
+
+       * tools/mkpasswd.c: Likewise.
+
+       * tools/transition: Likewise.
+
+2005-03-19  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/channel.c (sub1_from_channel): Check apass rather than mode
+       to determine whether an apass is set (MODE_KEY/APASS/UPASS are not
+       set in mode.mode).
+       (send_channel_modes): Use the same change when determining how to
+       send oplevels for channels.
+
+2005-03-19  Michael Poole <mdpoole@troilus.org>
+
+       * include/IPcheck.h (IPcheck_connect_fail): Take a Client
+       parameter instead of irc_in_addr.
+
+       * ircd/IPcheck.c (IPcheck_connect_fail): Likewise.  Assert that
+       the client has been IP-checked.
+       (IPcheck_remote_connect): Assert that the client has not yet been
+       charged for connecting.
+       (IPcheck_connect_succeeded): Assert that the client has been
+       charged for connecting.
+       (IPcheck_disconnect): Likewise.
+
+       * ircd/m_nick.c (m_nick): Pass rejected client to
+       IPcheck_connect_fail() when somebody takes the nick first.
+       (ms_nick): Likewise.
+
+       * ircd/s_serv.c (server_estab): Pass new server to
+       IPcheck_connect_fail().
+
+       * ircd/s_user.c (register_user): When rejecting a user, pass
+       the struct Client to IPcheck_connect_fail().
+
+2005-03-19  Michael Poole <mdpoole@troilus.org>
+
+       * doc/example.conf (Connect): Remove a buggy comment about leaf
+       directives; refer the reader to the Connect block instead.
+
+       * tools/convert-conf.py: Set "leaf;" rather than "leaf = yes;"
+
+2005-03-19  Michael Poole <mdpoole@troilus.org>
+
+       * doc/example.conf (Operator): Correct the comment explaining
+       hashed passwords.
+
+       * ircd/m_oper.c (oper_password_match): Check correct variable to
+       determine whether the hashed password matched.
+
+2005-03-08  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/match.c (ipmask_parse): Explicitly zero-initialize the mask
+       and bit count for "*".
+       (ipmask_check): Make more robust to similar errors.
+
+2005-03-07  Michael Poole <mdpoole@troilus.org>
+
+       * configure.in: Consistently use a constant in AC_DEFINE().
+
+       * configure: Regenerate.
+
+       * doc/example.conf (Port): Add comment about the mask option.
+       (Port): Fix the vhosted Port example.
+
+       * ircd/ircd_parser.y (clientblock): Correctly initialize the IP
+       address and addrbits for a Client block with no IP mask.
+
+       * ircd/match.c (ipmask_parse): Accept * as a zero-bit mask.
+
+       * ircd/s_auth.c (start_auth_query): Count socket allocation
+       failure as a failed auth check, as .11 does.
+
+       * ircd/s_debug.c (debug_serveropts): Add '6' to server options
+       when compiled with IPv6 support.
+
+2005-02-23  Michael Poole <mdpoole@troilus.org>
+
+       * doc/example.conf: Explain apass_opmode privilege, pointing out
+       that, unlike previous privs, the default is OFF for global opers.
+
+       * include/client.h (PRIV_APASS_OPMODE): Define new privilege.
+
+       * ircd/channel.c (mode_parse_upass): Only prevent local opers
+       without the apass_opmode privilege from forcing a +U change.
+       (mode_parse_apass): Likewise, for +A.
+
+       * ircd/client.c (client_set_privs): Turn off PRIV_APASS_OPMODE in
+       the default privileges for global opers.
+
+       * ircd/ircd_lexer.l (apass_opmode): Recognize keyword.
+
+       * ircd/ircd_parser.y (TPRIV_APASS_OPMODE): New token.
+       (privtype): Fix typo for local_badchan privilege value.
+       Accept apass_opmode token.
+
+2005-02-23  Michael Poole <mdpoole@troilus.org>
+
+       * doc/example.conf: Fix comment's description of "whox" privilege.
+
+2005-02-21  Michael Poole <mdpoole@troilus.org>
+
+       * include/channel.h (ShowChannel): Remove PRIV_LIST_CHAN check
+       from here, so /whois does not show secret global channels.
+
+       * ircd/m_list.c (param_parse): Require PRIV_LIST_CHAN to use
+       "/list s".
+       (m_list): Allow opers with PRIV_LIST_CHAN to see secret channels.
+
+2005-02-21  Perry Lorier <isomer@undernet.org>
+
+       * ircd/s_stats.c: Hide the hub IP's.  They're kinda important.
+
+2005-02-20  Perry Lorier <isomer@undernet.org>
+
+       * ircd/ircd_parser.y: Moved some parse errors from log_write()'s to
+       parse_error()'s so that ./ircd -k will display them.  Also clarified
+       the warning about oper blocks.
+
+2005-02-20  Perry Lorier <isomer@undernet.org>
+
+       * tools/convert-conf.py: A multitude of changes to deal with parsing
+       mistakes, generate a newer config file, better error handling,
+       being smarter about what config elements you generate etc.
+       
+2005-02-20  Perry Lorier <isomer@undernet.org>
+
+       * ircd/engine_epoll.c: Change a size_t to socklen_t to match
+       getsockopt prototype, so it compiles without warning on amd64
+
+2005-02-19  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/ircd_parser.y (clientblock): Parse IP address before
+       allocating ConfItem; if the parse fails, generate an error.
+
+       * ircd/s_err.c (RPL_STATSCLINE): Add format field to prefix IPv6
+       addresses starting with ':'.
+       (RPL_STATSILINE): Likewise.
+       (RPL_STATSOLINE): Add format field for username.
+
+       * ircd/s_stats.c (stats_configured_links): Pass the appropriate
+       argument for the RPL_STATSxLINE changes.
+       Change RPL_STATSILINE to use * instead of <NULL> when IP or host
+       is null.
+
+2005-02-18  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/IPcheck.c (ip_registry_find): Use canonical form of IP
+       address to look up and compare against hash entries.
+
+       * ircd/channel.c (apply_ban): Do not free a succesful BAN_DEL ban.
+
+       * ircd/ircd_parser.y (clientblock): Stash IP string in aconf->name.
+       (clienthost): Split hosts that contain '@' into username and host.
+       (clientip): Split IPs that contain '@' into username and IP.
+       (killreason): Add missing ~ to mask off DENY_FLAGS_FILE.
+
+       * ircd/m_silence.c (forward_silences): When we reject a silence,
+       splice it out of the ban list.  Warn the user if he is local.
+
+       * ircd/s_bsd.c (connect_inet): Set IP TOS for outbound server
+       connections.
+
+       * ircd/s_stats.c (stats_configured_links): Display correct field
+       when listing CONF_UWORLD entries.
+
+2005-02-09  Michael Poole <mdpoole@troilus.org>
+
+       * configure.in (YACC): Only warn if we cannot get a version number
+       from $YACC.
+
+       * configure: Regenerate.
+
+       * ircd/ircd_res.c (check_resolver_timeout): Try another way to
+       avoid timer_chg() on a non-queued/active timer.
+
+       * ircd/ircd_string.c (ircd_aton): Set part_start to handle input
+       strings like "::127.0.0.1".
+
+       * ircd/test/ircd_in_addr_t.c (test_addrs): Add a test for that.
+
+2005-02-02  Michael Poole <mdpoole@troilus.org>
+
+       * Makefile.in (install): Do not create ${prefix}/include since it
+       is no longer used.
+
+       * ircd/Makefile.in (install-*): Remove commented-out code to touch
+       and chown MPATH and RPATH.
+
+       * ircd/gline.c (gline_find): Allow searching for host-based
+       G-lines by plain hostname (not *@host), thus preventing "GLINE
+       test ..." from inserting duplicate G-lines.
+
+       * ircd/motd.c (motd_create): Null out new Motd's hostmask when
+       appropriate, avoiding an uninitialized or stale pointer.
+
+2005-01-26  Michael Poole <mdpoole@troilus.org>
+
+       * include/ircd_alloc.h (DoMallocZero): Parenthesize macro
+       arguments, fixing operator precedence problems.
+       (DoFree): Make debug version also overwrite p.
+
+       * include/memdebug.h (fda_get_byte_count, fda_get_block_count):
+       Declare functions used outside memdebug.c.
+
+       * ircd/Makefile.in (UMKPASSWD_SRC): Add memdebug.c.
+
+       * ircd/ircd_alloc.c (DoMalloc, DoMallocZero, DoRealloc): Do not
+       use these if using the memdebug version.
+
+       * ircd/memdebug.c: #include "send.h" and <string.h> to get
+       declarations for certain functions.
+
+       * ircd/umkpasswd.c (CurrentTime): Define in case of memdebug.
+       (sendto_opmask_butone): Likewise.
+
+2005-01-25  Michael Poole <mdpoole@troilus.org>
+
+       * configure.in: Fix typos and thinkos in previous commut.
+
+       * configure: Regenerate.
+
+       * doc/example.conf: Change class name in Connect block to be
+       consistent with earlier Class block.
+
+       * ircd/ircd.c (try_connections): Consider Connect blocks with hold
+       time of 0.  Fix Links() vs MaxLinks() comparison to reflect ref
+       count starting at 1.
+
+       * ircd/ircd_parser.y (cruleblock, iauthblock): Clear unused
+       variables after use.
+
+2005-01-24  Michael Poole <mdpoole@troilus.org>
+
+       * configure.in: Make sure that $LEX and $YACC are reasonable and
+       actually run.
+
+       * configure: Regenerate.
+
+       * ircd/ircd_res.c (check_resolver_timeout): Use correct macro to
+       test whether the timer is already pending.
+
+2005-01-23  Michael Poole <mdpoole@troilus.org>
+
+       * doc/example.conf (Kill): Fix typo in realname Kill block
+
+       * include/client.h (infousermodes): Fix typo in comment.
+
+       * ircd/ircd.c (parse_command_line): -k implies BOOT_TTY.
+       (main): Move daemon_init() before event_init() to work around BSD
+       lameness.
+
+2005-01-23  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/test/Makefile.in: Add missing "install" target.  Make
+       compatible with BSD make (which has no $^ and no $(CPPFLAGS) in
+       its default .c.o rule).
+
+2005-01-21  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/engine_kqueue.c: Move <sys/types.h> earlier to fix build on
+       FreeBSD 5.x (which needs it for <sys/event.h>).
+
+       * ircd/fileio.c (fbopen): Replace BSDism S_IREAD, S_IWRITE with
+       portable equivalents.
+
+       * ircd/ircd_log.c (log_open): Likewise.
+
+       * ircd/os_generic.c (_XOPEN_SOURCE): Increase to 600 (SuSv3?) so
+       that IPv6 definitions become visible on FreeBSD 5.3.
+
+       * ircd/s_auth.c: Remove apparently unused <sys/file.h> because
+       it fails to compile on FreeBSD 5.3.
+
+2005-01-22  Perry Lorier <isomer@undernet.org>
+
+       * ircd/ircd_parser.y: Fix missing ;
+
+2005-01-19  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/m_invite.c (m_invite, ms_invite): Include timestamp in
+       outbound INVITE messages.  On incoming INVITEs, ignore if the
+       timestamp is too recent or if the timestamp is missing and the
+       peer server is in burst.
+
+2005-01-15  Michael Poole <mdpoole@troilus.org>
+
+       * RELEASE.NOTES: Mention CIDR support for Client, Operator, bans
+       and silences.  Mention net.rider kick change.
+
+       * doc/example.conf (Class): Add documentation for restart and
+       local_opmode privileges.  Fix name of local_jupe privilege.
+
+       * ircd/ircd_lexer.l: Recognize local_opmode privilege.
+
+2005-01-14  Michael Poole <mdpoole@troilus.org>
+
+       * RELEASE.NOTES: Further updates (mention Pseudo blocks, clarify
+       CAP comment, mention named /stats, list config heteromorphisms.
+
+       * doc/readme.features: Document HIS_STATS_a, HIS_STATS_L,
+       HIS_STATS_R, LOCAL_CHANNELS, TOPIC_BURST.
+
+       * ircd/channel.c (mode_parse_apass): Change old mention of +u mode
+       to say +U.
+
+2005-01-13  Michael Poole <mdpoole@troilus.org>
+
+       * RELEASE.NOTES: Update for 2.10.12.
+
+2005-01-08  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/channel.c (@page zombie): Add synopsis to explain what
+       zombies are supposed to do.
+
+       * doc/example.conf (Features): Transfer recommended LOG features
+       from 2.10.11 example.conf.
+
+2005-01-03  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/ircd.c (try_connections): Test Connect hold time before
+       updating it (spotted by Kev).
+
+2005-01-03  Michael Poole <mdpoole@troilus.org>
+
+       * Makefile.in: Add ircd/test as a subdirectory.
+
+       * ircd/.cvsignore: Ignore umkpasswd binary.
+
+       * ircd/Makefile.in: Update dependencies.
+
+       * ircd/test/.cvsignore: New file.
+
+       * ircd/test/Makefile.in: Use ${} instead of $().  Add build,
+       depend, distclean targets to integrate with rest of build system.
+
+2005-01-03  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/IPcheck.c (ip_registry_check_remote): Do not count clones
+       that have an invalid IP address.
+
+       * ircd/ircd.c (try_connections): Update Connect hold time before
+       skipping it, to prevent infinite loops.
+
+2005-01-03  Kevin L Mitchell  <klmitch@mit.edu>
+
+       * ircd/s_user.c (is_silenced): is_silenced() would core if sptr
+       was a server; fixed to skip servers
+
+2004-12-28  Michael Poole <mdpoole@troilus.org>
+
+       * include/s_bsd.h (VirtualHost): Replace with separate variables
+       for IPv4 and IPv6 virtual hosts.
+
+       * include/uping.h (uping_echo): Remove declaration.
+
+       * ircd/ircd_auth.c (iauth_reconnect): Select VirtualHost_v4 or
+       VirtualHost_v6 based on iauth server address family.
+
+       * ircd/ircd_lexer.l: Do not recognize RESOLVER token.
+
+       * ircd/ircd_parser.y (ResolverAddr): Remove declaration.
+       (RESOLVER): Remove definition.
+       (generalresolver): Remove.
+       (generalvhost): Assign address to either VirtualHost_v4 or
+       VirtualHost_v6, depending on format.
+
+       * ircd/ircd_res.c (res_socket): Replace with separate variables
+       for IPv4 and IPv6 resolver sockets.
+       (ResolverAddr): Remove definition.
+       (restart_resolver): Attempt to set up both IPv4 and IPv6 sockets.
+       (send_res_msg): Select outbound FD based on resolver address type.
+       (res_readreply): Recognize either inbound socket FD.
+
+       * ircd/os_generic.c (sockaddr_from_irc): Require irc != NULL.
+       (os_socket): Require local != NULL.
+
+       * ircd/s_bsd.c (VirtualHost): Replace with separate variables
+       for IPv4 and IPv6 virtual hosts.
+       (connect_inet): Select virtual host based on destination address.
+
+       * ircd/uping.c (UPingFIleDescriptor): Remove.
+       (upingSock): Split into separate IPv4 and IPv6 variables.
+       (uping_echo_callback): Incorporate uping_echo() body here, so the
+       proper socket FD can be used.
+       (uping_init): Attempt to set up both v4 and v6 UPING sockets.
+       (uping_server): Create uping socket with appropriate local address.
+
+       * doc/example.conf (General): Update example config file to
+       reflect removal of Resolver setting and support for separate IPv4
+       and IPv6 VHost settings.
+
+2004-12-28  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/sys.h (BITS_ZERO_ON_*, HAVE_RELIABLE_SIGNALS, DOCURSES,
+       DOTERMCAP, IRC_UID, IRC_GID, LIMIT_FMT, FALSE, TRUE): Remove
+       unused macros.
+
+       * ircd/ircd_auth.c, ircd/listener.c, ircd/s_auth.c, ircd/s_bsd.c,
+       ircd/s_conf.c, ircd/uping.c, ircd/whocmds.c: Remove obsolete
+       #include <arpa/inet.h>.
+
+2004-12-28  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/match.c: Remove obsolete #include <arpa/inet.h>.
+       (ipmask_parse_ipv4): We already parse the dotted quads from the
+       input string, so use them instead of inet_addr() to populate
+       out->s_addr.
+
+       * ircd/gline.c: Remove obsolete #includes <arpa/inet.h>, "sys.h".
+       (do_gline): Pass SHOW_IP instead of TRUE as argument to
+       get_client_name().
+
+       * ircd/ircd.c (try_connections): Revise to use fewer temporary
+       variables.
+
+2004-12-28  Michael Poole <mdpoole@troilus.org>
+
+       * include/res.h: Implement irc_in_addr_* as macros.
+
+       * ircd/ircd_res.c: Remove the function bodies.
+
+       * ircd/ircd_string.c (irc_in_addr_is_ipv4): Remove body.
+       (ircd_ntoa_r): Do not append extra ':' when unparsing 0::.
+       (ircd_aton): Accept IPv6 addresses with all eight segments
+       specified (e.g. 0:0:0:0:0:0:0:0).  Correctly parse addresses
+       with IPv4 bits at the end (e.g. ::FFFF:127.0.0.1).
+
+       * ircd/test/ircd_in_addr_t.c, ircd/test/test_stub.c: New files.
+
+       * ircd/test/Makefile: Convert to Makefile.in for proper VPATH
+       support.  Add test_stub.c and ircd_in_addr_t.c references.
+
+       * configure.in: Generate ircd/test/Makefile as an output file.
+
+       * configure: Update.
+
+2004-12-18  Michael Poole <mdpoole@troilus.org>
+
+       * include/client.h: Move unreg, privs, capab and active fields
+       from struct Client to struct Connection since that is how they
+       are really associated.  Adjust macros to match.
+       (SetPriv, ClrPriv): New macros.
+
+       * ircd/client.c (client_set_privs): Exit earlier for remote
+       clients.  Adjust macro use to correspond.
+
+       * ircd/m_server.c (mr_server): Grant all privileges except
+       PRIV_SET to peer servers.
+
+2004-12-18  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/s_user.c (hide_hostmask): Add a missing "break;" to fix bug
+       #1087461.
+
+2004-12-18  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/engine_kqueue.c (engine_loop): Remove an assertion that the
+       socket's FD is the same after processing as it was before; local
+       clients apparently have s_fd() == -1 after close.
+
+2004-12-18  Kevin L Mitchell  <klmitch@mit.edu>
+
+       * ircd/s_user.c: make absolutely certain register_user() is never
+       called with cli_unreg non-zero; transition set_nick_name() over to
+       the new way of determining whether client is ready for
+       register_user()
+
+       * ircd/s_err.c: add ERR_UNKNOWNCAPCMD for reporting failure to
+       understand a given CAP subcommand
+
+       * ircd/parse.c: add "CAP" command
+
+       * ircd/m_user.c (m_user): transition over to new way of
+       determining whether client is ready for register_user()
+
+       * ircd/m_pong.c (mr_pong): transition over to new way of
+       determining whether client is ready for register_user()
+
+       * ircd/m_cap.c: implementation of the IRC capabilities draft
+
+       * ircd/list.c (make_client): initialize cli_unreg element of
+       client structure
+
+       * ircd/ircd_string.c: correct old bugs in ircd_strn?cmp()
+       functions that were never found because cross-case ordering has
+       not been needed until now
+
+       * ircd/Makefile.in: add m_cap.c to list of .c files
+
+       * include/numeric.h (ERR_UNKNOWNCAPCMD): define new error reply to
+       indicate an unknown CAP subcommand
+
+       * include/msg.h: add "CAP" command
+
+       * include/handlers.h: add m_cap() to list of handlers
+
+       * include/client.h: add support for client capabilities; rototill
+       the registration mechanism to dovetail well with the capability
+       system--i.e., allow the capability system to suspend registration
+       if the user issues one of the CAP commands
+
+       * include/capab.h: header file to define client capabilities
+
+2004-12-17  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/channel.h (apply_ban): Add new flag to indicate whether
+       newban should be free()'d after it is used.
+
+       * ircd/channel.c (apply_ban): Likewise.  Also set BAN_DEL flag
+       when setting BAN_OVERLAPPED, and free newban when BAN_DEL.
+       (mode_parse_ban): Delete buggy shortcut when channel banlist is
+       empty.
+       (mode_process_bans): Always give ownership of ban->banstr to the
+       mode buffer, avoiding a memory leak.
+
+       * ircd/m_silence.c (apply_silence): Pass new parameter to
+       apply_ban.
+
+2004-12-17  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/channel.c (sub1_from_channel): Immediately destroy
+       non-Apass channels when oplevels are enabled; otherwise, they can
+       stay opless for a considerable period.
+       (mode_parse_ban): Initialize banstr to NULL so that set_ban_mask()
+       does not try to free() an invalid pointer.
+
+       * ircd/ircd_parser.y (uworldblock): Put UWorld server name into
+       aconf->host, not aconf->name.
+
+       * ircd/m_server.c (mr_server, ms_server): Attach CONF_UWORLD items
+       by host here..
+
+       * ircd/s_conf.c (conf_check_server): .. rather than by name here.
+       (attach_conf_uworld): New function to attach CONF_UWORLD items.
+       (rehash): Use attach_conf_uworld() instead of attaching by name.
+
+2004-12-15  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/m_topic.c (do_settopic): Allow +k services to set topics on
+       channels they are not joined.
+
+2004-12-15  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/IPcheck.c (IPTargetEntry): Make count unsigned to squash
+       warning.
+       (ip_registry_canonicalize): New function to convert an IP address
+       into a canonical form for clone checks.
+       (ip_registry_hash): Update to reflect canonical form.
+       (ip_registry_find): Use ip_registry_canonicalize().
+       (ip_registry_check_local, ip_registry_check_remote): Likewise.
+
+       * ircd/numnicks.c (iptobase64): Map 6to4 addresses to IPv4 when
+       sending them to a non-IPv6 server.
+
+2004-02-17  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/s_user.c (hide_hostmask): Preserve user's visibility in a
+       +D channel when they hide their hostmask.
+
+2004-12-15  Michael Poole <dmpoole@troilus.org>
+
+       * doc/example.conf: Remove the example Server blocks since they
+       are no longer used (were merged into Connect).
+
+       * ircd/ircd_res.c (restart_resolver): Fix typo in previous commit.
+
+       * ircd/m_server.c (check_loop_and_lh): Use a different argument to
+       test whether an introduced server is directly connected or not.
+
+2004-12-14  Michael Poole <mdpoole@troilus.org>
+
+       * include/client.h (FLAG_IPV6): New value for enum Flag.
+       (IsIPv6, SetIPv6): Accessor macros for it.
+
+       * include/numnicks.h (iptobase64): Add flag indicating whether to
+       use full IPv6 addresses or fake them in an IPv4-compatible way.
+
+       * ircd/numnicks.c (iptobase64): Use the new flag.
+
+       * include/send.h (sendcmdto_flag_serv_butone): New function to
+       send different lines to servers based on flags (like FLAG_IPV6).
+
+       * ircd/send.c (sendcmdto_flag_serv_butone): Implement it.
+
+       * ircd/s_bsd.c (completed_connection): Advertise IPv6 support in
+       our server flags.
+
+       * ircd/s_serv.c (server_estab): Likewise.  Also make sure we send
+       compatible IP addresses for the new server.
+
+       * ircd/s_user.c (register_user): Only send full IPv6 addresses to
+       links that have FLAG_IPV6 set.
+
+2004-12-13  Michael Poole <mdpoole@troilus.org>
+
+       * doc/example.conf: Update General block comment to mention
+       new RESOLVER option and to explain IPv6 support.
+
+       * ircd/ircd_lexer.l: Recognize RESOLVER token.
+
+       * ircd/ircd_parser.y: Declare RESOLVER token and use it in an
+       alternative for generalitem.
+
+       * ircd/ircd_res.c: Define global ResolverAddr variable.  If it is
+       valid, use it instead of VirtualHost in restart_resolver().
+
+2004-12-13  Michael Poole <mdpoole@troilus.org>
+
+       * doc/example.conf: Update configuration to move Client block
+       comment after sample Class blocks, and update entries in it.
+
+       * ircd/ircd_lexer.y: Recognize IP and USERNAME tokens.
+
+       * ircd/ircd_parser.y: Add ip and username global variables and IP
+       and USERNAME tokens.  Add clientip and clientusername alternatives
+       for clientitem, and update clientblock to correspond.
+
+       * ircd/ircd_res.c (delete_resolver_queries): Do not try to walk
+       the request_list before request_list is initialized.
+       (cres_mem): Likewise.
+
+       * ircd/os_generic.c (sockaddr_from_irc): Improve guessing of
+       proper address family.
+
+       * ircd/s_conf.c (attach_iline): Allow aconf->host == NULL, which
+       means DNS reply is optional.  If aconf->addrbits >= 0, test it.
+
+       * tools/crypter: Delete.
+
+2004-12-11  Kevin L Mitchell  <klmitch@mit.edu>
+
+       * ircd/*.c: use new assert() in ircd_log.h in preference to system
+       assert()
+
+       * ircd/umkpasswd.c: use new assert in ircd_log.h; add necessary
+       glue so that umkpasswd will successfully compile and link
+
+       * ircd/test/ircd_chattr_t.c: comment out include of assert.h since
+       there are no calls to assert()
+
+       * ircd/ircd_log.c: add sentinel (log_inassert) to prevent assert()
+       from looping should there be an assertion failure somewhere in the
+       logging subsystem
+
+       * include/ircd_log.h: custom implementation of assert() that calls
+       log_write()
+
+2004-11-21  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/channel.c (mode_parse_upass): Allow forced mode changes to
+       be done by non-channel-managers, fixing a crash from OPMODE.
+       (mode_parse_apass): Likewise.
+
+2004-11-20  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/m_create.c (ms_create): Complain if a user tries to CREATE
+       a channel they are already in, but do not add them again.
+
+2004-11-09  Michael Poole <mdpoole@troilus.org>
+
+       * include/res.h (init_resolver): Delete, and initialize lazily.
+
+       * ircd/ircd.c (main): Do not call init_resolver().
+
+       * ircd/ircd_res.c (restart_resolver): Use default VirtualHost for
+       local resolver socket address.
+       (init_resolver): Delete.
+       (make_request): Call restart_resolver() if necessary.
+       (query_name): Use ircrandom() instead of rand().
+
+       * ircd/os_generic.c (sockaddr_from_irc): Convert last argument to
+       a file descriptor that indicates the socket family to use.
+       (os_sendto_nonb,os_socket,os_connect_nonb): Update to match.
+
+2004-11-09  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/engine_epoll.c (engine_delete): Do not attempt to remove a
+       socket from epoll on delete, since the kernel does that for us.
+
+2004-11-07  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/m_server.c (m_server, ms_server): Assign timestamp before
+       it might be used in exit_new_server().
+
+2004-11-07  Michael Poole <mdpoole@troilus.org>
+
+       * aclocal.m4, config.h.in, configure, ircd/Makefile.in: Regenerate
+       to reflect the changes since these files' last rebuild.
+
+2004-11-07  Michael Poole <mdpoole@troilus.org>
+
+       * include/ircd_crypt.h (ircd_crypt): This should return char*, not
+       const char*, since it does not own the returned pointer.
+
+       * ircd/ircd_crypt.c (ircd_crypt): Change return type.
+
+       * ircd/ircd_crypt_smd5.c (irc_crypt_smd5): Make passwd a static
+       field since it is returned but this function must own the buffer.
+
+       * ircd/m_oper.c (oper_password_match): Free the string returned by
+       ircd_crypt().
+
+       * ircd/engine_epoll.c (engine_loop): Fix a memory leak.
+
+2004-11-07  Michael Poole <mdpoole@troilus.org>
+
+       * acinclude.m4: Look for a 64-bit integer type.
+
+       * configure.in: Look for inttypes.h, since some systems have that
+       but not stdint.h (and define 64-bit integers therein).
+
+       * include/client.h: Delete con_sendK, con_receiveK.  Make
+       con_sendB and con_receiveB 64 bits wide.
+
+       * include/s_misc.h: Delete is_cks, is_ckr, is_sks, is_skr.
+       Convert the other byte counters and the connected time counters to
+       64 bits wide.
+
+       * ircd/ircd_snprintf.c (doprintf): Unconditionalize the
+       HAVE_LONG_LONG bits, and use the 64-bit integer types from above.
+
+       * ircd/packet.c (update_bytes_received): Remove use of
+       cli_receiveK().
+
+       * ircd/s_bsd.c (deliver_it): Likewise.
+       (close_connection): Likewise.
+
+       * ircd/s_misc.c (tstats): Likewise.  Update format strings to use
+       %Lu for 64-bit integer parameters.
+
+       * ircd/s_stats (stats_links): Convert cli_sendK() and
+       cli_receiveK() use shifted versions of the byte counters, and
+       update format strings to use %Lu for 64-bit integer parameters.
+
+2004-11-07  Michael Poole <mdpoole@troilus.org>
+
+       * include/s_user.h (add_silence): Delete.
+       (del_silence): Delete.
+
+       * include/struct.h (struct User): Convert silence list to struct Ban.
+
+       * ircd/m_silence.c (apply_silence, forward_silences): New functions.
+       (m_silence): Use forward_silences() instead of add_silence().
+       (ms_silence): Likewise.
+
+       * ircd/s_err.c (replyTable): Update RPL_SILELIST.
+
+       * ircd/s_misc.c (exit_one_client): Update to new silence list type.
+
+       * ircd/s_user.c (is_silenced): Use find_ban() to search for
+       silences.  If one is found, send it plus any silence exceptions.
+       (del_silence): Delete.
+       (add_silence): Delete.
+
+2004-11-07  Michael Poole <mdpoole@troilus.org>
+
+       * include/channel.h: Remove declarations for undefined functions
+       cancel_mode(), add_token_to_sendbuf(), IsMember().  Delete
+       add_banid(), next_removed_overlapped_ban().  Add BAN_EXCEPTION
+       flag and new functions find_ban(), apply_ban().
+
+       * ircd/channel.c (PartFmt*, next_ban, prev_ban, removed_bans_list,
+       LocalChanOperMode): Remove unused variable definitions.
+       (make_nick_user_host): Delete.
+       (add_banid): Delete.
+       (next_removed_overlapped_ban): Delete.
+       (find_ban): New function, which knows about exceptions.
+       (is_banned): Use find_ban() and only work on a struct Membership.
+       (bmatch): New function, which knows about CIDR bans.
+       (apply_ban): New function to replace add_banid().
+       (mode_parse_ban): Use apply_ban().
+
+2004-10-28  Michael Poole <mdpoole@troilus.org>
+
+       * configure.in (AC_PREREQ): Depend on autoconf 2.50 since we use
+       new macros like AC_LINK_IFELSE and AC_LANG_PROGRAM.
+
+2004-10-22  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/m_invite.c (m_invite, ms_invite): Fix INVITE forwarding
+       with announcements enabled (do not "announce" to the recipient,
+       and unconditionally send to the recipient).
+
+       * ircd/send.c (sendcmdto_channel_servers_butone): Properly skip
+       the "from" client and implement SKIP_NONOPS and SKIP_NONVOICES.
+
+2004-10-21  Michael Poole <mdpoole@troilus.org>
+
+       * include/channel.h (Ban): Add fields address, nu_len, addrbits to
+       support netmask-based bans.
+
+       * ircd/channel.c (set_ban_mask): New function to parse a ban as
+       either netmask-based or not.
+       (make_ban): Use set_ban_mask().
+       (make_nick_user_ip): Becomes unused; remove it.
+       (is_banned): Rewrite to match only once against the nick!user part
+       of a ban, and compare addresses if BAN_IPMASK is set.
+       (mode_parse_ban): Use set_ban_mask().
+
+2004-10-21  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/s_conf.c (attach_iline): Test resolved host names against
+       aconf->host, not the (NULL) aconf->name.
+
+2004-10-19  Michael Poole <mdpoole@troilus.org>
+
+       * include/channel.h: Move ban flags out of channel flags and
+       rename to reflect this.
+
+       * ircd/channel.c: Update ban constant names.
+
+       * ircd/m_burst.c: Likewise.
+
+2004-10-18  Michael Poole <mdpoole@troilus.org>
+
+       * include/list.h (SLink): Remove ban elements from here...
+
+       * include/channel.h (Ban): And move to the new struct Ban.
+       (Channel): Update banlist field to match.
+       (next_removed_overlapped_ban): Update return type to match.
+       (make_ban, free_ban): New functions.
+
+       * ircd/channel.c (next_ban, prev_ban, removed_bans_list): Update
+       list types.
+       (free_bans): New variable to hold unused Ban elements.
+       (make_ban, free_ban): New functions.
+       (destruct_channel, add_banid, next_removed_overlapped_ban): Update
+       to use struct Ban.
+       (is_banned, send_channel_modes, send_ban_list): Likewise.
+       (ParseState, mode_parse_ban, mode_process_bans): Likewise.
+       (mode_parse): Likewise.
+
+       * ircd/m_burst.c (ms_burst): Update to use struct Ban.
+
+       * ircd/m_clearmode.c (do_clearmode): Update to use struct Ban.
+
+       * ircd/s_debug.c (count_memory): Update to use struct Ban.
+
+2004-10-18  Kevin L Mitchell  <klmitch@mit.edu>
+
+       * ircd/gline.c (gline_find): unless we're looking for an exact
+       match, we should call match() on hostnames, not ircd_strcmp()
+
+2004-10-17  Michael Poole <mdpoole@troilus.org>
+
+       * include/s_conf.h (ConfItem): Add new field username.  Replace
+       unused field bits with addrbits.
+       (find_conf_exact): Replace user and host arguments with cptr.
+       (find_conf_name, read_tlines, find_restrict): Remove declaration
+       for undefined functions.
+       (conf_parse_userhost): New function.
+
+       * ircd/m_oper.c (m_oper): Update calls to find_conf_exact(): both
+       resolved hostname and IP are matched in one pass now.
+
+       * ircd/s_bsd.c (close_connection): Update call to find_conf_exact().
+
+       * ircd/s_conf.c (conf_parse_userhost): New function.
+       (check_limit_and_attach): Use correct ConfItem field to determine
+       maximum connections per IP.
+       (attach_iline): Replace user@host matching with shorter, clearer
+       matching against username and host/IP fields.
+       (find_conf_exact): Likewise.
+
+       * ircd/ircd_parser.y: Replace assignment to aconf->host for
+       CONF_CLIENT and CONF_OPERATOR with calls the CIDR-aware
+       conf_parse_userhost().  This means CONF_CLIENT ConfItems no longer
+       use the name field or the IP token.  Remove the latter.
+
+       * ircd/ircd_lexer.l: Remove unused token IP.
+
+2004-10-17  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/crule.c (crule_via): Simplify the lookup for the directly
+       connected server name.
+
+2004-10-16  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/class.c: Make find_class() return NULL for unknown classes,
+       rather than returning the start of connClassList.
+
+       * ircd/match.c (parse_ipmask): Translate IPv4 masks as
+       IPv4-compatible addresses.
+       (check_ipmask): Fix comparison of IP masks.
+
+       * ircd/motd.h, ircd/motd.c: Add a new MOTD type, MOTD_IPMASK, that
+       uses CIDR style masks in the hostname field of a Motd block.
+
+2004-10-16  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/numeric.h: Remove the unused RPL_STATMEM and
+       RPL_STATMEMTOT.  Move the RPL_BOUNCE comment to its current
+       value (the former RPL_STATMEM).
+
+       * ircd/s_err.c: Remove format strings for RPL_STATMEM and
+       RPL_STATMEMTOT.
+
+2004-10-16  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/m_server.c: Look up server configuration by name of our
+       directly connected peer rather than the server being introduced.
+
+2004-10-13  Michael Poole <mdpoole@troilus.org>
+
+       * include/channel.h: Delete MODE_LISTED and is_listed().  Replace
+       ListingArgs.chptr with ListingArgs.bucket.  Move declaration of
+       list_next_channels() to..
+
+       * include/hash.h: here, and drop the "nr" argument.
+
+       * ircd/channel.c: Remove redundant scan of local clients for
+       channels being listed.  Delete list_next_channels() function.
+
+       * ircd/hash.c: Add list_next_channels() here, revising to not use
+       MODE_LISTED and to use ListingArgs.bucket instead of chptr.  Also
+       decide when to stop sending RPL_LISTs based on a half-full sendq.
+
+       * ircd/m_burst.c, ircd/s_misc.c: Delete mention of MODE_LISTED.
+
+       * ircd/m_list.c: Delete mention of MODE_LISTED.  Unconditionally
+       call list_next_channels(sptr).
+
+       * ircd/s_bsd.c: Remove the "nr" argument to list_next_channels().
+
+       * ircd/Makefile.in: Update dependencies (for hash.c).
+
+2004-10-13  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/ircd_parser.y: Consistently zero out global variables after
+       they are used (prevents double frees and other problems).
+
+2004-10-12  Michael Poole <mdpoole@troilus.org>
+
+       * include/client.h: Rename FLAGSET_ISSET, _SET, _CLEAR to FlagHas,
+       Set, Clr respectively.  Get rid of FLAG_CHKACCESS and FLAG_LOCAL.
+       Delete con_fd (get from con_socket) and con_port.  Move sentalong
+       from send.c to struct Connection, and cli_lasttime and cli_since
+       from struct Client to struct Connection.  Update cli_*() macros to
+       use con_*(cli_connect(cli)).
+
+       * ircd/client.c: Replace PrivSet() with FlagSet(), PrivClr() with
+       FlagClr(), PrivHas() with FlagHas().
+
+       * ircd/ircd_parser.y: Likewise.
+
+       * ircd/list.c: Remove assignment to cli_local() since it is now a
+       calculated value.
+
+       * ircd/s_bsd.c: Remove uses of cli_port().
+
+       * ircd/s_conf.c: Remove uses of ClearAccess().
+
+       * ircd/send.c: Delete sentalong array and replace with references
+       to con_sentalong().
+
+2004-10-12  Michael Poole <mdpoole@troilus.org>
+
+       * doc/example.conf: Update example config to reflect the changes
+       made in the remainder of this patch.
+
+       * include/list.h: Make make_conf() take a type argument.
+
+       * include/s_conf.h: Delete CONF_LEAF and CONF_HUB.  Add "maximum"
+       and "hub_limit" to ConfItem to compensate.
+
+       * ircd/ircd_lexer.l: Recognize MAXHOPS token.
+
+       * ircd/ircd_parser.y: Get rid of aconf global variable and add
+       hub_limit global variable.  Add MAXHOPS token, and productions
+       inside connectblock to recognize it and hub masks.  Allow maxlinks
+       field in a Client block, rather than overloading password field.
+       Convert serverblock to uworldblock and remove extraneous fields.
+
+       * ircd/m_server.c: Make check_loop_and_lh() look up ConfItem and
+       calculate LHcptr and active_lh_line.  Merge some duplicated code
+       so handling active_lh_line cases is clearer.
+
+       * ircd/s_conf.c: Make make_conf() take a type argument.  Delete
+       CONF_LEAF and CONF_HUB.  Do not overwrite server name with what
+       is specified in the config file.
+
+       * ircd/s_err.c: Remove the unused RPL_STATSNLINE and
+       RPL_STATSHLINE.  Remove useless parameters and format fields from
+       RPL_STATSCLINE, RPL_STATSILINE, RPL_STATSLLINE, RPL_STATSOLINE and
+       RPL_STATSULINE.
+
+       * ircd/s_serv.c: Delete CONF_LEAF and CONF_HUB.
+
+       * ircd/s_stats.c: Get rid of report_array and make
+       stats_configured_links() directly use RPL_STATSxLINE (adding the
+       new fields for Server and Client blocks).  Remove /stats h, since
+       that has no meaning.
+
+2004-10-12  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/m_burst.c: Mask off channel modes in a wiped-out channel by
+       default rather than by listing which should be wiped out.
+
+2004-10-09  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/m_server.c: Forward port checks for leaf and hub config
+       rules, and reorganize mr_server() and ms_server() by moving out
+       common code.  Add doxygen comments for the file.
+
+2004-10-09  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/hash.c: Fix thinko in hash function: It is not indexed
+       simply by character value, so we cannot just remap the values
+       by case.
+
+2004-10-05  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/hash.c: Replace the old hash function with one based on
+       randomized CRC-32.  The new one avoids a big table from the old
+       function.
+
+2004-10-05  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/random.c: Convert to use ircd_md5 interface and hopefully
+       keep more internal random state.
+
+2004-10-05  Michael Poole <mdpoole@troilus.org>
+
+       * include/ircd_md5.h, ircd/ircd_md5.c, ircd_crypt_smd5.c,
+       ircd/umkpasswd.c: Get rid of the GoodMD5xxx/BrokenMD5xxx
+       prefixes.
+
+2004-10-05  Michael Poole <mdpoole@troilus.org>
+
+       * adns, lib/adns: Remove unused adns library.
+
+2004-10-05  Michael Poole <mdpoole@troilus.org>, hikari <hikari@undernet.org>, Perry Lorier <isomer@undernet.org>
+
+       * include/*.h, ircd/*.c: Convert comments to Doxygen-compatible
+       format, and add new comments where needed.
+
+       * Doxyfile: New file to tell Doxygen how to run.
+
+2004-09-21  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/s_auth.c (HeaderMessages): Make the compiler, not the
+       programmer, generate magic numbers.
+       (AuthIncompleteList): Remove.
+       (AuthPollList): Remove.
+
+2004-09-19  Michael Poole <mdpoole@troilus.org>
+
+       * acinclude.m4: Clean up AC_DEFINE()s so we no longer need
+       acconfig.h.
+
+       * acconfig.h: Remove since it is now redundant.
+
+       * aclocal.m4, config.h.in, configure: Regenerate.
+
+2004-09-19  hikari <hikari@undernet.org>
+
+       * configure.in: Fixed configure script rules to fail if (f)lex or yacc/bison 
+       aren't found as they're essential for compilation.  Regenerated files with 
+       autreconf.
+               
+2004-09-18  Michael Poole <mdpoole@troilus.org>
+
+       * doc/example.conf: Add NETWORK feature example.  Fix typos in
+       eaxmples for HANGONGOODLINK and IRCD_RES_TIMEOUT.
+
+       * include.class.h: Make max_links and ref_count unsigned ints.
+       Make ping_freq and conn_freq unsigned short. (No more negative
+       numbers in /stats y.)
+
+       * ircd/ircd.c: Report configuration file name for "ircd -k".
+
+2004-09-18  hikari <hikari@undernet.org>
+
+       * ircd/Makefile.in: Fixed a missing internal build dependency.
+       
+2004-09-16  Michael Poole <mdpoole@troilus.org>
+
+       * INSTALL: Fix name of example.conf and mention its installed
+       location.
+
+       * include/supported.h (FEATURESVALUES2): Fix a reference to
+       channel mode +u that escaped earlier rename attempts.
+
+       * ircd/ircd_auth.c (iauth_connect): Assign port number after
+       zeroing out the destination address.
+       Add some additional debug statements to help follow operations.
+
+       * ircd/ircd_parser.y (iauthblock): Do not require "name" to be set.
+
+2004-09-11  Bas Steendijk <steendijk@xs4all.nl>
+
+       * include/channel.h, include/supported.h, ircd/channel.c,
+       ircd/s_err.c: Use +U instead of +u for user keys.
+
+2004-09-13  Michael Poole <mdpoole@troilus.org>
+
+       * doc/example.conf: Remove sample VIRTUAL_HOST setting.
+
+       * doc/readme.features: Remove VIRTUAL_HOST documentation, and
+       update NODNS documentation to match current behavior.
+
+       * include/s_conf.h: Remove now-unused vhost_address field and
+       set_virtual_host() function.
+
+       * include/ircd_features.h, ircd/ircd_features.c, ircd/s_debug.c:
+       Remove VIRTUAL_HOST.
+
+       * ircd/ircd_auth.c, ircd/s_bsd.c: Use VirtualHost as local address
+       if we do not have a more specific alternate.
+
+       * ircd/ircd_parser.y: Check for sanity in General blocks (from old
+       conf_add_local()) and assign vhost directly to VirtualHost.
+
+       * ircd/ircd_res.c (irc_in_addr_valid): Fix thinko; obviously any
+       value will be either != 0 or != 0xffff.
+
+       * ircd/os_generic.c: Use AF_INET instead of AF_INET6 when the
+       local addresses are specified as IPv4 addresses.
+
+       * ircd/s_conf.c: Remove unused conf_add_local() and
+       set_virtual_host().
+
+2004-09-13  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/listener.c (add_listener): Consolidate duplicated code, and
+       make sure listener->server is set before calling inetport() on it.
+
+2004-09-12  Michael Poole <mdpoole@troilus.org>
+
+       * include/channel.c (mode_parse_upass, mode_parse_apass): Only let
+       services (not normal opers) force a change of +A or +u.
+
+2004-09-11  Michael Poole <mdpoole@troilus.org>
+
+       * include/s_stats.h: Add sd_name to struct StatDesc.  Stop
+       publishing the statsinfo and statsmap arrays; replace them with
+       stats_find().  Change argument list of StatFunc() to work with
+       names.
+
+       * ircd/m_stats.c: Use stats_find() instead of statsmap[].  Use the
+       full argument instead of just the first character in reports.
+
+       * ircd/s_stats.c: Adapt individual stats handler functions to new
+       argument list.  Add long names to statsinfo[].  Add new functions
+       stats_cmp(), stats_search(), stats_find().  Sort statsinfo[] in
+       stats_init().
+
+       * ircd/s_err.c: Change ENDOFSTATS to display a string rather than
+       a single character.
+
+       * ircd/s_user.c: Send an error to the user when a message loses
+       its target in transit.
+
+       * include/class.h include/gline.h include/ircd_features.h
+       include/listener.h include/motd.h include/msgq.h include/res.h
+       include/s_debug.h include/s_misc.h include/userload.h ircd/class.c
+       ircd/gline.c ircd/ircd_features.c ircd/ircd_res.c ircd/listener.c
+       ircd/motd.c ircd/msgq.c ircd/s_debug.c ircd/s_misc.c
+       ircd/userload.c: Adjust stats handlers to new argument list.
+
+2004-09-11  Michael Poole <mdpoole@troilus.org>
+
+       * include/numeric.h, ircd/s_err.c: Remove RPL_TRACEPING, and
+       replace with RPL_TRACEEND.
+
+       * ircd/s_trace.c: Move all the duplicated code in m*_trace() to
+       do_trace().  Implement RPL_TRACEEND, per RFE#830291.
+
+2003-06-20  Alexander Maassen <outsider@key2peace.org>
+
+       * ircd/m_topic.c : Don't allow banned users to set a topic in a
+       channel.
+
+2004-09-11  Kevin L Mitchell  <klmitch@mit.edu>
+
+       * config.h.in, tools/Makefile.crypt: Remove wrong pathname from
+       comment in header.
+
+       * ircd/m_clearmode.c, ircd/m_opmode.c: Fix wrong pathname in
+       header comment.
+
+       * ircd/m_away.c, ircd/m_kill.c, ircd/m_notice.c, ircd/m_ping.c,
+       ircd/m_pong.c, ircd/m_privmsg.c, ircd/m_quit.c, ircd/m_topic.c,
+       ircd/m_version.c: Remove "template" moniker from comments.
+
+       * ircd/test/ircd_chattr.0.dat (IsChannelPrefix): Drop + from
+       channel prefix list.
+
+2004-09-11  Michael Poole <mdpoole@troilus.org>
+
+       * doc/example.conf: Add examples for FEAT_HIS_* features.
+
+2003-06-08 Matthias Crauwels <ultimate_@wol.be>
+       [Feature renamed to FEAT_HIS_WHOIS_LOCALCHAN by Michael Poole.]
+
+       * include/ircd_features.h: new feature FEAT_HIS_LOCAL_CHAN_WHOIS
+
+       * ircd/ircd_features.c: new feature FEAT_HIS_LOCAL_CHAN_WHOIS
+
+       * ircd/m_whois.c: hide local channels in local WHOIS, this breaks HIS
+
+       * doc/readme.features: documented FEAT_HIS_LOCAL_CHAN_WHOIS
+
+       * doc/ircd.conf.sample: default value for FEAT_HIS_LOCAL_CHAN_WHOIS
+
+2004-09-11  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/ircd_relay.c (server_relay_channel_message,
+       server_relay_channel_notice): Do not allow other servers to send
+       or relay to local channels.
+
+       * ircd/m_wallchops (ms_wallchops): Likewise.
+
+       * ircd/m_wallvoices (ms_wallvoices): Likewise.
+
+2004-09-11  Kevin L Mitchell  <klmitch@mit.edu>
+
+       * ircd/gline.c (gline_add): fix GLINE logging (Bug #750927)
+
+       * ircd/channel.c: removing limits shouldn't gobble an argument;
+       this was a subtle interaction issue with modebuf...fixed by adding
+       MODE_LIMIT to modebuf_flush_int() and short-circuiting
+       modebuf_mode_uint() to add MODE_LIMIT to mbuf->mb_rem in the
+       removal case.  Note that this is not proof against the sequence,
+       "modebuf_mode_uint(mbuf, MODE_ADD | MODE_LIMIT, 10);
+       modebuf_mode_uint(mbuf, MODE_DEL | MODE_LIMIT, 10);"
+       (Bug #916138)
+
+2004-09-11  Michael Poole <mdpoole@troilus.org>
+
+       * include/supported.h: Kev pointed out I misinterpreted the
+       meaning of CHANMODES; fix this.  Also define CHANNELLEN and
+       STATUSMSG from the ISUPPORT draft.
+
+2004-09-10  Michael Poole <mdpoole@troilus.org>
+
+       * include/supported.h (FEATURESVALUES2): Include A,u, in CHANMODES
+       when oplevels are enabled.
+
+2004-09-10  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/channel.c (send_channel_modes): Only send oplevels for
+       channels that actually use them -- for -A channels, send chanops
+       as :o even if OPLEVELS is enabled.
+
+       * ircd/ircd.c: Fix -k (chkconf mode) and show in usage help.
+
+       * ircd/numnicks.c (base64toip): Fill in the right number of 0
+       words when we see _ in a base64-encoded IPv6 address.
+
+2004-09-10  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/ircd.c: Add -k as a chkconf-like option to exit after
+       reading the configuration file.
+
+       * ircd/chkconf.c: Remove as unused.
+
+       * ircd/Makefile.in: Remove last mentions of chkconf from Makefile.
+
+2004-09-10  Michael Poole <mdpoole@troilus.org>
+
+       * doc/example.conf: Remove examples for unused features (TIMESEC,
+       CRYPT_OPER_PASSWORD) and add for new feature (ANNOUNCE_INVITES).
+
+       * doc/readme.features: Remove documentation for unused features
+       (TIMESEC, CRYPT_OPER_PASSWORD, oper/locop privileges,
+       HIS_DESYNCS), update defaults for SOCKSENDBUF and SOCKRECVBUF, and
+       add documentation for ANNOUNCE_INVITES.
+
+       * include/ircd_features.h: Remove unused features (TIMESEC,
+       CRYPT_OPER_PASSWORD, LIST_CHAN, HIS_DESYNCS).
+
+       * include/ircd_features.c: Likewise.
+
+       * ircd/ircd_res.c: Actually use FEAT_IRCD_RES_RETRIES and
+       FEAT_IRCD_RES_TIMEOUT where appropriate.
+
+       * ircd/s_debug.c: Do not display setting of unused (and now
+       non-existent) FEAT_CRYPT_OPER_PASSWORD.
+
+2004-09-10  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/os_generic.c (sockaddr_from_irc): Fix IPv4 implementation
+       to use the correct address family and IP offset.
+
+2004-09-10  Michael Poole <mdpoole@troilus.org>
+
+       * include/s_conf.h (struct ConfItem): Add origin and origin_name
+       fields.
+
+       * ircd/ircd_parser.y: Add new global variable "origin."  Add a new
+       "connectionvhost" production that accepts vhost = "IP" inside a
+       Connect block and assigns the IP to origin_name.
+
+       * ircd/s_bsd (connect_inet): If aconf has a valid origin, use it
+       as the local address.  Otherwise, fall back to the old logic (if
+       VIRTUAL_HOST="TRUE", use the virtual host setting).
+
+       * ircd/s_conf.c (lookup_confhost): If the ConfItem has an
+       origin_name, try to parse it as an IP address.
+
+2004-04-17  Isomer <isomer@undernet.org>
+       * ircd/parse.c: Don't rate limit /gline messages
+
+2004-09-10  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/ircd_parser.y: Replace references to yylval.whatever with
+       references to the appropriate term.  This fixes bugs like
+       "1 hour 30 minutes" being misrecognized as 30 seconds.
+
+2004-09-10  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/ircd_features.c (features): Change default values for
+       SOCKSENDBUF and SOCKRECVBUF to SERVER_TCP_WINDOW, so that users
+       need not specify them in ircd.conf.
+
+2004-09-10  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/ircd_parser.y (serverblock): Server blocks should default
+       to CONF_LEAF status.
+
+       * doc/example.conf: Update example to reflect this.
+
+2004-09-10  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/parse.c (msg_tree_parse): Reject commands that contain
+       non-alphabetic characters.
+
+2004-09-09  Michael Poole <mdpoole@troilus.org>
+
+       * config.h.in: Remove duplicated and unused macro definitions.
+
+2004-08-24  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/client.h: Properly parenthesize "flag" argument to
+       FLAGSET_INDEX() and FLAGSET_MASK() macros.
+
+2004-08-22  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/channel.c (send_channel_modes): If oplevels are disabled,
+       send 'o' for chanops instead of the member's oplevel.
+
+2004-08-22  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/s_conf.c: find_conf_byip() should use irc_in_addr_cmp()
+       instead of memcmp().  (Fixes IPv4 servers linking to an IPv6
+       server.)
+
+2004-08-22  Alex Badea  <decampos@users.sourceforge.net>
+
+       * include/ircd_defs.h: increased SOCKIPLEN to fit ipv6 addresses
+
+2004-08-19  Michael Poole <mdpoole@troilus.org>
+
+       * include/res.h: Remove unused function gethost_byname_type().
+
+       * ircd/ircd_res.c: Likewise, and clean up some small functions
+       only used once (remove_dlink(), timeout_resolver()).  Use rand()
+       for random request IDs instead of the deprecated *rand48().  Make
+       resolver timeout event fire only when needed instead of once a
+       second.
+
+2004-08-17  Michael Poole <mdpoole@troilus.org>
+
+       IPv6 support, with lots of code and design borrowed from a patch
+       by Alex Badea.
+
+       * config.h.in: Add place to #define IPV6 support.
+
+       * configure.in: Check for struct sockaddr_in6, and use that as
+       the default choice for IPv6 support.
+
+       * configure: Regenerate.
+
+       * include/IPcheck.h, include/client.h, include/gline.h,
+       include/ircd_string.h, include/listener.h, include/match.h,
+       include/res.h, include/s_bsd.h: Convert from struct in_addr (from
+       <netinet/in.h>) to struct irc_in_addr (from "res.h").
+
+       * include/ircd_osdep.h, include/s_conf.h, include/uping.h: Convert
+       from struct sockaddr_in (from <netinet/in.h>) to struct
+       irc_sockaddr (from "res.h").  Add new functions os_socket(),
+       os_accept(), os_sendto_nonb() to help abstract away actual
+       sockaddr types.
+
+       * include/ircd_chattr.h, ircd/table_gen.c: Define new bit to mark
+       characters valid in IPv6 addresses.
+
+       * include/numnicks.h, ircd/numnicks.c: New functions iptobase64()
+       and base64toip() to convert from base64 to struct irc_in_addr.
+
+       * ircd/IPcheck.c, ircd/channel.c, ircd/m_nick.c, ircd/m_oper.c,
+       ircd/m_userip.c, ircd/m_who.c, ircd/m_whois.c, ircd/s_misc.c,
+       ircd/s_serv.c, ircd/s_user.c, ircd/whocmds.c: Use struct
+       irc_in_addr instead of unsigned int or struct in_addr.
+
+       * ircd/gline.c: Use new more-generic ipmask functions.
+
+       * ircd/ircd.c: Use struct irc_sockaddr instead of separate port
+       fields.
+
+       * ircd/ircd_reslib.c: Use struct irc_sockaddr and ircd_aton()
+       instead of irc_ssaddr and irc_getaddrinfo().
+
+       * ircd/ircd_string.c: Implement new functions: IPv6-capable
+       ircd_ntoa_r(), ircd_aton_ip4(), ircd_aton().
+
+       * ircd/match.c: Delete IPv4-only matchcompIP().  Replace with
+       IPv6-capable ipmask_parse() and ipmask_check().
+
+       * ircd/numnicks.c: Implement new functions: iptobase64() and
+       base64toip().
+
+       * ircd/os_generic: Convert external parameters to be struct
+       irc_addrinfo.  When using IPv6 support, sockaddr_in6 is native.
+       Implement new functions os_sendto_nonb(), os_socket() and
+       os_accept().
+
+       * ircd/ircd_auth.c, ircd/ircd_parser.y, ircd/ircd_res.c,
+       ircd/listener.c, ircd/m_connect.c, ircd/s_auth.c, ircd/s_bsd.c,
+       ircd/s_conf.c, ircd/s_stats.c, ircd/uping.c: Use struct
+       irc_sockaddr instead of separate in_addr and port fields and new
+       OS support functions.
+
+       * include/ircd_addrinfo.h, ircd/ircd_getaddrinfo.c,
+       ircd/ircd_getnameinfo.c: Remove, since these functions are no
+       longer used.
+
+       * ircd/os_bsd.c, ircd/os_linux.c, ircd/os_openbsd.c,
+       ircd/os_solaris.c, ircd/res_adns.c, ircd/res_libresolv.c: Remove,
+       since these are unused and not compatible with IPv6 support.
+
+       * ircd/Makefile.in: Remove references to ircd_getXxxxinfo.c.
+       Regenerate dependencies.
+
+2004-08-17  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/ircd_lexer.l: Change tokenizer to reduce number of lexer
+       states and be case-insensitive again.
+
+2004-08-15  Michael Poole <mdpoole@troilus.org>
+
+       * aclocal.m4: Check for uintNN_t instead of u_intNN_t, since the
+       former is from C99 (and the latter is absent on Solaris).
+
+       * configure.in: Remove check for inttypes.h (which is a C99 format
+       string header); replace with check for stdint.h.  Add checks for
+       sys/param.h and sys/socket.h.  Check for socklen_t being defined
+       (OS X does not set it).  Run program tests for lex and yacc, and
+       use them rather than assuming flex and bison.  Remove OSDEP_C and
+       mention to adns.  Remove check for res_mkquery().
+
+       * config.h.in: Update u_intNN_t #undef lines.  Add #undef
+       socklen_t so configure test can set it.
+
+       * configure: Regenerate.
+
+       * include/ircd_addrinfo.h: #include headers needed for netdb.h and
+       to define struct addrinfo and uintNN_t.
+
+       * include/ircd_reslib.h: Replace u_intNN_t with uintNN_t.
+
+       * include/res.h: #include "ircd_addrinfo.h" to get proper type
+       definitions.  #define INADDR_NONE if it is not defined (as on
+       Solaris).
+
+       * ircd/Makefile.in: Replace LEX and YACC definitions.  Remove
+       OSDEP_C and OSDEP_SRC; always compile os_generic.c.  Remove adns
+       directory from CPPFLAGS.  Regenerate dependencies.
+
+       * ircd/client.c: Return when no propagation set for oper, to
+       squash warning about use of "defaults" before it is set.
+
+       * ircd/engine_epoll.c: #include correct C99 integer header.
+
+       * ircd/engine_poll.c: Last argument to getsockopt() should be of
+       socklen_t, not size_t; fix.
+
+       * ircd/engine_select.c: Squash warning about bzero().
+
+       * ircd/ircd_auth.c: OS X does not define in_addr_t, so replace it
+       with uint32_t.  We need <stdint.h> for that, so include it.
+
+       * ircd/ircd_getnameinfo.c, ircd/memdebug.c: Replace u_int32_t with
+       uint32_t.
+
+       * ircd/ircd_lexer.l: Replace flex-isms with portable syntax.
+       There is no portable way to do %option, so remove that.  lex on
+       Solaris needs several of its internal tables to be bigger, so
+       increase those sizes.
+
+       * ircd/ircd_parser.y: Remove the second declarations of two
+       tokens, since standard yacc warns about changing precedence.
+
+       * ircd/os_generic.c: Make this compile on common OSes (Linux,
+       Solaris, OS X, FreeBSD, OpenBSD).
+
+       * ircd/table_gen.c: Make arguments to isprint() all unsigned char
+       to squash warnings on Solaris that array index is "char."
+
+       * ircd/umkpasswd.c: Remove #include <libgen.h> since it is not
+       portable, and replace basename() with an equivalent.
+
+       * ircd/uping.c: Typecast printf arguments for 64-bit OSes.
+
+2004-07-27  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/m_burst.c: Add new netride_modes() function to check
+       which modes could be used in a net.ride.  Use this instead
+       of the old check for just +i or +k.
+       (Based on patches by beware and pomac.)
+
+2004-07-25  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/ircd_parser.y: Remove redundant semicolon; it causes
+       errors on some versions of yacc.
+
+2004-07-21  Michael Poole <mdpoole@troilus.org>
+
+       * include/client.h, ircd/ircd_auth.c, ircd/ircd_crypt_smd5.c,
+       ircd/ircd_reslib.c: Fix warnings from gcc -pedantic.
+
+2004-07-21  Michael Poole <mdpoole@troilus.org>
+
+       New DNS resolver code, courtesy of Dianora and the rest of the
+       Hybrid team.  (Bugs are of course my fault.)
+
+       * configure.in, Makefile.in, ircd/Makefile.in: Remove adns and
+       libresolv from the build process.  Update dependencies.
+
+       * configure: Regenerate.
+
+       * include/client.h: Change connection's DNS reply type.
+
+       * include/ircd_features.h, ircd/ircd_features.c: New HIS_STATS_a.
+
+       * include/numeric.h, ircd/s_err.c, ircd/s_stats.c: Add new
+       RPL_STATSALINE and /stats a to list DNS servers.
+
+       * include/ircd_addrinfo.h, include/ircd_reslib.h, include/res.h,
+       ircd/ircd_getaddrinfo.c, ircd/ircd_getnameinfo.c, ircd/ircd_res.c,
+       ircd/ircd_reslib.c: New resolver files.
+
+       * ircd/ircd_auth.c, ircd/s_auth.c, ircd/s_bsd.c, ircd/s_conf.c:
+       Update to new resolver callback interface and to only deal with
+       one IP and one name per DNS reply.
+
+       * ircd/parse.c: Remove /DNS command, since new resolver does not
+       track those statistics.
+
+2004-07-20  Michael Poole <mdpoole@troilus.org>
+
+       * doc/readme.features: Change references to O:, Y:, etc lines into
+       references to the appropriate block types.
+
+2004-07-01  Michael Poole <mdpoole@troilus.org>
+
+       * include/fileio.h: Elaborate on "works for any file descriptor."
+
+       * include/iauth.h: Remove unused file.
+
+2004-07-01  Michael Poole <mdpoole@troilus.org>
+
+       * include/map.h, ircd/map.c: Remove unused code.
+
+       * ircd/m_links.c, ircd/m_map.c, ircd/s_misc.c: Remove includes of
+       map.h and a call to map_update().
+
+       * ircd/Makefile.in: Remove map.c and regenerate dependencies.
+
+       * ircd/ircd_parser.y: Recognize Diane Bruce as a copyright holder
+       for the new config parser.
+
+       * ircd/match.c: Remove pointless pointer dereference (Reed points
+       out that this generates a warning with old gcc).
+
+       * ircd/s_user.c: Display connection class in CONNEXIT connection
+       notice as a string rather than an integer.
+
+       * tools/ringlog.c, tools/ringlog.pl: At Kevin's request, remove
+       lines (falsely) identifying ringlog as related to IRC; the files
+       are general purpose.
+
+       * configure.in, include/ircd_snprintf.h: Add checks for
+       va_copy()-like alternatives and use them if va_copy() is missing.
+
+       * configure, config.h.in: Regenerate.
+
+2004-02-01  beware <steendijk@xs4all.nl>
+
+       * ircd/channel.c: Check bans that look like IP bans against user's
+       hostname just in case they have a host like 1234.domain.tld.
+
+2003-12-18  Timothy Grant Vogelsang <net@astrolink.org>
+
+       * ircd/ircd_log.c, ircd/send.c: va_list is not a scalar type
+
+2004-04-02  Gavin Grieve <hektik@dimebox.net>
+
+       * ircd/ircd_parser.y: Fix rehash warnings for servername and
+       numeric so they only warn if changed in the config file.
+
+2004-06-30  Michael Poole <mdpoole@troilus.org>
+
+       * doc/readme.iauth, include/ircd_auth.h, ircd/ircd_auth.c: New
+       files.
+
+       * doc/example.conf: Illustrate IAUTH configuration.
+
+       * include/client.h: Add fields to record IAUTH status.
+
+       * ircd/Makefile.in: Add ircd_auth.c to Makefile.
+
+       * ircd/ircd_lexer.l, ircd/ircd_parser.y: Add new IAUTH section.
+
+       * ircd/s_conf.c: Notify IAUTH code when reloading a configuration
+       so that an obsolete connection can be abandoned.
+
+       * ircd/s_misc.c: Report client exits via IAUTH.
+
+       * ircd/s_user.c: If IAUTH is active and a connecting user has not
+       been checked against it, interrogate the IAUTH server.
+
+2004-06-25  Michael Poole <mdpoole@troilus.org>
+
+       * configure.in: Check for crypt.h as well.
+
+       * configure: Regenerate.
+
+       * ircd/ircd_crypt_native.c: Move XOPEN defines earlier so they
+       affect the first includes of system headers.  Include crypt.h if
+       it is available.
+
+       * ircd/umkpasswd.c: Quash a gcc warning.
+       
+2004-06-23  Michael Poole <mdpoole@troilus.org>
+
+       * doc/Authors: Add contributors to ircu2.10.11 and myself.
+
+       * ircd/gline.c: Fix buglet in my forward port of Alex Badea's fix.
+
+       * configure.in: Add missing check for inttypes.h; remove obsolete
+       display of Head-in-sand, add display of epoll() engine.
+
+       * INSTALL, INSTALL_FR, doc/readme.cvs: Update descriptions of how
+       to use SourceForge's CVS server, from the u2.10.11 branch.
+
+2003-11-09 beware <steendijk@xs4all.nl>
+
+        * ircd/s_user.c: move assigning a numeric to a local client from
+       when nick is set, to when connection becomes client, to not waste
+       numerics.
+
+2004-06-08  Kevin L Mitchell  <klmitch@mit.edu>
+
+       * ircd/parse.c: don't let rank-and-file users escape HIS
+       limitations with /jupe...
+
+2004-06-18  Alex Badea  <decampos@users.sourceforge.net>
+
+       * ircd/gline.c (gline_lookup): only return a gline if it's
+       active
+
+       * ircd/s_conf.c (find_kill): don't check for active gline,
+       since gline_lookup does now
+
+2002-11-11  hikari <shadow@undernet.org>
+       * ircd/ircd.c: added call to irc_crypt_init() - someone hurry up and 
+       modularise :P
+
+       * ircd/ircd_xopen.c: removed, superseded by new crypto system.
+
+       * ircd/ircd_crypt.c: wrote scary ircd_crypt() interface function,
+       wrote ircd_crypt_mech_register() function, various other bits 
+       designed to create a near-pluggable crypto system for ircu.  currently
+       this code also loads the various mechanisms i've written code for.
+
+       * ircd/ircd_crypt_smd5.c: imported the crypt_md5 function from 
+       elsewhere, manipulated to suit ircu, returns a salted MD5 password.
+
+       * ircd/ircd_crypt_native.c: replaces the old ircd_xopen.c file,
+       generate a crypted password using the systems native crypt() function.
+
+       * ircd/ircd_crypt_plain.c: plain text crypt mechanism, should really
+       only be used for testing purposes.
+
+       * ircd/ircd_md5.c: main gubbins of the MD5 hashing code, lifted from
+       elsewhere, ircuified.
+
+       * ircd/umkpasswd.c: mkpasswd program for ircu.
+
+       * include/ircd_xopen.h: removed, superseded by new crypto system.
+
+       * include/ircd_crypt.h: external definitions for the new ircd_crypt()
+       function and definition of the ircd_crypt_mech structure for containing
+       crypto mechanism data.
+
+       * include/ircd_crypt_smd5.h: sundary definitions for the salted MD5
+       mechanism.
+
+       * include/ircd_crypt_native.h: sundary definitions for the native 
+       crypt() mechanism.
+
+       * include/ircd_crypt_plain.h: sundary definitions for the plain text
+       mechanism.
+
+       * include/umkpasswd.h: fluff for umkpasswd.
+
+2003-03-11  Landon Fuller (landonf) <landonf@sf.net>
+
+       * configure.in: allow ircu to build on OS X.
+
+2004-05-24  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/m_invite.c (m_invite): Include channel name in invitation
+       announcements.
+       (ms_invite): Likewise, and also fix a use-before-assignment bug in
+       them.
+
+2004-05-18  Michael Poole <mdpoole@troilus.org>
+
+       Announce invitations to other channel operators.
+
+       * include/ircd_features.h, ircd/ircd_features.c
+       (ANNOUNCE_INVITES): Add new boolean feature, default off.
+
+       * include/numeric.h, ircd/s_err.c (RPL_ISSUEDINVITE): Add new
+       reply.
+
+       * include/send.h, ircd/send.c (sendcmdto_channel_butserv_butone):
+       Add 'skip' parameter that is needed elsewhere.
+       (sendcmdto_channel_servers_butone): New function.
+
+       * ircd/channel.c, ircd/m_burst.c, ircd/m_kick.c, ircd/m_topic.c,
+       ircd/s_user.c: Add argument for 'skip' to calls to s_c_b_b.
+
+       * ircd/m_invite.c (m_invite, ms_invite): If ANNOUNCE_INVITES, send
+       the INVITE message to all interested servers, and send a numeric
+       to all local chanops.
+
+2004-05-18  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/res_adns.c (res_ourserver): Remove unused function.
+       (validate_name): Likewise.
+
+2004-05-17  Michael Poole <mdpoole@troilus.org>
+
+       * include/ircd_features.h, ircd/ircd_features.c, ircd/s_debug.c:
+       Rip out feature settings related to oper privileges.
+
+       * include/client.h: Comment a few unexplained privileges.
+
+       * ircd/ircd_lexer.l: Rename privilege keywords to match their
+       names in code and /PRIVS output.  Add support for two "new"
+       privileges (FORCE_OPMODE, FORCE_LOCAL_OPMODE).
+
+       * include/class.h, ircd/client.c, ircd/ircd_parser.y,
+       ircd/m_oper.c: Replace the removed feature settings with
+       per-connection class operator privileges.
+
+       * doc/example.conf: Document the change.
+
+       * ircd/ircd_parser.y (portblock): Fix slight memory leak.
+
+2004-05-16  Michael Poole <mdpoole@troilus.org>
+
+       * doc/example.conf: Make this show the new NICKLEN default.
+
+2004-05-14  Kevin L Mitchell  <klmitch@mit.edu>
+
+       * ircd/ircd_features.c: per CFV-0243, NICKLEN default is increased
+       to 12
+
+2004-05-14  Kevin L Mitchell  <klmitch@mit.edu>
+
+       * ircd/s_user.c: process account creation timestamp if present in
+       user mode portion of a N protocol message; add account creation
+       timestamp to outgoing N protocol messages if that timestamp is
+       non-zero
+
+       * ircd/m_account.c: process account creation timestamp if present
+       in AC protocol message
+
+       * include/struct.h: add account creation timestamp
+
+2004-05-16  Michael Poole <mdpoole@troilus.org>
+
+       * doc/example.conf: Document operator privilege settings.
+
+2004-05-16  Michael Poole <mdpoole@troilus.org>
+
+       Get rid of CONF_LOCOP; use PRIV_PROPAGATE instead.
+
+       * ircd/ircd_parser.y (invert): New variable.
+       (operlocal): Remove production.
+       (operpriv): Use "invert" variable.
+       (privtype): Add LOCAL alternative production.
+
+       * ircd/m_oper.c (m_oper): Remove references to CONF_LOCOP; replace
+       with CONF_OPERATOR or PRIV_PROPAGATE checks, as appropriate.
+
+       * ircd/s_conf.c (AuthorizationCheckResult, find_conf_exact):
+       Likewise.
+
+       * ircd/s_stats.c (report_array, statsinfo): Likewise.
+
+       * ircd/s_user.c (set_user_mode): Likewise.
+
+2004-05-15  Michael Poole <mdpoole@troilus.org>
+
+       * patches/diffs/astralnet.diff, patches/diffs/nocfv.diff: Remove
+       patches obsoleted by F: lines.
+
+       * patches/diffs/topicburst.diff: Remove patch that was integrated
+       into the main code.
+
+2004-05-15  Isomer <isomer@undernet.org>
+
+       [Original ChangeLog date: 2003-11-05 -MDP]
+
+       * ircd/m_whois.c: On remote whois, show +s local channels with a *
+       prefix to opers.
+
+2004-05-15  Michael Poole <mdpoole@troilus.org>
+
+       * include/gline.h, ircd/gline.c, ircd/s_err.c: Forward port a lot
+       of gline-related fixes from 2.10.11.  Things that work are due to
+       Kev, Isomer, Spike, hikari, and probably others; CVS makes it hard
+       to figure out who did what.  Any mistakes are mine.
+
+2004-05-15  Isomer <isomer@undernet.org>
+
+       [Original ChangeLog date: 2003-11-05 -MDP]
+
+       * ircd/s_misc.c, ircd/s_user.c: added numnick to SNO_CONNEXIT
+       messages (so you can match EXIT's to CONN's)
+
+2004-05-15  Reed Loden <reed@reedloden.com>
+
+       [Original ChangeLog date: 2003-05-01 -MDP]
+
+       * ircd/s_err.c: Added network to text and edited 001 a bit.
+
+       * ircd/s_user.c: Send network with 001.
+
+2004-05-15  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/s_user.c (add_target): Move free target invite check...
+
+       * ircd/s_user.c (check_target_limit): to here, matching 2.10.11's
+       behavior.
+
+2004-05-15  Isomer <isomer@undernet.org>
+
+       [Original ChangeLog date: 2003-11-23 -MDP]
+
+       * ircd/s_user.c: Don't credit users with an extra attempt if they
+       are klined/glined, throttle them!
+
+2004-05-15  Jeekay <jeekay@netgamers.org>
+
+       [Original ChangeLog date: 2003-04-24 -MDP]
+
+       * ircd/s_user.c: Altered (K-lined) to depend on find_kill type
+
+2004-05-15  splidge <splidge@quakenet.org>
+
+       [Original ChangeLog date: 2003-09-03 -MDP]
+
+       * ircd/s_user.c: Made hide_hostmask() not show bogus joins for
+       channels where the user is a zombie.
+
+2004-05-15  beware <steendijk@xs4all.nl>
+
+       [Original ChangeLog date: 2003-10-25 -MDP]
+       
+        * ircd/m_whois.c: Fixed /whois comma separated list with wildcards
+       cpu hog bug
+
+2004-05-15  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/s_conf.c (rehash): Call clear_quarantines on rehash since
+       2.10.11 does.  Show ident and IP for clients being killed by new
+       G-lines and K-lines.
+
+2004-05-15  hikari <shadow@undernet.org>
+
+       [Original ChangeLog date: 2003-06-27 -MDP]
+       
+       * ircd/ircd.c: After thought, update the next check time based on
+       when an unregistered client should expire.
+
+2004-05-15   hikari <shadow@undernet.org>
+
+       [Original ChangeLog date: 2003-06-22 -MDP]
+
+       * ircd/ircd.c: Fixed check_pings() - shouldn't be any problem with
+       clients not being able to connect anymore.
+
+2004-05-15  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/channel.c (can_join): Revert to using IsInvited() rather
+       than walking the list directly.
+       (modebuf_flush_int): Fix errant HEAD_IN_SAND_SNOTICES check to
+       use feature_bool(FEAT_HIS_SNOTICES) instead.
+
+2004-05-15  Kevin L Mitchell  <klmitch@mit.edu>
+
+       [Original ChangeLog date: 2004-01-31 -MDP]
+
+       * ircd/channel.c (mode_parse_key): don't allow , in keys!
+
+2003-04-12  David Mansell (splidge) <splidge@sf.net>
+
+       [Original ChangeLog date: 2003-04-14 -MDP]
+
+       * ircd/channel.c: When keys and limits conflict on burst, the key
+       which is first alphabetically or the limit which is lower will be 
+       used by both servers. This matches pre-2.10.11 behaviour.  
+       Closes: (#713930)
+
+2004-05-15  David Mansell <splidge@quakenet.org>
+
+       [Original ChangeLog date: 2002-12-28 -MDP]
+
+       * ircd/channel.c (mode_parse_limit): don't allow -l when no limit is
+       set, don't allow -l with negative parameter (or unsigned >2^31).
+2004-05-15  David Mansell <splidge@quakenet.org>
+
+       [Original ChangeLog date: 2002-12-31 -MDP]
+
+       * ircd/m_burst.c (ms_burst): when kicking net riders, clear
+       invites too.
+
+2004-05-15  Isomer <isomer@undernet.org>
+
+       [Original ChangeLog date: 2003-11-04 -MDP]
+
+       * ircd/s_serv.c: Burst glines/jupes early
+
+2004-05-15  volta <volta2@gmx.de>
+
+       [Original ChangeLog date: 2003-04-26 -MDP]
+
+         * ircd/m_userip.c, ircd/m_userhost.c: Small fix, that
+         allows users to see their own ip & hostname. (Should solve
+         all problems with dcc)
+
+2004-05-15  Kevin L Mitchell  <klmitch@mit.edu>
+
+       [Original ChangeLog date: 2003-06-13 -MDP]
+
+       * ircd/m_settime.c: it's supposed to be %ld, not %l
+
+2004-05-15  Isomer <isomer@undernet.org>
+
+       [Original ChangeLog date: 2004-03-20 -MDP]
+
+       * ircd/m_invite.c: Disallow invites to non existant channels
+
+2004-05-15  David Mansell <splidge@quakenet.org>
+
+       [Original ChangeLog date: 2003-04-26 -MDP]
+
+       * ircd/m_invite.c: let +k users invite into channels they aren't on.
+
+2004-05-15  hikari <shadow@undernet.org>
+
+       [Original ChangeLog date: 2003-07-13 -MDP]
+       
+       * ircd/IPcheck.c: Fixed (another) overflow problem in
+       ip_registry_check_local()
+
+       [Original ChangeLog date: 2003-06-29 -MDP]
+
+       * ircd/IPcheck.c: Fixed overflow problem in
+       ip_registry_connect_fail()
+
+2004-05-15 Isomer <isomer@undernet.org>
+
+       [Original ChangeLog date: 2003-05-02 -MDP]
+       
+       * ircd/IPcheck.c: Added assert()'s to check for underflow
+
+2004-05-15  Kevin L Mitchell  <klmitch@mit.edu>
+
+       [Original ChangeLog date: 2003-11-22 -MDP]
+
+       * tools/wrapper.c: commit uid on chroot fix from ubra
+
+       * ircd/version.c.SH: fix generation generation
+
+2004-05-15  Isomer <isomer@undernet.org>
+
+       [Original ChangeLog date: 2003-11-23 -MDP]
+       
+       * ircd/os_*.c, ircd/ircd_features.c: Default changing window sizes
+       to off.  if an admin is smart enough to understand these features
+       they can enable them manually.
+
+2004-05-15  splidge  <splidge@quakenet.org>
+
+       [Original ChangeLog date: 2003-03-26 -MDP]
+
+       * ircd/include/ircd_features.h, include/ircd_osdep.h,
+         ircd/ircd_features.c, ircd/listener.c, ircd/os_bsd.c, 
+         ircd/os_generic.c, ircd/os_linux.c, ircd/os_openbsd.c
+         ircd/os_solaris.c, ircd/s_bsd.c: Patch to allow socket bufs to be 
+         altered via F: lines
+
+2004-05-15  Isomer <isomer@undernet.org>
+
+       [Original ChangeLog date: 2003-11-18 -MDP]
+
+       * ircd/s_auth.c, ircd/res_libresolv.c, ircd/res_adns.c: Clean up
+       the preregistration subsystem allowing customisation of timers,
+       make the dns resolver stats oper only, and make it much more clear
+       what all the numbers are.
+
+2004-05-15  Spike <spike@undernet.org>
+
+       [Original ChangeLog date: 2003-11-23 -MDP]
+
+       * ircd/IPcheck.c: Make IPcheck constants configurable
+
+2004-05-14  Kevin L Mitchell  <klmitch@mit.edu>
+
+       [Original ChangeLog date: 2003-11-22 -MDP]
+
+       * ircd/m_nick.c (m_nick): truncate the nickname to the minimum of
+       the maximum allowed length (NICKLEN) or the allowed nickname
+       length specified as the NICKLEN feature
+
+       * ircd/ircd_features.c: declare NICKLEN and set its default value
+       to 9
+
+       * include/supported.h: add MAXNICKLEN to ISUPPORT and do a little
+       rearranging...
+
+       * include/ircd_features.h: add NICKLEN feature
+
+       * include/ircd_defs.h (NICKLEN): raise max NICKLEN to 15
+
+       * doc/readme.features: document new NICKLEN feature
+
+       * doc/example.conf: list new NICKLEN F-line
+
+2004-05-14  Matthias Crauwels <ultimate_@wol.be>
+
+       [Original ChangeLog date: 2003-06-08 -MDP]
+       
+       * ircd/gline.c: fixed the counting bug in gline_memory_count
+       * ircd/jupe.c: fixed the counting bug in jupe_memory_count
+
+2004-05-14  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/m_mode.c (ms_mode): Do not always try to call
+       set_user_mode() when parv[1] is a channel name.
+
+2004-05-10  Michael Poole <mdpoole@troilus.org>
+
+       Implement a per-connection-class default usermode option.
+
+       * doc/example.conf: Illustrate how to use the option.
+
+       * include/class.h (struct ConnectionClass): New "default_umode"
+       field.
+       (ConfUmode): New macro.
+
+       * include/client.h (client_get_default_umode): New function.
+
+       * ircd/client.c (client_get_default_umode): Implement it.
+
+       * ircd/ircd_lexer.l (usermode): New token.
+
+       * ircd/ircd_parser.y (classblock, etc): New syntax.
+
+       * ircd/s_user.c (register_user): Set default user modes for user.
+       This sends the new mode to the user, so the explicit send later
+       is no longer necessary.
+
+2004-05-10  Michael Poole <mdpoole@troilus.org>
+
+       Forward port of asuka-topicburst.patch from Quakenet's "Asuka"
+       patch set.
+
+       * include/ircd_features.h (FEAT_TOPIC_BURST): Add new feature.
+
+       * ircd/channel.c (send_channel_modes): If F:TOPIC_BURST:TRUE,
+       also send a TOPIC to the peer.
+
+       * ircd/ircd_features.c (FEAT_TOPIC_BURST): Add new boolean
+       feature, defaulting to FALSE.
+
+       * ircd/m_topic.c (do_settopic): Add argument for topic timestamp,
+       and allow F:HIS_BANWHO to hide the originator of the topic.
+       (ms_topic): Parse optional timestamp arguments to TOPIC, and use
+       them to decide whether to ignore the topic.
+
+2004-05-10  Michael Poole <mdpoole@troilus.org>
+
+       Forward port of delayed-join.patch from Quakenet's "Asuka" patch
+       set (which was a port of code I wrote for the other ircu).
+
+       * include/channel.h (CHFL_DELAYED): New membership flag.
+       (MODE_DELJOINS, MODE_WASDELJOINS): New channel modes.
+       (infochanmodes): Add +D to list of supported channel modes.
+       (IsDelayedJoin, SetDelayedJoin, ClearDelayedJoin): New macros.
+       (member_can_send_to_channel, client_can_send_to_channel): Add
+       "reveal" parameter to indicate whether a request should cause
+       a join-delayed user to become visible.
+       (RevealDelayedJoin, CheckDelayedJoins): New functions.
+
+       * include/numeric.h (RPL_DELNAMREPLY): New numeric.
+       
+       * include/s_user.h (NAMES_DEL): New flag for do_names().
+
+       * include/supported.h (FEATURESVALUES2): Add +D to list of
+       supported channel modes.
+
+       * ircd/channel.c (remove_member_from_channel,
+       member_can_send_to_channel, client_can_send_to_channel,
+       joinbuf_join): Handle join-delayed users.
+       (channel_modes, modebuf_flush_int, modebuf_mode, modebuf_flush,
+       modebuf_extract, mode_process_clients, mode_parse_mode,
+       mode_parse): Handle delayed-join channels.
+       (RevealDelayedJoin, CheckDelayedJoins): New functions.
+
+       * ircd/ircd_relay.c (relay_channel_message, relay_channel_notice,
+       server_relay_channel_message, server_relay_channel_notice): Add
+       argument for "reveal" parameter to client_can_send_to_channel().
+
+       * ircd/m_burst.c (ms_burst): Support MODE_DELJOINS channels.
+
+       * ircd/m_clearmode.c (do_clearmode): Support clearing mode +D.
+
+       * ircd/m_join.c (join0): Pass the CHFL_DELAYED flag when parting a
+       channel with JOIN 0.
+
+       * ircd/m_kick.c (m_kick): For join-delayed members, only send the
+       KICK to the kicker and kickee.  Then check whether +d can be
+       removed.
+
+       * ircd/m_names.c (do_names): Show join-delayed users if and only
+       if the NAMES_DEL flag is given.  If NAMES_DEL is given, also use
+       RPL_DELNAMREPLY instead of RPL_NAMREPLY.
+       (m_names): If NAMES -D, pass NAMES_DEL to do_names().
+
+       * ircd/m_part.c (m_part, ms_part): Add "reveal" argument for
+       member_can_send_to_channel().  Set CHFL_DELAYED join in joinbuf if
+       the user is join-delayed.
+
+       * ircd/m_quit.c (m_quit): Handle join-delayed users and new
+       argument for member_can_send_to_channel().
+
+       * ircd/m_topic.c (do_settopic): If a join-delayed channel member
+       changes the topic, reveal the member.
+
+       * ircd/m_wallchops.c (m_wallchops, ms_wallchops): Add argument for
+       "reveal" parameter to client_can_send_to_channel().
+
+       * ircd/m_wallvoices.c (m_wallvoices, ms_wallvoices): Likewise.
+
+       * ircd/m_who.c (m_who): Skip join-delayed members where we skip
+       zombies.
+
+       * ircd/m_whois.c (do_whois): Use '<' as a prefix for join-delayed
+       users.  Use slightly more efficient macros rather than function
+       calls to test for ops and voice.
+
+       * ircd/s_err.c (RPL_DELNAMREPLY): New numeric response string.
+
+       * ircd/s_user.c (hide_hostmask): For users with no modes in a
+       join-delayed channel, do not send JOIN to other members after the
+       QUIT :Registered.
+
+       * ircd/send.c (sendcmdto_common_channels_butone): Skip
+       join-delayed users where we skip zombies.
+       
+2004-05-10  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/ircd_events.c: Actually reference and try to use the epoll
+       event engine.  Omitted from yesterday's commit.
+
+2004-05-09  Michael Poole <mdpoole@troilus.org>
+
+       Forward port of Paul "Zoot" Chang's pseudo-command.patch and
+       pseudo-support.patch.
+
+       * doc/example.conf: Illustrate how to use the feature.
+
+       * include/handlers.h (m_pseudo): Declare new handler function.
+
+       * include/ircd_features.h (HIS_STATS_R): Add a feature to control
+       user visibility of the pseudo-commands.
+
+       * include/msg.h: Add flag and field for the extra information used
+       to select a pseudo-command's target.
+
+       * include/numeric.h (RPL_STATSRLINE, ERR_SERVICESDOWN): Add
+       definitions.
+
+       * include/parse.h (register_mapping, unregister_mapping): Declare.
+
+       * include/s_conf.h (struct nick_host, struct s_map,
+       GlobalServiceMapList): Define.
+
+       * ircd/Makefile.in: Add m_pseudo.c to IRCD_SRC.  Add generated
+       files to "make depend" dependency list.  Update dependencies.
+
+       * ircd/ircd_features.c (HIS_STATS_R): Define feature type and
+       default value.
+
+       * ircd/ircd_lexer.l (pseudo, prepend): Recognize new tokens.
+
+       * ircd/ircd_parser.y: Support "Pseudo" configuration blocks.
+
+       * ircd/parse.c (msgtab): Add initializer for field "extra" to all
+       commands.
+       (msg_tree_insert, msg_tree_remove, register_mapping,
+       unregister_mapping): New functions.
+       (parse_client): Implement MFLG_EXTRA extra argument passing.
+
+       * ircd/s_conf.c (GlobalServiceMapList): New variable.
+
+       * ircd/s_err.c (RPL_STATRLINE, ERR_SERVICESDOWN): Add format
+       strings for new numeric responses.
+
+       * ircd/s_stats.c (stats_mapping): New function.
+       (statsinfo): Add entry for /stats R and make old /stats r entry
+       case-sensitive.
+       
+2004-05-09  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/ircd_parser.y (parse_error): Convert to being a wrapper for
+       yyerror() so that configuration errors all go to the same place.
+
+       * ircd/s_conf.c: New variables conf_error and conf_already_read.
+       conf_error is cleared by read_configuration_file() and set by
+       yyerror(); conf_already_read is set by read_configuration_file()
+       and never cleared.  Make yyerror() display error to stderr before
+       conf_already_read is set.  Make configuration errors a fatal
+       condition in init_conf().
+
+2004-05-09  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/Makefile.in: Pass the source directory as an argument to
+       version.c.SH so it knows where to find the source files for an
+       out-of-srcdir build.
+
+       * ircd/version.c.SH: Use that information.
+
+2004-05-09  Michael Poole <mdpoole@troilus.org>
+
+       * Makefile.in: Ensure ${prefix}/include exists, since the adns
+       install puts files in that directory.  (The adns Makefile does
+       not use configure's ${includedir}.)
+
+2004-05-09  Michael Poole <mdpoole@troilus.org>
+
+       * doc/readme.features: The logic for F:AUTOHIDE was removed, but
+       not its documentation.  Fix that omission.
+
+       * include/ircd_features.h, ircd/ircd_features.c: Remove the unused
+       definitions for FEATURE_AUTOHIDE.
+
+2004-05-09  Michael Poole <mdpoole@troilus.org>
+
+       * doc/readme.who: Document the support for account matching and
+       display in the WHO command.
+
+2004-05-09  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/ircd.c (main): Move check_pid() call until after we read
+       the configuration file so that F:PPATH works correctly.
+
+2004-05-09  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/match.c (match): Use ToLower() instead of tolower() for
+       character comparisons.
+
+2004-05-09  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/s_user.c (register_user): Initialize "flag" (user's old
+       modes) passed to send_umode() so that the real set of modes are
+       sent to the user.
+       
+2004-05-09  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/m_server.c (ms_server): Apply +h/+s flags only to the new
+       server, not to a hub between us and the new server.
+
+       * ircd/ircd_relay.c (relay_directed_message): Check FLAG_SERVICE
+       on target server rather than FLAG_CHSERV (so that directed
+       messages work at all).
+
+2004-05-09  Michael Poole <mdpoole@troilus.org>
+
+       * configure.in: Add checks for epoll_* system call family.
+
+       * configure: Regenerate.
+
+       * ircd/engine_epoll.c: New file; forward ported from 2.10.11
+       branch.
+
+2004-05-09  Michael Poole <mdpoole@troilus.org>
+
+       * include/ircd_alloc.h: Add definitions for MyRealloc, since they
+       are needed by kqueue and epoll event engines; kill #if 0'd block.
+
+       * include/memdebug.h: Declare dbg_realloc() helper function.
+
+       * ircd/ircd_alloc.c: Implement DoRealloc() helper function.
+
+       * ircd/memdebug.c: Implement dbg_realloc() helper function.
+
+2004-05-09  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/channel.c (find_no_nickchange_channel): Disallow nick
+       changes on a moderated channel with neither ops nor voice.
+
+       * ircd/s_err.c: Update ERR_BANNICKCHANGE message to match.
+
+2004-01-20  Perry Lorier <isomer@undernet.org>
+
+       * ircd/ircd_parser.y: Fixed parser to work with a more modern bison
+
+2004-01-21 Gavin Grieve <hektik@dimebox.net>
+
+       * ircd/channel.c, include/channel.h: bring forward the IsUserParting()
+         code to resolve the multiple part messages bug written by Entrope.
+
+2003-08-12 Timothy Vogelsang <net@astrolink.org>
+
+        * ircd/match.c: (match) rewrote function based on existing
+          code from the hybrid ircd -- death to goto
+
+2003-07-07  Bas Steendijk <steendijk@xs4all.nl>
+
+        * ircd/s_user.c: invalidate ban cache for user on host hiding/account
+
+2003-07-04  Bas Steendijk <steendijk@xs4all.nl>
+
+        * include/client.h, ircd/m_userhost.c, ircd/m_userip.c, ircd/m_who.c,
+        ircd/m_whois.c, ircd/whocmds.c: the same code, for "can user A see user
+        B is an oper", appeared in a lot of places. made it a define SeeOper.
+
+2003-07-04  Bas Steendijk  <steendijk@xs4all.nl>
+        * ircd/s_user.c: umode_str (user modes in N token) internal flags var
+       was not initialized to the user's flags, returned a string with
+       random modes set.
+
+2003-07-01  Bas Steendijk  <steendijk@xs4all.nl>
+
+        * ircd/m_names.c: length counter being incremented one too many
+        for each nick, resulting names reply messages are about 50 chars
+        shorter than possible. fixed.
+
+2003-06-29  Bas Steendijk  <steendijk@xs4all.nl>
+
+        * ircd/channel.c: don't ever send mode changes for local channels to
+       servers.
+
+2003-06-27  Bas Steendijk  <steendijk@xs4all.nl>
+
+        * include/channel.h, include/client.h, ircd/s_user.c, ircd/s_err.c:
+        moved the supported channel/user mode strings of the 004 reply from
+        s_err.c to the header files where the channels/user modes are
+        defined, and show or hide +Au based on OPLEVELS setting.
+
+2003-06-25  Bas Steendijk  <steendijk@xs4all.nl>
+
+        * ircd/m_burst.c: Clear topic set by netrider on burst.
+
+2003-08-05 Diane Bruce  <db@db.net>
+
+        * ircd/parse.c: Fixed the typo the fix of the typo created
+
+2003-08-01 Diane Bruce  <db@db.net>
+
+       * ircd/parse.c: Fixed typo
+
+2003-06-22  Diane Bruce  <db@db.net>
+
+       * ircd/parse.c: Completely rewritten June 2, 2003 - Dianora
+
+2003-06-22  Bas Steendijk  <steendijk@xs4all.nl>
+
+        * include/ircd_features.h, include/supported.h, ircd/ircd_features.c,
+       ircd/ircd_features.c, ircu2.10/ircd/m_join.c, doc/example.conf: 
+       Make ability to create local channels a feature which can be disabled.
+
+2003-06-22  Bas Steendijk  <steendijk@xs4all.nl>
+
+       * include/ircd_features.h, ircd/channel.c, ircd/ircd_features.c,
+       ircd/m_kick.c, doc/example.conf: Added OPLEVELS feature, which
+       makes it possible to disable the +Au/oplevels functions.
+
+2003-06-17  Alex Badea  <vampire@p16.pub.ro>
+
+       * ircd/res_adns.c: included sys/types.h, for non-Linux
+       headers
+
+2003-03-06  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * libs/dbprim: database primitives library, including
+       flexible linked lists, auto-resizing hash tables, and sparse
+       matrices.  Has a test suite for everything but portions of
+       the sparse matrix routines (I'm lazy; someone help me write
+       them!).  Documentation generated by doxygen--feel free to
+       critique, suggest phrasing improvements, etc.
+
+2003-01-22  Kevin L. Mitchell  <klmitch@mit.edu>
+       * libs: put third-party libraries in this subdirectory.
+       Started by copying adns into it--will fix the rest and remove
+       the top-level copy later.
+
+2003-01-14  Andrew Miller <a1kmm@mware.virtualave.net>
+       * ircd/m_settime.c: Fixed a minor format string issue.
+       
+2003-01-12  Thomas Helvey <tom.helvey@cox.net>
+       * adns/src/check.c, adns/src/transmit.c, ircd/m_opmode.c,
+       ircd/motd.c, ircd/s_user.c: Cleanup warnings, fix precedence
+       bugs in transmit.c and m_opmode.c.
+
+2003-01-12  Thomas Helvey <tom.helvey@cox.net>
+       * include/class.h, include/ircd_string.h, ircd/class.c,
+       ircd/gline.c, ircd_string.c: Fix undefined order
+       of evaluation bug in gline.c, add general purpose hasher for
+       conf entries. 
+
+2003-01-11  Thomas Helvey <tom.helvey@cox.net>
+       * include/channel.h, include/ircd_alloc.h, ircd/channel.c,
+       ircd/client.c, ircd/gline.c, ircd/ircd_alloc.c,
+       ircd/ircd_events.c, ircd/ircd_log.c, ircd/ircd_parser.y,
+       ircd/ircd_snprintf.c, ircd/listener.c, ircd/m_nick.c,
+       ircd/m_opmode.c, ircd/m_whois.c, ircd/motd.c,
+       ircd/s_auth.c, ircd/s_bsd.c, ircd/uping.c: Server compiles
+       with g++ again, type safety, const correctness fixes,
+       remove C++ keywords again :/
+
+2003-01-11  Thomas Helvey <tom.helvey@cox.net>
+       * ircd/client.c, ircd/ircd_feature.c: Bugfix, the feature
+       table data was in a different order than the feature data
+       structure, which resulted in a wild index being used in
+       feature_bool. The feature_bool function didn't check it's
+       index before indexing the features array resulting in
+       a core dump on /oper.
+
+2003-01-10  Thomas Helvey <tom.helvey@cox.net>
+       * include/client.h, include/res.h, include/s_bsd.h,
+       ircd/ircd.c, ircd/list.c ircd/m_connect.c, ircd/res_adns.c,
+       ircd/res_libresolv.c, ircd/s_auth.c, ircd/s_bsd.c, ircd/s_conf.c:
+       Remove resolver cache wart, change hostent representation, cleanup
+       resolver clients.
+
+2003-01-10  Thomas Helvey <tom.helvey@cox.net>
+       * ircd/map.c, ircd/Makefile.in, include/map.h: Remove 
+        HEAD_IN_SAND macros to get server to build, rebuild dependencies.
+
+2003-01-08  Fredrik Soderblom <froo@quakenet.org>
+        * ircd/s_err.c, ircd/s_user.c (hide_hostmask): Simplify
+        RPL_HOSTHIDDEN and the use of it.
+
+2003-01-07  Kevin L Mitchell  <klmitch@mit.edu>
+
+       * BUGS: removed from distribution
+
+       * ChangeLog.07: moved into doc/history
+
+       * ChangeLog.10: moved into doc/history
+
+       * INSTALL: pulled up from u2.10.11.04
+
+       * README: pulled up from u2.10.11.04
+
+       * README.FreeBSD: pulled up from u2.10.11.04
+
+       * README.Solaris: pulled up from u2.10.11.04
+
+       * RELEASE.NOTES: add sysctl note from u2.10.11.04
+
+       * TODO: removed from distribution
+
+       * configure.in: add extra check for res_mkquery; remove
+       --disable-headinsand since it no longer has any effect; pull up
+       "Enable" vs. "Disable" changes from u2.10.11.04
+
+       * doc/readme.asll: pulled up from u2.10.11.04
+
+       * doc/readme.features: pull up missing documentation, including a
+       couple of corrections
+
+       * doc/readme.log: correct text to read FACILITY instead of SYSLOG
+       in the documentation for configuring syslog facility
+
+       * include/channel.h: declare IsInvited()
+
+       * include/handlers.h: do some minor reorderings
+
+       * include/ircd_defs.h: remove deprecated NETWORK and URL_CLIENTS
+       #define's
+
+       * include/ircd_policy.h: removed from the distribution
+
+       * include/jupe.h: declare jupe_memory_count()
+
+       * include/msgq.h: remove MsgCounts structure
+
+       * include/numeric.h: add a blank line after RPL_STATSQLINE; add
+       RPL_HOSTHIDDEN
+
+       * include/s_stats.h: include ircd_features.h for definition of the
+       enum; remove extraneous declarations
+
+       * ircd/Makefile.in: add LDFLAGS to table_gen
+
+       * ircd/engine_poll.c: remove commented-out assertion
+
+       * ircd/ircd.c: include s_stats.h and call stats_init()
+
+       * ircd/ircd_features.c: feature names have to be case-sensitive
+       because of some of the HIS features
+
+       * ircd/ircd_relay.c: reorder includes
+
+       * ircd/m_account.c: include string.h for strlen()
+
+       * ircd/m_clearmode.c: remove extraneous clean_channelname(); make
+       sure to refer to chname, not parv[1]
+
+       * ircd/m_create.c: remove the broken code that squits servers that
+       are >5 minutes fast; fix "badop || CHFL_CHANOP" bug that caused op
+       desyncs
+
+       * ircd/m_gline.c: if it's a server, force the gline; don't
+       gline_find() before determining if the oper had the privilege
+
+       * ircd/m_kick.c: kicks by servers should appear to be from the
+       local server thanks to HIS
+
+       * ircd/m_lusers.c: needs ircd_features.h, not ircd_policy.h
+
+       * ircd/m_map.c: needs ircd_features.h, not ircd_policy.h
+
+       * ircd/m_nick.c: added an assertion and some explanatory comments
+       pulled up from u2.10.11.04
+
+       * ircd/m_opmode.c: no longer requiring oper to be on the channel;
+       search for quarantines before allowing ops
+
+       * ircd/m_privmsg.c: one character typo that probably means nothing
+
+       * ircd/m_settime.c: add back comments I left in the code
+
+       * ircd/m_squit.c: remove protocol_violation() notices
+
+       * ircd/m_userhost.c: return realhost if user is an oper
+
+       * ircd/m_wallvoices.c: only m_wallvoices() should add a +
+
+       * ircd/m_who.c: add handling for the 'a' field
+
+       * ircd/m_whois.c: correct a typo of FEAT_HIS_SERVERNAME for
+       FEAT_HIS_SERVERINFO
+
+       * ircd/s_bsd.c: close file descriptors 0, 1, and 2; pull up some
+       ancient bug fixes from the u2.10.11 branch
+
+       * ircd/s_debug.c: include gline.h, jupe.h, motd.h, and s_stats.h;
+       call motd_memory_count(), gline_memory_count(), and
+       jupe_memory_count() when reporting memory usage; add back a
+       comment regarding "DBuf caveats"
+
+       * ircd/s_err.c: add RPL_STATSQLINE, RPL_HOSTHIDDEN, and pull up
+       change to ERR_NOPRIVILEGES wording
+
+       * ircd/s_misc.c: include ircd_features.h and not ircd_policy.h
+
+       * ircd/s_stats.c: count from 0 and not 1 when initializing the
+       stats
+
+       * ircd/s_user.c: comment out assertion; remove extraneous
+       definition of FLAGS_HOST_HIDDEN; add in hikari's "your host is now
+       hidden" reply; don't detach oper confs unless sptr is not an oper
+
+       * ircd/table_gen.c: pull up change to NTL_CHPFX (removing +);
+       change channel name character range to be from '\041' (!) to
+       UCHAR_MAX
+
+       * ircd/whocmds.c: pull up fix to /who idle time from u2.10.11.04
+
+       * tools/linesync/linesync.conf: pull up from u2.10.11.04
+
+       * tools/linesync/linesync.sh: pull up from u2.10.11.04
+
+2003-01-07 Andrew Miller <a1kmm@mware.virtualave.net>
+       * almost everything: Forward ported numerous changes from .11 to .12
+       
+2002-07-05 Andrew Miller <a1kmm@mware.virtualave.net>
+       * ircd/packet.c(connect_dopacket): Pass the job on to server_dopacket
+       when they become a server.
+       * ircd/s_bsd.c(read_packet): Check they are now a server *after* the
+       packet is sent.
+       * ircd/class.c(make_class): Fixed an assert to be more useful.
+       
+2002-07-05 Andrew Miller <a1kmm@mware.virtualave.net>
+       * ircd/packet.c
+       * ircd/packet.h: (connect_dopacket): Made a dopacket function for
+       connecting links which sends the messages through the correct message
+       handler.
+       * ircd/s_bsd.c(read_packet): Put packets through the correct handler
+       for connecting links. Properly handle unknown links becoming
+       connecting or servers.
+
+2002-07-01 Andrew Miller <a1kmm@mware.virtualave.net>
+       * include/ircd_alloc.h (MyFree): Accept NULL pointers to do nothing
+       with, this is used quite a lot.
+       * ircd/class.c (make_class): Initialise the ref_count to 1 so that
+       we don't leak.
+       * ircd/class.c (add_class): When updating a class, free the old name
+       first to prevent leakage.
+       * ircd/class.c (class_delete_marked): Decrement the ref_count for the
+       class after it is removed from the linked list.
+       * ircd/ircd_parser.y: Changed a free to MyFree().
+       * ircd/ircd_parser.y: Removed a few debugging messages.
+
+2002-07-01 Andrew Miller <a1kmm@mware.virtualave.net>
+       * s_bsd.c (read_packet): Our daily addition to the list of entities to
+       treat as servers - Connecting servers.
+       
+2002-07-01 Andrew Miller <a1kmm@mware.virtualave.net>
+       * doc/debug_memleak_gc.patch,
+       * include/ircd_ircd_alloc.h,
+       * include/memdebug.h,
+       * configure.in,
+       * ircd/Makefile.in,
+       * ircd/memdebug.c: added a Boehm's gc based leak detector to find leaks
+       and notify the operators.
+       
+2002-06-29  Andrew Miller <a1kmm@mware.virtualave.net>
+
+       * ircd/s_bsd.c (read_packet): don't make handshaking servers go through
+       the dbufs.
+       
+2002-06-18  Andrew Miller <a1kmm@mware.virtualave.net>
+
+       * ircd/s_bsd.c (read_packet): don't allow unregistered clients to flood
+       the server.
+       
+2002-06-18  Alex Badea  <vampire@p16.pub.ro>
+
+       * ircd/m_burst.c (ms_burst): kick local members if the channel
+       has a larger local TS and it's +i or +k remotely (anti net.ride)
+
+       * ircd/ircd_parser.y: fixed a bug that broke IP-based C:lines
+
+       * ircd/s_err.c: connection classes are now strings (RPL_STATSCLINE)
+
+       * include/s_conf.h: externalized lookup_confhost
+
+       * adns/Makefile.in: compilation-outside-source-tree fix
+
+2002-06-17  Alex Badea  <vampire@p16.pub.ro>
+
+       * adns/*: added a slightly hacked copy of adns
+
+       * configure.in: added a --disable-adns switch if you want
+       to use the old libresolv res.c
+
+       * configure: ran autoconf
+
+       * ircd/res_libresolv.c: renamed from res.c
+
+       * ircd/res_adns.c: added adns resolver
+
+2002-06-17  Alex Badea  <vampire@p16.pub.ro>
+
+       * ircd/ircd_parser.y: fixed 'Connect' block processing so now
+       you can actually connect to other servers
+
+2002-06-04  Alex Badea  <vampire@p16.pub.ro>
+
+       * ircd/m_stats.c (report_servers_verbose): oops, fixed it so
+       it displays all servers, not just local connects
+
+2002-05-30  Jean-Edouard Babin  <Jeb@jeb.com.fr>
+
+       * ircd/m_server.c (mr_server): fixed core bug on insufficient
+       arguments
+
+2002-05-26  Jeekay  <jeekay@irc.planetarion.com>
+       
+       * ircd/m_join.c (HasControlChars): fixed unsigned vs signed
+
+2002-05-26  Jeekay  <jeekay@irc.planetarion.com>
+       * ircd/m_join.c (m_join,HasControlChars): check if a channel
+       name has any control chars (<=32) in it before allowing a
+       local user to join.
+2002-21-05 Andrew Miller <a1kmm@mware.virtualave.net>
+       * ircd/ircd_relay.c: stop an information leak about the
+       the network topography from relayed messages.
+
+2002-04-19  Alex Badea  <vampire@p16.pub.ro>
+
+       * ircd/m_who.c (m_who): disallow non-opers to /who server.name
+
+2002-04-18  Alex Badea  <vampire@p16.pub.ro>
+
+       * ircd/s_err.c (RPL_STATSILINE): connection classes are now
+       strings
+
+2002-04-17  beware <steendijk@tomaatnet.nl>
+
+       * m_whois.c (m_whois): disallow remote queries for non-existent
+       local users when originated by a non-oper
+
+2002-04-16  Alex Badea  <vampire@p16.pub.ro>
+
+       * ircd/s_user.c (hunt_server_cmd): also send a "no such server"
+       reply if the servername contains a '*' and it doesn't exist
+
+       * include/patchlevel.h (PATCHLEVEL): bump patchlevel
+
+2002-04-16  beware <steendijk@tomaatnet.nl>
+
+       * ircd/m_whois.c: the previous patch broke whois, fixed it
+       another way
+
+       * ircd/m_admin.c: cleaned up m_admin too while we're here,
+       hunt_server_cmd can do all the work for us
+
+2002-04-15  Alex Badea  <vampire@p16.pub.ro>
+
+       * ircd/m_stats.c: added verbose server reporting (/stats v
+       or /stats V for machine-readable format) (bugzilla bug 52)
+
+       * include/numeric.h: added RPL_STATSVERBOSE 236
+
+       * ircd/s_err.c: added RPL_STATSVERBOSE
+
+       * ircd/s_stats.c: added help for stats 'v'
+
+2002-04-15  Alex Badea  <vampire@p16.pub.ro>
+
+       * ircd/class.c (get_client_class): fixed typo which caused
+       /trace (and perhaps motd) to core
+
+2002-04-15  beware <steendijk@tomaatnet.nl>
+
+       * ircd/m_whois.c: Fixed /whois servermask nomatch bug
+       where normal users could use the function to discover servers,
+       also the NOSUCHSERVER check code was missing.
+
+2002-04-14  Alex Badea  <vampire@p16.pub.ro>
+
+       * ircd/ircd_parser.y: fixed cli_info(&me) not being set
+       from 'description' conf
+
+2002-04-13  Stephane Thiell <mbuna@undernet.org>
+
+       * ircd/m_whois.c: removed FindUser() in ms_whois to fix
+       remote whois relaying.
+
+       * ircd/class.c: removed unused (and duplicated) code
+       get_client_ping().
+       
+       * include/class.h: removed unused function prototype.
+       
+       * config.guess: upgraded with latest
+       
+       * config.sub: upgraded with latest
+
+2002-04-12  Alex Badea  <vampire@p16.pub.ro>
+
+       * ircd-patch: report which files failed the dry run (so the
+       user may force the patch if the rejects are in less-than-vital
+       files, such as ChangeLog or documentation)
+
+2002-04-12  Alex Badea  <vampire@p16.pub.ro>
+
+       * ircd/m_invite.c: don't propagate invites for local channels
+
+       * include/patchlevel.h (PATCHLEVEL): bump patchlevel
+
+2002-04-10 Joseph Bongaarts <foxxe@wtfs.net>
+
+       * ircd/ircd.c: The last fix broke autoconnects completely.
+       Fixed it another way.
+       
+2002-04-09  Brian Cline  <clineb@cs.winthrop.edu>
+
+        * ircd/ircd.c (try_connections): To avoid problems with infinite event
+        loops, don't try connecting to servers whose connect frequency is 0.
+       
+2002-04-10  Alex Badea  <vampire@p16.pub.ro>
+
+       * ircd/ircd_parser.y: fixed a "features" block parse bug
+
+       * tools/convert-conf.py: added a configuration file converter
+       from 2.10.11 to 2.10.12 format
+
+       * ircd-patch: added GPL information to top of file
+
+2002-04-09  Alex Badea  <vampire@p16.pub.ro>
+
+       * configure.in: added a human-readable report of configured
+       options at the end of the configure process
+
+       * configure: regenerated with autoconf
+
+2002-04-08  Gavin Grieve  <ggrieve@ihug.co.nz>
+
+       * include/supported.h: change CHARSET to CASEMAPPING after
+       discussions as to what would be the preferred name.
+
+2002-04-05 Andrew Miller <a1kmm@mware.virtualave.net>
+       * ircd/s_conf.c, ircd_parser.y, ircd_lexer.l: Add privilege
+       specification.
+        * Fix a minor parser bug that meant rehash didn't always
+       work correctly.
+
+2002-04-03  Alex Badea  <vampire@p16.pub.ro>
+
+       * include/channel.h: fix compiler warnings (paratheses around &&)
+
+       * ircd/channel.c (modebuf_extract): fix compiler warnings
+       (uninitialized variables)
+
+       * ircd/Makefile.in: make ircd properly compile outside the
+       source tree
+
+2002-04-03  Alex Badea  <vampire@p16.pub.ro>
+
+       * include/s_user.h: added a sptr parameter to InfoFormatter
+       function type
+
+       * ircd/m_who.c: don't match IPs for clients which have a hidden host,
+       except when the inquiring user is an oper
+
+       * ircd/whocmds.c: show the fake IP from FEAT_HIDDEN_IP if the
+       target has a hidden host, but show real IP to opers
+
+       * ircd/m_userip.c (userip_formatter): add sptr parameter; show the
+       fake IP from FEAT_HIDDEN_IP if the target has a hidden host, but
+       show real IP to opers
+
+       * ircd/m_userhost.c (userhost_formatter): add (unused) sptr parameter
+
+       * ircd/s_user.c (send_user_info): pass sptr to the formatting function
+
+       * include/ircd_features.h: new feature FEAT_HIDDEN_IP (stores which
+       fake IP to show for clients with a hidden host)
+
+       * ircd/ircd_features.c: new feature FEAT_HIDDEN_IP
+
+       * doc/example.conf: default value for FEAT_HIDDEN_IP
+
+       * doc/readme.features: documented FEAT_HIDDEN_IP
+
+2002-04-03 Andrew Miller <a1kmm@mware.virtualave.net>
+       * doc/example.conf: Cleaned up some comments that ended up in
+         strange places due to problems in the merge process.
+       * ircd/m_nick.c: Cleaned up ms_nick, and fixed a bug that
+         probably dates back to Jarkko code.
+
+2002-04-02  Kevin L Mitchell  <klmitch@mit.edu>
+
+       * ircd/m_kill.c: let ms_kill() and mo_kill() seperate the message
+       from the path before calling do_kill(); add a msg argument to
+       do_kill() and use it in preference to comment; remove all that old
+       code that fiddled with the buf and the comment
+
+       * ircd/ircd_log.c (log_write_kill): add a seperate msg argument
+
+       * include/ircd_log.h: add a seperate msg argument to
+       log_write_kill()
+
+       * ircd/ircd.c: display event engine and MAXCONNECTIONS information
+2002-04-02  Alex Badea <vampire@p16.pub.ro>
+
+       * ircd-patch: Automatically generate a version string from patches
+
+2002-04-02  Alex Badea <vampire@p16.pub.ro>
+       
+       * ircd-patch: Test before doing anything dangerous, provide -f to
+               to it anyway.  exit levels for easy scripting.
+
+2002-04-01  Kevin L Mitchell  <klmitch@mit.edu>
+
+       * ircd/channel.c (joinbuf_join): don't add a channel to the list
+       in the joinbuf unless when we flush it, we empty the list
+
+2002-04-02 Andrew Miller <a1kmm@mware.virtualave.net>
+       * ircd/ircd_parser.y: Added ircd parser, lexer, to replace the
+          old configuration file format.
+       * ircd/ircd_lexer.l
+       * ircd/s_conf.c
+       * doc/example.conf
+
+2002-03-23 Bert Faes <bert.faes@pandora.be>
+
+       * s_misc.c made /trace reply always show the username
+       
+2002-03-28  Kevin L Mitchell  <klmitch@mit.edu>
+
+       * configure.in: use AC_CHECK_FUNCS to define HAVE_* macros; test
+       for setrlimit, getrusage, and times
+
+       * configure: rerun auto-conf
+
+       * config.h.in: rerun autoheader
+
+2002-03-27  Kevin L Mitchell  <klmitch@mit.edu>
+
+       * ircd/m_burst.c (ms_burst): use MODEBUF_DEST_NOKEY to suppress
+       sending of the key to the channel
+
+       * ircd/channel.c (modebuf_flush_int): when processing keys, only
+       include the actual key in the mode sent to the channel if
+       MODEBUF_DEST_NOKEY is not set
+
+       * include/channel.h: needed more bits for MODEBUF_DEST_*,
+       especially when adding MODEBUF_DEST_NOKEY to force keys in the
+       BURST to be reported as "*" to the channel
+
+       * ircd/m_oper.c (m_oper): clear the new oper's sendq so it gets
+       inherited from the class associated with the O-line
+
+2002-03-25  Kevin L Mitchell  <klmitch@mit.edu>
+
+       * ircd/s_user.c (set_nick_name): invalidate all ban valid caching
+       when a user changes his nickname so we can catch if he now matches
+       a ban
+
+2002-03-20 Reed Loden <reed@redmagnet.com>
+       * doc/example.conf: Added OPER_LIST_CHAN and LOCOP_LIST_CHAN.
+
+       * doc/readme.features: Added OPER_LIST_CHAN and LOCOP_LIST_CHAN.
+
+2002-03-20 LordLuke <lordluke@undernet.org>
+       * ircd/client.c: Add LOCOP_LIST_CHAN feature.
+
+       * ircd/ircd_features.h: Add LOCOP_LIST_CHAN feature.
+
+2002-03-19 Joseph Bongaarts <foxxe@wtfs.net>
+
+       * ircd/m_links.c: Make /links behave like /map for head_in_sand.
+       cleaned up excess code.
+
+       * ircd/map.c: Added map_dump_links_head_in_sand() Made changes in
+       map_add() and map_update() for links changes.
+
+       * include/map.h: Added info and prot to struct Map
+
+       * include/ircd_defs.h: Added MAP_CACHE_TIME for length of time
+       servers are cached in MapList
+
+       * ircd/s_misc.c: changed #ifdef for map_update()
+
+       * ircd/m_server.c: changed #ifdef for map_update()
+
+       * include/ircd_policy.h: added NO_HEAD_IN_SAND for easier removal of
+       hiding features.
+
+       * configure.in: add --disable-headinsand
+
+       * configure: Ran autoconf
+
+       * ircd/m_stats.c: Fixed a bug in /stats i and made /stats i show 
+       connect limits
+
+       * ircd/s_stats.c: Made /stats i report connect limits
+
+       * ircd/s_err.c: Modified RPL_STATSILINE to use %s instead of 
+       "*" for the password field.
+       
+2002-03-19 LordLuke <lordluke@undernet.org>
+
+       * include/channel.h: Allow opers to view +s channels in /list
+
+       * include/client.h: Add "PRIV_LIST_CHAN" oper privilege
+
+       * include/ircd_features.h: added "LIST_CHAN" feature
+
+       * ircd/channel.c: Allow opers to view +s channels in /list
+
+       * ircd/client.c: Add "PRIV_LIST_CHAN"
+
+       * ircd/ircd_features.c: Add "LIST_CHAN" feature
+
+2002-03-13 Joseph Bongaarts <foxxe@wtfs.net>
+
+       * ircd/m_kill.c: Last of the last of the bug fixes (Thanks Spike).
+       Must be more careful when forward porting by hand...
+       
+2002-03-13  Carlo Wood  <run@alinoe.com>
+
+       * include/channel.h: CHFL_CHANNEL_MANAGER, new local
+       channel flag set when someone creates a channel or joins
+       using the Apass.  IsChannelManager(), SetChannelManager():
+       macros to manipulate new channel flag.
+       channel_modes: Added new argument to avoid calling
+       find_member_link more often than needed.
+
+       * include/numeric.h: RPL_APASSWARN, ERR_NOTLOWEROPLEVEL,
+       ERR_NOTMANAGER, ERR_CHANSECURED, ERR_UPASSSET,
+       ERR_UPASSNOTSET: new numeric replies.
+
+       * ircd/channel.c: is_level0_op: removed.
+       member_can_send_to_channel: disallow channel manager
+       to talk.  channel_modes: show upass to level0 ops.
+       mode_parse_upass: Only the channel manager is allowed
+       to change the upass.  Only allow to set upass when apass
+       is also set.  mode_parse_apass: Don't allow to change the
+       Apass if the channel is older than 48 hours.  Only allow
+       to remove the apass when upass is not set.  Send clear
+       warnings regarding the importance of apass.
+       mode_process_clients: Don't change the oplevel of an opped
+       member in a channel where upass is not set.
+
+       * ircd/destruct_event.c: exec_expired_destruct_events:
+       Bug fix: send DESTRUCT message when destructing a channel.
+
+       * ircd/m_destruct.c: ms_destruct: Bug fix: use self as
+       prefix for DESTRUCT message.
+
+       * ircd/m_join.c: m_join: Handle apass and upass.
+
+       * ircd/m_kick.c: m_kick: Don't allow to kick member with
+       a higher or equal op-level.
+
+       * ircd/m_mode.c: m_mode: Now pass member to channel_modes.
+       ms_mode: Allow server to do modes on channels with apass
+       set.
+
+       * ircd/s_err.c: RPL_APASSWARN, ERR_NOTLOWEROPLEVEL,
+       ERR_NOTMANAGER, ERR_CHANSECURED, ERR_UPASSSET,
+       ERR_UPASSNOTSET: new numeric replies.
+
+
+2002-03-10 Joseph Bongaarts <foxxe@wtfs.net>
+
+       * ircd/m_kill.c: Last of the bug fixes for do_kill()
+
+       * ircd/list.c: Don't remove clients from the linked list
+       that aren't actually in the list.
+       
+2002-03-08  Carlo Wood  <run@alinoe.com>
+       * include/channel.h: Added CHFL_BURST_ALREADY_OPPED
+       and CHFL_BURST_ALREADY_VOICED.
+
+       * ircd/m_burst.c: Allow BURST outside net-burst
+       and take into account that users are already joined
+       to the channel in that case.
+
+       * ircd/m_destruct.c: Implementation of DESTRUCT
+       handling code.
+
+       * ircd/m_join.c: Set the channel creationtime to
+       the timestamp of a message when that timestamp is
+       smaller.
+2002-02-27 Reed Loden <reed@redmagnet.com>
+       * tools/crypter: Updated some variables, added another notice,
+       added CVS Id tag, and updated Perl location.
+
+       * tools/ringlog.c: Added IRC - Internet Relay Chat, 
+       tools/ringlog.c
+
+       * tools/ringlog.pl: Added IRC - Internet Relay Chat, 
+       tools/ringlog.pl
+
+       * tools/wrapper.c: Added IRC - Internet Relay Chat, 
+       tools/wrapper.c
+
+       * tools/mkpasswd.c: Added CVS Id tag
+
+       * tools/sums: Updated to comply with sums being moved to tools/
+       and added CVS Id tag
+
+       * tools/README: Updated location of file and partly rewrote to fit 
+       u2.10.11's Features
+
+       * tools/Makefile.crypt: Updated location of file and added CVS Id 
+       tag
+
+       * acconfig.h: Updated location of file
+
+       * config.h.in: Updated location of file
+
+       * tools/Bounce/bounce.conf: Added CVS Id tag
+
+       * tools/Bounce/Bounce.cpp: Updated location of file
+
+       * tools/Bounce/Bounce.h: Updated location of file
+
+       * tools/hashtoy: Added CVS Id Tag
+
+2002-02-27  Carlo Wood  <run@alinoe.com>
+
+        * /ircd/ircd.c: check_pings: First check if a PING was sent at all.
+
+2002-03-01  Carlo Wood  <run@alinoe.com>
+
+       * include/channel.h: struct Channel: new attribute destruct_event.
+       Prototype for destruct_channel().
+
+       * include/destruct_event.h: new header file for destruct_event.c.
+
+       * ircd/Makefile.in: New source file: destruct_event.c.
+
+       * ircd/channel.c: sub1_from_channel: Don't destruct channel
+       immedeately but instead schedule it for destruction after
+       some time when a channel becomes empty (and clear invite
+       only and limit in that case).
+       destruct_channel: new function, was previously the destructing
+       part of sub1_from_channel.
+       add_user_to_channel: remove destruction request if any.
+
+       * ircd/destruct_event.c: New file.  Implementation of functions
+       schedule_destruct_event_1m, schedule_destruct_event_48h,
+       remove_destruct_event and exec_expired_destruct_events.
+
+       * ircd/ircd.c: destruct_event_timer: new timer.
+       main: use destruct_event_timer to call exec_expired_destruct_events
+       once per minute.
+
+       * ircd/m_endburst.c: ms_end_of_burst: Don't complain about empty
+       channels.  Schedule new empty channels for destruction.
+
+       * ircd/m_join.c: m_join: Destruct just-created channel immedeately.
+
+2002-03-01  Carlo Wood  <run@alinoe.com>
+       * ircd/s_misc.c: exit_client: Only call map_update()
+       for servers.
+
+2002-02-28  Carlo Wood  <run@alinoe.com>
+       * include/channel.h: New attribute 'oplevel' in struct Membership.
+       Added defines MAXOPLEVELDIGITS and MAXOPLEVEL.
+       New macros:  OpLevel(member): returns op-level of member and
+       SetOpLevel(member, value): sets op-level of member.
+       Prototype of add_user_to_channel: add oplevel to parameters.
+       Prototype of mode_parse: add member to to parameters.
+
+       * include/numeric.h: added ERR_NOTLOWEROPLEVEL.
+
+       * ircd/s_err.c: idem.
+
+       * ircd/channel.c: Removed unmatched '{' braces from comments
+       (confuses vi).  add_user_to_channel: oplevel is passed to function
+       and added in the created MemberShip structure.  send_channel_modes:
+       Generate the nick:mode list of the BURST msg in the new style (with
+       op-levels).  DONE_UPASS/DONE_APASS: fixed typo in comment.  struct
+       ParseState: New attribute: member.  mode_process_clients: Disallow
+       deopping someone with an equal or higher op-level, take care of
+       inheritance of op-level.  mode_parse: member is passed to function      
+       and added in the created ParseState structure.  joinbuf_join: pass 0
+       as oplevel to add_user_to_channel as needed initialization of oplevel
+       in struct MemberShip.
+
+       * ircd/m_burst.c: ms_burst: Implementation of op-levels in the
+       decoding of a BURST message and passing on a BURST message.
+       Renamed default_mode to current_mode.
+
+       * ircd/m_mode.c: m_mode/ms_mode: pass on `member' to mode_parse.
+
+       * ircd/m_opmode.c: ms_opmode/mo_opmode: pass on NULL as member
+       to mode_parse (causes opped member to get op-level 0).                  
+
+2002-02-25  Carlo Wood  <run@alinoe.com>
+       * include/channel.h: Added two new strings to struct Mode,
+       upass and apass, both with maximum length PASSLEN (a new
+       define in this file).  Two new mode defines MODE_UPASS and
+       MODE_APASS.
+
+       * ircd/channel.c: is_level0_op: Added as dummy function.
+       channel_modes/modebuf_flush_int/modebuf_extract/mode_parse:
+       Added support for MODE_APASS (+A) and MODE_UPASS (+u).
+       mode_parse_upass: New function to parse mode +u.
+       mode_parse_apass: New function to parse mode +A.
+
+       * ircd/s_err.c: Added 'A' and 'u' to mode list (RPL_MYINFO).            
+
+2002-02-25  Carlo Wood  <carlo@alinoe.com>
+
+       * ircd/m_server.c: remove unused variables
+
+2002-02-25 Joseph Bongaarts <foxxe@wtfs.net>
+
+       * ircd/m_map.c: Modified to show a useful output to non-opered
+         clients when HEAD_IN_SAND_MAP is defined. Servers are added to
+         the list when first seen (after receiving SERVER) and that list
+         is sent to clients. Servers are excluded from the list if they are
+         hubs, services, or have been missing for more than 1 week.
+       
+       * ircd/map.c: Created file for map_* functions
+
+       * include/map.h: Created file for map_* functions
+
+       * ircd/m_server.c: Added calls to map_update()
+
+       * ircd/s_misc.c: Added call to map_update()
+
+       * ircd/parse.c: Changed to use m_map() and mo_map()
+       
+2002-02-22 Reed Loden <reed@redmagnet.com>
+
+       * ircd/m_connect.c: Removed an extra : in remote connect message.
+
+2002-02-19 Joseph Bongaarts <foxxe@wtfs.net>
+
+        * ircd/whocmds.c: Local opers should also be able to
+        see servernames in /who
+
+       * ircd/gline.c: Fix core bug in gline_find()
+
+       * ircd/m_kill.c: Bug fix for HIS_KILLWHO
+
+2002-02-19 John Buttery <john@io.com>
+
+       * ircd/ircd.c: Updated "No such file" error message.
+       
+2002-02-18 Joseph Bongaarts <foxxe@wtfs.net>
+
+       * ircd/m_kill.c: Changed m_kill() to do_kill() because its not
+       a message handler, and some general cleanups and bug fixes. 
+
+       * include/ircd_policy.h: Added HEAD_IN_SAND_KILLWHO for hiding
+       kill source.
+       
+2002-02-16  Tim Vogelsang <net@astrolink.org>
+
+        * ircd/m_kill.c: added a new static function, m_kill, which
+        performs the actual kill.
+       
+2002-02-14 Joseph Bongaarts <foxxe@wtfs.net>
+
+       * Added support for LIST STOP
+       
+2002-02-13 Joseph Bongaarts <foxxe@wtfs.net>
+
+       * Merged changes from u2_10_11 to main branch.
+       
+2002-02-08  Tim Vogelsang  <net@astrolink.org>
+
+       * ircd/m_quit.c: don't prefix user quits with "Quit:" unless a
+       reason is supplied.
+
+2002-02-06  Kevin L Mitchell  <klmitch@mit.edu>
+
+       * ircd/s_auth.c (read_auth_reply): left out an = in an
+       assertion--shouldn't have had any impact, though
+
+       * ircd/Makefile.in: add a hook for using ringlog; run make depend
+
+       * tools/ringlog.c: for the heck of it, add a comment including
+       rules for /etc/magic
+
+2002-02-05  Kevin L Mitchell  <klmitch@mit.edu>
+
+       * tools/ringlog.pl: perl script to take output from ringlog and
+       pass it to addr2line to get function, file, and line number
+       information
+
+       * tools/ringlog.c: program/object to help in building function
+       trace information
+
+2002-02-04  Alex Badea  <vampire@p16.pub.ro>
+
+       * include/ircd_features.h: added new feature MOTD_BANNER
+
+       * ircd/ircd_features.c: added new feature MOTD_BANNER
+
+       * ircd/motd.c (motd_signon): send a one-line banner from
+       FEAT_MOTD_BANNER if it's not NULL and FEAT_NODEFAULTMOTD
+       is set
+
+       * doc/example.conf: default value for MOTD_BANNER feature
+
+       * doc/readme.features: documented the MOTD_BANNER feature
+
+2002-02-04  Kevin L Mitchell  <klmitch@mit.edu>
+
+       * ircd/s_debug.c (debug_serveropts): remove deprecated CHROOTDIR
+       check; added character 'A' to the server options string to
+       indicate when assertion checking is enabled
+
+2002-02-03  Kevin L Mitchell  <klmitch@mit.edu>
+
+       * include/patchlevel.h (PATCHLEVEL): bump patchlevel
+
+       * ircd/engine_kqueue.c (set_or_clear): don't generate an ET_ERROR
+       event if the errno is EBADF, since the caller probably already
+       knows about it and just hasn't gotten around to processing it yet
+
+       * ircd/ircd_events.c: set the GEN_ERROR flag if an ET_ERROR event
+       is generated; don't process socket_events() or socket_state() if
+       an error occurred; add GEN_ERROR to list of flags in gen_flags()
+
+       * include/ircd_events.h: define new GEN_ERROR flag; add a macro to
+       clear it
+
+2002-02-01  Kevin L Mitchell  <klmitch@mit.edu>
+
+       * ircd/channel.c: change make_nick_user_{ip,host} to not use a
+       static buffer--instead, a buffer of the right size (NUH_BUFSIZE or
+       NUI_BUFSIZE--I confess they're not well-named) is allocated by the
+       caller
+
+2002-02-02  Alex Badea  <vampire@p16.pub.ro>
+
+       * include/client.h: added user flag FLAGS_HIDDENHOST
+
+       * include/ircd_features.h: added FEAT_HOST_HIDING and
+       FEAT_HIDDEN_HOST
+
+       * include/numeric.h: defined numeric 338 (RPL_WHOISACTUALLY)
+       to report real hostnames and IPs to opers
+
+       * include/s_user.h: exported hide_hostmask()
+
+       * include/send.h: changed sendcmdto_channel_butserv to
+       sendcmdto_channel_butserv_butone; ditto for
+       sendcmdto_common_channels
+
+       * include/struct.h: added realhost to struct User
+
+       * include/whowas.h: added realhost to struct Whowas
+
+       * ircd/channel.c: match bans against both real and hidden
+       hostmasks; moved some calls to use sendcmdto_*_butone
+
+       * ircd/gline.c: match glines agains real host
+
+       * ircd/ircd_features.c: added FEAT_HOST_HIDING and
+       FEAT_HIDDEN_HOST
+
+       * ircd/m_account.c: call hide_hostmask() for possibly
+       hiding the user's host
+
+       * ircd/m_burst.c: moved some calls to use sendcmdto_*_butone
+
+       * ircd/m_topic.c: moved some calls to use sendcmdto_*_butone
+
+       * ircd/m_userip.c: report IP 127.0.0.1 if the user has a hidden
+       host
+
+       * ircd/m_who.c: match real hosts, if the query comes from an oper
+
+       * ircd/m_whois.c: report real hostname and IP to opers
+
+       * ircd/m_whowas.c: report real hostname to opers
+
+       * ircd/s_err.c: added user mode 'x' to the list of supported user
+       modes in RPL_MYINFO (004); added RPL_WHOISACTUALLY for reporting
+       real hostnames to opers
+
+       * ircd/s_misc.c: moved some calls to use sendcmdto_*_butone
+
+       * ircd/s_serv.c: send real hostname to servers
+
+       * ircd/s_user.c: send real hostname to servers; added processing
+       of usermode 'x'; added hide_hostmask() which actually does the work
+       of hiding a user's host; moved some calls to use sendcmdto_*_butone
+
+       * ircd/send.c: changed sendcmdto_channel_butserv to
+       sendcmdto_channel_butserv_butone; ditto for
+       sendcmdto_common_channels
+
+       * ircd/whocmds.c: extra letter 'x' in WHO reply if the user has
+       it's host hidden
+
+       * ircd/whowas.c: if needed, store a user's real host so we can
+       report it to opers later
+
+       * doc/readme.features: documented HOST_HIDING and HIDDEN_HOST
+       features
+
+       * doc/example.conf: default values for HOST_HIDING and
+       HIDDEN_HOST features
+
+2002-02-01  Tim Vogelsang  <net@astrolink.org>
+
+       * ircd/send.c (sendwallto_group_butone): don't sent wallops to
+       ordinary users
+
+2002-01-28  Kevin L Mitchell  <klmitch@mit.edu>
+
+       * ircd/jupe.c (jupe_activate): remove a bogus assertion
+
+       * include/patchlevel.h (PATCHLEVEL): bump patchlevel
+
+       * ircd/s_err.c: added new channel mode 'r' to list of supported
+       channel modes in RPL_MYINFO (004); migrated RPL_USERIP to use
+       numeric 340 instead of 307; add ERR_NEEDREGGEDNICK (477) for
+       informing users why they can't join a +r channel
+
+       * ircd/m_clearmode.c (do_clearmode): add support for MODE_REGONLY
+       (+r) to do_clearmode(); note that it is *not* being added to the
+       default clearmode mask!
+
+       * ircd/channel.c: don't allow non-+r users to send messages to +r
+       channels from off the channel; add support for MODE_REGONLY (+r)
+       to channel_modes(); don't allow non-+r users to join +r channels
+       without an invite; add support for MODE_REGONLY to the modebuf_*()
+       family of functions (changes in modebuf_flush_int(),
+       modebuf_mode(), and modebuf_extract()); add support for
+       MODE_REGONLY to mode_parse()
+
+       * include/supported.h (FEATURESVALUES2): added the new channel
+       mode 'r' to the list of supported channel modes
+
+       * include/numeric.h: move RPL_USERIP to 340 to avoid the 307
+       conflict; add ERR_NEEDREGGEDNICK (477) for the new +r channels
+
+       * include/channel.h: remove unused MODE_SENDTS; add new
+       MODE_REGONLY
+
+       * ircd/s_bsd.c (read_packet): remove call to timer_verify()
+
+       * ircd/list.c: remove calls to timer_verify() from
+       alloc_connection() and dealloc_connection()
+
+       * ircd/ircd_events.c: turn off timer_verify(); remove calls to it
+       from timer_run()
+
+2002-01-27  Kevin L Mitchell  <klmitch@mit.edu>
+
+       * include/patchlevel.h (PATCHLEVEL): bump patchlevel
+
+       * ircd/ircd_events.c (timer_run): why did I ever use a next
+       pointer when the algorithm guarantees that the head pointer will
+       always be the next pointer?
+
+2002-01-26  Kevin L Mitchell  <klmitch@mit.edu>
+
+       * include/patchlevel.h (PATCHLEVEL): bump patchlevel
+
+       * ircd/s_bsd.c (read_packet): call timer_verify() after adding the
+       client process timer to catch any list corruption
+
+       * ircd/list.c: surround alloc_connection() and
+       dealloc_connection() with calls to timer_verify()
+
+       * ircd/ircd_events.c: add sledgehammer known as timer_verify() to
+       verify the timer list's structure; call it around timer_run()
+
+2002-01-22  Kevin L Mitchell  <klmitch@mit.edu>
+
+       * ircd/send.c (sendcmdto_common_channels): don't send message to a
+       channel that the source is a zombie on
+
+2002-01-13  Kevin L Mitchell  <klmitch@mit.edu>
+
+       * ircd/ircd_events.c (timer_enqueue): one more assertion--make
+       sure a timer has the ACTIVE flag set before enqueueing the timer
+
+       * include/patchlevel.h (PATCHLEVEL): bump patchlevel
+
+       * ircd/list.c (dealloc_connection): assert that the process timer
+       has been removed from the timer queue before dealloc_connection()
+       is called
+
+2002-01-12  Kevin L Mitchell  <klmitch@mit.edu>
+
+       * ircd/res.c: don't accept T_A when we're looking for T_PTR
+
+       * ircd/channel.c (modebuf_flush_int): nuke the code that would
+       send a HACK DESYNCH notice on a HACK(2)--it would be far too
+       chatty
+
+       * ircd/m_away.c (user_set_away): use AWAYLEN instead of TOPICLEN
+
+       * include/supported.h: add AWAYLEN to the list of supported
+       features
+
+       * include/ircd_defs.h: add AWAYLEN to specify the maximum length
+       of an away message
+
+       * include/patchlevel.h (PATCHLEVEL): bump patchlevel
+
+       * ircd/m_mode.c (m_mode): pass extra parameter to channel_modes()
+
+       * ircd/channel.c: pass a buflen parameter to channel_modes() for
+       pbuf--we were using sizeof(pbuf), which would always be
+       sizeof(char*) before; change send_channel_modes() to pass extra
+       parameter to channel_modes()
+
+       * include/channel.h: pass a buflen parameter to channel_modes()
+       for pbuf
+
+       * include/patchlevel.h (PATCHLEVEL): bump patchlevel
+
+       * ircd/uping.c (uping_start): initialize some timers
+
+       * ircd/s_bsd.c (read_packet): use new t_onqueue() macro to figure
+       out when we need to re-add the process timer
+
+       * ircd/s_auth.c (make_auth_request): initialize a timer
+
+       * ircd/res.c (init_resolver): initialize some timers
+
+       * ircd/list.c (alloc_connection): initialize the client process
+       timer
+
+       * ircd/ircd_events.c: add a function, timer_init(), to initialize
+       a struct Timer; recast timer_add() to catch when adding a marked
+       timer and not re-enqueue it--but mark it for re-enqueuing; update
+       timer_del() to turn off the GEN_READD flag and to ignore reference
+       counts when destroying the timer--we're using GEN_MARKED as an
+       ersatz referance count; changed timer_run() to work with the new
+       way of doing things; add GEN_ACTIVE and GEN_READD to gen_flags()'s
+       map[]
+
+       * ircd/ircd.c: initialize some timers
+
+       * ircd/engine_select.c (engine_loop): initialize a timer
+
+       * ircd/engine_poll.c (engine_loop): initialize a timer
+
+       * ircd/engine_kqueue.c (engine_loop): initialize a timer
+
+       * ircd/engine_devpoll.c (engine_loop): initialize a timer
+
+       * ircd/IPcheck.c (IPcheck_init): initialize a timer
+
+       * include/ircd_events.h: add GEN_READD flag for timers to indicate
+       that a timer must be readded; add t_onqueue() macro to check to
+       see if a timer is on the queue (this is a hack, though); added
+       timer_init() to initialize a struct Timer--we're no longer doing
+       the initialization in timer_add()
+
+2002-01-11  Kevin L Mitchell  <klmitch@mit.edu>
+
+       * ircd/engine_devpoll.c (engine_loop): relocate an assertion to
+       prevent a core bug *in* the assertion
+
+       * doc/readme.features: document new POLLS_PER_LOOP feature; change
+       documentation to reflect that OPER_SET now defaults to FALSE
+
+       * doc/p10.html: documented the new ACCOUNT stuff
+
+       * doc/example.conf: document new POLLS_PER_LOOP default; change
+       default for OPER_SET
+
+       * RELEASE.NOTES: changed documentation to reflect the fact that
+       assertions are now enabled by default and do not cause memory
+       leaks
+
+       * ircd/res.c (make_cache): removed a bogus assertion we probably
+       never caught because assertions haven't been enabled on production
+       servers for any length of time before
+
+       * ircd/engine_devpoll.c (engine_loop): ditto for POLLS_PER_DEVPOLL
+
+       * ircd/engine_kqueue.c (engine_loop): stupid me forgot one
+       instance of POLLS_PER_KQUEUE
+
+       * include/patchlevel.h (PATCHLEVEL): bump patchlevel
+
+       * ircd/s_bsd.c (client_timer_callback): only clear the
+       FREEFLAG_TIMER flag when the timer is being destroyed
+
+       * ircd/ircd_features.c: create a new feature, POLLS_PER_LOOP, and
+       default it to 200; turn OPER_SET off by default
+
+       * ircd/engine_kqueue.c: dynamically allocate and reallocate the
+       array of events to obtain from the kernel
+
+       * ircd/engine_devpoll.c: dynamically allocate and reallocate the
+       array of events to obtain from the kernel
+
+       * include/ircd_features.h: add a new feature for tuning how many
+       events to get from the kernel, for engines that support that
+
+       * ircd/Makefile.in: re-run make depend to correct dependancies
+
+       * ircd/m_who.c: remove unneeded inclusion of list.h
+
+       * ircd/ircd_events.c: remove unneeded inclusion of list.h
+
+       * ircd/whocmds.c (do_who): hide server name in /who unless
+       requester is an operator; simplify hop count insertion
+
+       * ircd/s_misc.c (exit_one_client): make sure client's snomask is
+       cleared
+
+       * ircd/parse.c: use mo_version and mo_admin when opers do /version
+       or /admin
+
+       * ircd/m_whowas.c (m_whowas): use HEAD_IN_SAND_SERVERNAME instead
+       of the static string "*.undernet.org"
+
+       * ircd/m_version.c: only let ordinary users get version
+       information for the server they are on
+
+       * ircd/m_admin.c: only let ordinary users get admin information
+       for the server they are on
+
+       * ircd/channel.c (client_can_send_to_channel): check is_banned()
+       before letting the client speak on a channel s/he is not on
+
+       * include/supported.h: add NETWORK to feature list
+
+       * include/handlers.h: declare mo_admin() and mo_version()
+
+2002-01-10  Kevin L Mitchell  <klmitch@mit.edu>
+
+       * include/patchlevel.h (PATCHLEVEL): bump patchlevel
+
+       * ircd/s_debug.c (count_memory): conditionalize on MDEBUG instead
+       of !NDEBUG
+
+       * ircd/m_stats.c: conditionalize /stats M on MDEBUG instead of
+       !NDEBUG
+
+       * ircd/ircd_alloc.c: conditionalize on MDEBUG instead of on
+       !NDEBUG
+
+       * ircd/fda.c: conditionalize on MDEBUG instead of on !NDEBUG
+
+       * ircd/Makefile.in: run make depend on chkconf.c as well
+
+       * include/ircd_alloc.h: instead of conditionalizing on !NDEBUG,
+       conditionalize on MDEBUG
+
+       * include/fda.h: instead of conditionalizing on !NDEBUG,
+       conditionalize on MDEBUG
+
+       * configure: rebuild configure script
+
+       * configure.in: enable assertion checking by default, since we
+       have now decoupled memory debugging from the NDEBUG macro
+
+       * ircd/s_user.c (set_nick_name): remove calls to
+       verify_client_list()
+
+       * ircd/s_misc.c (exit_one_client): remove calls to
+       verify_client_list()
+
+       * ircd/s_conf.c (rehash): remove calls to verify_client_list()
+
+       * ircd/m_who.c (m_who): remove calls to verify_client_list()
+
+       * ircd/list.c: remove calls to verify_client_list(); keep
+       verify_client_list() around just in case we ever need it again,
+       but never compile it in
+
+       * ircd/ircd_events.c (event_execute): remove calls to
+       verify_client_list()
+
+       * ircd/client.c (client_get_ping): remove calls to
+       verify_client_list()
+
+       * include/list.h (send_listinfo): remove temporary debugging
+       function verify_client_list()
+
+       * ircd/uping.c: don't die if the event type is ET_ERROR in socket
+       callback functions
+
+       * ircd/res.c (res_callback): don't die if the event type is
+       ET_ERROR
+
+       * ircd/listener.c (accept_connection): don't die if the event type
+       is ET_ERROR
+
+2002-01-09  Kevin L Mitchell  <klmitch@mit.edu>
+
+       * ircd/s_user.c (set_nick_name): bracket call to
+       add_client_to_list() with calls to verify_client_list()
+
+       * include/patchlevel.h (PATCHLEVEL): bump patchlevel (again)
+
+       * ircd/list.c (verify_client_list): add a probabilistic loop
+       detector: for every client added, there is a 2% probability that
+       it will be used to replace the value of sentinel; if at any time,
+       sentinel is found again, we know we're in a loop
+
+       * ircd/ircd_events.c (event_execute): add verify_client_list()
+       calls wrapping event_execute; at the very least, I'll figure out
+       what event the corruption occurred in
+
+       * ircd/list.c: moved verify_client_list() to try to keep it from
+       being inlined
+
+       * ircd/Makefile.in (version.c): version.c wasn't dependant on
+       version.h and patchlevel.h, like it was supposed to be
+
+       * include/patchlevel.h (PATCHLEVEL): bump patchlevel
+
+       * ircd/s_auth.c (destroy_auth_request): overload send_reports
+       argument to also indicate whether or not to call
+       release_auth_client() and thereby enter the client into the linked
+       list
+
+       * ircd/engine_devpoll.c (engine_loop): remove bogus assertion
+
+       * include/patchlevel.h (PATCHLEVEL): bump patchlevel
+
+       * ircd/list.c (free_client): verify that destroy_auth_request()
+       didn't automagically re-add us to the list; we might have to think
+       about this interaction more carefully, actually
+
+       * ircd/s_auth.c (auth_kill_client): zero the auth pointer before
+       calling free_client(); otherwise, free_client() will try to free
+       the auth by calling destroy_auth_request(), which will call
+       add_client_to_list()
+
+       * ircd/s_misc.c (exit_one_client): liberally sprinkle calls to
+       verify_client_list() around to catch any corruption that might
+       occur here
+
+       * ircd/s_conf.c (rehash): liberally sprinkle calls to
+       verify_client_list() here, since this is about the only routine I
+       can think of that could cause the "core on kill -HUP" bug
+
+       * ircd/m_who.c: sprinkle calls to verify_client_list() around
+       liberally, since we've seen crashes here; temporarily include the
+       otherwise unneeded list.h header
+
+       * ircd/list.c: sprinkle calls to verify_client_list() around quite
+       liberally; add debugging asserts to list manipulation functions to
+       catch strange settings for next and prev pointers; define
+       verify_client_list(), which walks the client list and verifies
+       that everything is as it's supposed to be
+
+       * ircd/client.c: wrap client_get_ping with calls to
+       verify_client_list() to see if that's where we're dying
+
+       * include/patchlevel.h (PATCHLEVEL): bump to 03
+
+       * include/list.h: declare verify_client_list() if DEBUGMODE
+       enabled; otherwise, define it to be empty
+
+2002-01-08  Kevin L Mitchell  <klmitch@mit.edu>
+
+       * ircd/m_quit.c (m_quit): remove an unused variable
+
+       * include/patchlevel.h (PATCHLEVEL): bump PATCHLEVEL to 2
+
+       * ircd/s_user.c: when building the user mode to send to the user,
+       don't include +r; add an extra set of parens to squelch a warning
+
+       * ircd/m_quit.c (m_quit): use exit_client_msg()
+
+       * include/patchlevel.h (PATCHLEVEL): bump patch level, so we can
+       keep track of who's running what version
+
+       * ircd/m_squit.c (ms_squit): remove debugging calls to
+       protocol_violation()
+
+       * Makefile.in: change MAKEFILES to IRCD_MAKEFILES to work around a
+       new gmake "feature" (pull-up from trunk)
+
+       * ircd/m_quit.c (m_quit): prefix user quits with "Quit:" (pull-up
+       from trunk)
+
+2002-01-07  Kevin L Mitchell  <klmitch@mit.edu>
+
+       * ircd/s_user.c: add FLAGS_ACCOUNT, represented as 'r', to the
+       list of user modes; process account name as part of user mode in
+       NICK decoding (set_nick_name()); add account name to usermode when
+       building the usermode to incorporate in outgoing NICK messages
+
+       * ircd/s_err.c: add RPL_WHOISACCOUNT for reporting what account a
+       user is logged in to
+
+       * ircd/parse.c: define the new ACCOUNT command, usable only by
+       servers and ignored by everything else
+
+       * ircd/m_whois.c: report what account name is associated with a
+       user, if any
+
+       * ircd/m_account.c: implement the ACCOUNT command
+
+       * ircd/Makefile.in: add m_account.c to the list of sources; ran
+       make depend
+
+       * include/struct.h: add an account field to struct User
+
+       * include/numeric.h: add a reply, RPL_WHOISACCOUNT, for reporting
+       what username a user is logged in under
+
+       * include/msg.h: add ACCOUNT command and token (AC)
+
+       * include/ircd_defs.h: define ACCOUNTLEN to be 12--this matches
+       the maximum length of a username for X
+
+       * include/handlers.h: add declaration for ms_account()
+
+       * include/client.h: add FLAGS_ACCOUNT to flag when a user account
+       name has been set; added FLAGS_ACCOUNT to SEND_UMODES; added
+       IsAccount() and SetAccount() to manipulate the flag
+
+       * ircd/m_squit.c (ms_squit): if we call FindNServer() on a server
+       name like "Amsterdam2.NL.EU.undernet.org", we get the struct
+       Client for the server with numeric "Am", which happens to be
+       stockholm!  To fix this, we look up the full name *first*; if that
+       doesn't get it, *then* we look up by numeric.
+
+2001-12-24  Perry Lorier <isomer@coders.net>
+       * ircd/m_server.c: cleanups, maybe this will make the bug easier
+       to find.
+
+       * ircd/m_stats.c: display maximum number of connects in an I:
+
+2001-11-22  Perry Lorier  <isomer@coders.net>
+       * ircd/m_squit.c: Bug fix in squit
+
+2001-11-03  Greg Sikorski <gte@atomicrevs.demon.co.uk>
+       * ircd/parse.c, include/handlers.h: Give remote whois the correct
+       handler.
+       
+2001-11-01  Kevin L Mitchell  <klmitch@mit.edu>
+
+       * ircd/send.c: some minor white-space fiddling; recast selector
+       test in sendwallto_group_butone() to remove a warning regarding
+       putting & within parentheses
+
+       * ircd/m_create.c (ms_create): use time_t instead of int as a
+       declaration for rate
+
+       * ircd/ircd_reply.c (protocol_violation): it's supposed to be
+       WALL_DESYNCH, not CMD_DESYNCH, if I understand things right--no
+       wonder we weren't seeing any protocol violations!
+
+       * include/send.h: include time.h for time_t; move WALL_* closer to
+       the function they're used in; some white-space fiddling; add
+       declaration of sendto_opmask_butone_ratelimited()
+
+       * ircd/m_squit.c (ms_squit): add protocol_violation() calls in the
+       cases where we ignore a squit, so we aren't taken by surprise, at
+       least...
+
+       * ircd/m_create.c (ms_create): Display origin server, not origin
+       user
+
+       * ircd/m_create.c (ms_create): Fix "Timestamp drift" server notice
+
+2001-10-31  Perry Lorier  <isomer@coders.net>
+       * include/m_ping.c: Forward port ping bug
+
+2001-10-31  Perry Lorier  <isomer@coders.net>
+       * include/patchlevel.h: We're beta now
+
+2001-10-31  Perry Lorier  <isomer@coders.net>
+       * ircd/s_user.c: fixed hunt_server
+
+2001-09-21  Perry Lorier  <isomer@coders.net>
+       * ircd/send.c and various: replace sendcmdto_flag_butone with
+       sendwallto_group_butone
+
+2001-09-21  Vampire-  <unknown>
+       * ircd/ircd_string.c: unique_name_vector round II.
+
+2001-09-21  mbuna  <mbuna@undernet.org>
+       * configure.in: Add support for darwin
+
+2001-09-21  Perry Lorier  <isomer@coders.net>
+       * ircd/s_user.c I'm stupid, s/acptr/from/, Hektik pointed it out
+
+2001-09-20  Perry Lorier  <isomer@coders.net>
+
+       * Pullups from 2.10.10.pl16
+       * Added some warnings, and the concept of rate limited snotices
+
+2001-08-31  Kevin L Mitchell  <klmitch@mit.edu>
+
+       * ircd/channel.c: use "%u" to format limit arguments; use
+       strtoul() to process limit arguments in a /mode command--note:
+       most clients seem to truncate the integer, probably because
+       they're using atoi, and perhaps signed ints
+
+2001-08-17  Kevin L Mitchell  <klmitch@mit.edu>
+
+       * ircd/numnicks.c: include stdlib.h for exit()
+
+       * ircd/ircd_log.c: include stdlib.h for exit()
+
+       * ircd/ircd_events.c: include stdlib.h for exit()
+
+       * ircd/s_stats.c: remove description of /stats v, since it's gone
+
+       * ircd/m_wallops.c (mo_wallops): add "*" to the beginning of
+       /wallops to distinguish wallops from wallusers
+
+       * ircd/m_error.c (mr_error): ignore ERROR from clients that aren't
+       in the "handshake" or "connecting" states--I think the latter will
+       never happen, but...
+
+       * doc/Authors: apply delete's Authors patch
+
+       * RELEASE.NOTES: rewrite RELEASE.NOTES, basing it a little on
+       Braden's version
+
+       * README: rewrite README
+
+2001-07-31  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/s_serv.c (server_estab): remove unused variable split
+
+       * ircd/parse.c: add mr_error to the parse table
+
+       * ircd/m_error.c (mr_error): add mr_error() to handle ERRORs from
+       unregistered connections--if IsUserPort() is true, the ERROR is
+       ignored, otherwise, the message is saved
+
+2001-07-28  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/m_kill.c (ms_kill): another minor typo *sigh*
+
+       * ircd/s_user.c (send_supported): oops, minor typo...
+
+       * ircd/s_user.c: implement send_supported() to send two ISUPPORT
+       messages containing our feature buffers; make register_user() use
+       send_supported()
+
+       * ircd/s_misc.c (exit_client): make sure not to give away a remote
+       server in the ERROR message sent to the client; if the killer is a
+       server, we substitute our name in its place
+
+       * ircd/m_version.c (m_version): use send_supported() to send the
+       ISUPPORT values to the user
+
+       * ircd/m_nick.c: shave nick collision kills here a bit, too, for
+       the same reasons as for m_kill.c
+
+       * ircd/m_kill.c: shave kills a bit so that the results look
+       exactly the same no matter where you are; if we didn't do this, it
+       would be possible to map the network by looking at the differences
+       between kills originating under various circumstances
+
+       * include/supported.h: split the features into two, so as to not
+       bust the parameter count when sending the features list
+
+       * include/s_user.h: declare new send_supported() function to send
+       the ISUPPORT information
+
+2001-07-27  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/s_bsd.c: disable IP (*not* TCP) options to prevent
+       source-routed spoofing attacks; this is only available under
+       u2.10.11, so don't even bother, since no one but testers are using
+       the source base
+
+2001-07-25  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * include/ircd_policy.h: enable HEAD_IN_SAND_REMOTE by default
+
+       * ircd/s_err.c: put in a . for reporting link version on /trace,
+       to match what /version does
+
+2001-07-21  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/s_misc.c (exit_client): servers don't understand what the
+       numeric nick ERROR is supposed to mean, so they ignore error
+       messages, resulting in not knowing why we were rejected; use
+       sendcmdto_one for servers and sendrawto_one for clients
+
+2001-07-17  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/m_burst.c (ms_burst): in the case of a modeless channel and
+       a nick collide, a bare BURST may be propagated; adjust the
+       enforced parameter count to accept the bare BURST
+
+2001-07-12  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/s_bsd.c: mark a client as having been IP checked
+
+       * ircd/IPcheck.c (ip_registry_check_remote): remove unneeded
+       second call to SetIPChecked()
+
+2001-07-11  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/engine_poll.c: deal with POLLHUP properly (hopefully)
+
+       * ircd/engine_devpoll.c: deal with POLLHUP properly (hopefully)
+
+2001-07-09  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/os_bsd.c (os_get_rusage): move buf into the two ifdef'd
+       sections so that if neither is used, the declaration of buf will
+       not elicit an "unused variable" warning under NetBSD
+
+       * ircd/m_map.c: include string.h to declare strcpy (fix warnings
+       on alpha)
+
+       * ircd/m_away.c: include string.h to declare strcpy/strlen (fix
+       warnings on alpha)
+
+       * ircd/ircd_log.c: include string.h to declare strcpy/strlen (fix
+       warnings on alpha)
+
+       * ircd/client.c: include string.h to declare memset (fix warnings
+       on alpha)
+
+       * ircd/channel.c: remove unused functions next_overlapped_ban,
+       del_banid, and is_deopped (fix warnings under -O1)
+
+       * ircd/IPcheck.c: include string.h to declare memset/memcpy (fix
+       warnings on alpha)
+
+2001-06-29  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/s_user.c (set_user_mode): clear the snomask if the user
+       isn't supposed to receive server notices anymore
+
+       * ircd/ircd_features.c: change CONFIG_OPERCMDS to default to FALSE
+
+       * configure.in: use AC_MSG_CHECKING/AC_MSG_RESULT when checking
+       installation prefix; default devpoll and kqueue to on (they get
+       turned off if the required headers aren't present)
+
+       * ircd/whocmds.c (do_who): use ircd_snprintf() instead of
+       sprintf_irc(); it's a bit hackish, but it'll do for now
+
+       * ircd/support.c: remove unused #include
+
+       * ircd/send.c: remove unused #include
+
+       * ircd/s_user.c: use ircd_snprintf() instead of sprintf_irc()
+
+       * ircd/s_serv.c: remove unused #include
+
+       * ircd/s_misc.c: use ircd_snprintf() and friends instead of
+       sprintf_irc() and friends
+
+       * ircd/s_err.c: moved atoi_tab[] from ircd/sprintf_irc.c to
+       ircd/s_err.c, which is the only other file to refer to it
+
+       * ircd/s_conf.c (conf_add_deny): use ircd_snprintf() instead of
+       sprintf_irc()
+
+       * ircd/s_bsd.c (connect_server): use ircd_snprintf() instead of
+       sprintf_irc()
+
+       * ircd/s_auth.c: use ircd_snprintf() instead of sprintf_irc()
+
+       * ircd/res.c: use ircd_snprintf() instead of sprintf_irc()
+
+       * ircd/m_version.c: use ircd_snprintf() instead of sprintf_irc()
+
+       * ircd/m_kill.c: use ircd_snprintf() instead of sprintf_irc()
+
+       * ircd/listener.c: use ircd_snprintf() instead of sprintf_irc()
+
+       * ircd/gline.c: use ircd_snprintf() instead of sprintf_irc()
+
+       * ircd/channel.c: don't include sprintf_irc.h; use ircd_snprintf()
+       instead of sprintf_irc()
+
+       * ircd/Makefile.in: remove sprintf_irc.c from sources list; run
+       make depend
+
+       * include/ircd_string.h: remove declaration of sprintf_irc() (what
+       was it doing here anyway?)
+
+       * include/sprintf_irc.h: removed unneeded source file
+
+       * ircd/sprintf_irc.c: removed unneeded source file
+
+       * ircd/s_debug.c (count_memory): remove some dead code
+
+       * ircd/s_auth.c: remove some dead code
+
+       * ircd/res.c (update_list): remove some dead code
+
+       * ircd/m_whowas.c: remove some dead code
+
+       * ircd/m_whois.c: remove some dead code
+
+       * ircd/m_who.c: remove some dead code
+
+       * ircd/m_wallusers.c: remove some dead code
+
+       * ircd/m_wallops.c: remove some dead code
+
+       * ircd/m_wallchops.c: remove some dead code
+
+       * ircd/m_version.c: remove some dead code
+
+       * ircd/m_userip.c: remove some dead code
+
+       * ircd/m_userhost.c: remove some dead code
+
+       * ircd/m_uping.c: remove some dead code
+
+       * ircd/m_trace.c: remove some dead code
+
+       * ircd/m_topic.c: remove some dead code
+
+       * ircd/m_tmpl.c: remove some dead code
+
+       * ircd/m_time.c: remove some dead code
+
+       * ircd/m_squit.c: remove some dead code
+
+       * ircd/m_silence.c: remove some dead code
+
+       * ircd/m_settime.c: remove some dead code
+
+       * ircd/m_set.c: remove some dead code
+
+       * ircd/m_server.c: remove some dead code
+
+       * ircd/m_rpong.c: remove some dead code
+
+       * ircd/m_rping.c: remove some dead code
+
+       * ircd/m_restart.c: remove some dead code
+
+       * ircd/m_reset.c: remove some dead code
+
+       * ircd/m_rehash.c: remove some dead code
+
+       * ircd/m_quit.c: remove some dead code
+
+       * ircd/m_proto.c: remove some dead code
+
+       * ircd/m_privs.c: remove some dead code
+
+       * ircd/m_privmsg.c: remove some dead code
+
+       * ircd/m_pong.c: remove some dead code
+
+       * ircd/m_ping.c: remove some dead code
+
+       * ircd/m_pass.c: remove some dead code
+
+       * ircd/m_part.c: remove some dead code
+
+       * ircd/m_opmode.c: remove some dead code
+
+       * ircd/m_oper.c: remove some dead code
+
+       * ircd/m_notice.c: remove some dead code
+
+       * ircd/m_nick.c: remove some dead code
+
+       * ircd/m_map.c: remove some dead code
+
+       * ircd/m_lusers.c: remove some dead code
+
+       * ircd/m_list.c: remove some dead code
+
+       * ircd/m_links.c: remove some dead code
+
+       * ircd/m_kill.c: remove some dead code
+
+       * ircd/m_kick.c: remove some dead code
+
+       * ircd/m_jupe.c: remove some dead code
+
+       * ircd/m_join.c: remove some dead code
+
+       * ircd/m_ison.c: remove some dead code
+
+       * ircd/m_invite.c: remove some dead code
+
+       * ircd/m_info.c: remove some dead code
+
+       * ircd/m_help.c: remove some dead code
+
+       * ircd/m_gline.c: remove some dead code
+
+       * ircd/m_get.c: remove some dead code
+
+       * ircd/m_error.c: remove some dead code
+
+       * ircd/m_endburst.c: remove some dead code
+
+       * ircd/m_die.c: remove some dead code
+
+       * ircd/m_desynch.c: remove some dead code
+
+       * ircd/m_destruct.c: remove some dead code
+
+       * ircd/m_defaults.c: remove some dead code
+
+       * ircd/m_create.c: remove some dead code, along with an #if 1
+
+       * ircd/m_cprivmsg.c: remove some dead code
+
+       * ircd/m_connect.c: remove some dead code
+
+       * ircd/m_close.c: remove some dead code
+
+       * ircd/m_clearmode.c: remove some dead code
+
+       * ircd/m_burst.c: remove some dead code
+
+       * ircd/m_away.c: remove some dead code
+
+       * ircd/m_admin.c: remove some dead code
+
+       * ircd/listener.c (accept_connection): remove some dead code
+
+       * ircd/ircd_reply.c (need_more_params): remove some dead code
+
+       * ircd/channel.c (add_banid): remove some dead code
+
+       * include/support.h: remove some dead code
+
+       * include/querycmds.h: remove some dead code
+
+       * doc/readme.chroot: document how to do chroot operation
+
+2001-06-28  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/Makefile.in: tune for VPATH builds/installs; add a rule to
+       force bin directory to be created if necessary prior to
+       installation; run make depend
+
+       * doc/Makefile.in (install): tune for VPATH installs by cd'ing to
+       the ${srcdir}
+
+       * Makefile.in: tune to detect Makefile.in changes in
+       subdirectories and to create installation directory indicated by
+       ${prefix}
+
+       * ircd/whocmds.c (count_users): routine to count the number of
+       users matching a given user@host mask
+
+       * ircd/s_err.c: add error messages for ERR_LONGMASK,
+       ERR_TOOMANYUSERS, and ERR_MASKTOOWIDE
+
+       * ircd/m_gline.c: look for and advance past '!' flag on G-lines
+       from operators; only set GLINE_OPERFORCE flag if oper has the
+       PRIV_WIDE_GLINE privilege
+
+       * ircd/ircd_features.c: add GLINEMAXUSERCOUNT, which is the
+       maximum number of users a G-line can impact before it has to be
+       forced; OPER_WIDE_GLINE, to allow operators to use ! to force a
+       wide G-line to be set; and LOCOP_WIDE_GLINE, to allow local
+       operators to use ! to force a wide G-line to be set
+
+       * ircd/gline.c: make make_gline() be called with separate user and
+       host arguments, and not call canon_userhost() directly; implement
+       gline_checkmask() to verify that a host mask is acceptable; move
+       BADCHAN check up in gline_add(), and check passed-in mask under
+       certain circumstances for acceptability; fix call to
+       sendto_opmask_butone() to handle separation of userhost into user
+       and host in gline_add(); update call to make_gline()
+
+       * ircd/client.c: use FEAT_OPER_WIDE_GLINE and
+       FEAT_LOCOP_WIDE_GLINE to set PRIV_WIDE_GLINE for an operator; add
+       PRIV_WIDE_GLINE to privtab[] for client_report_privs()
+
+       * include/whocmds.h (count_users): declare routine to count users
+       matching a given user@host mask
+
+       * include/numeric.h: added three new error returns: ERR_LONGMASK
+       -- mask can't be formatted into a buffer; ERR_TOOMANYUSERS -- too
+       many users would be impacted by the mask; ERR_MASKTOOWIDE -- mask
+       contains wildcards in the wrong places
+
+       * include/ircd_features.h: add FEAT_GLINEMAXUSERCOUNT,
+       FEAT_OPER_WIDE_GLINE, and FEAT_LOCOP_WIDE_GLINE
+
+       * include/gline.h (GLINE_OPERFORCE): provides a way for m_gline()
+       to signal to gline_add() that the operator attempted to force the
+       G-line to be set
+
+       * include/client.h (PRIV_WIDE_GLINE): new privilege for operators
+
+       * doc/readme.gline: update to document new "!" prefix to a G-line
+       user@host mask
+
+       * doc/readme.features: document GLINEMAXUSERCOUNT,
+       OPER_WIDE_GLINE, and LOCOP_WIDE_GLINE
+
+       * doc/example.conf: update to mention new features along with
+       their defaults
+
+2001-06-27  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * doc/example.conf: updated example.conf from Braden
+       <dbtem@yahoo.com>
+
+       * include/supported.h: forward-port from pl15
+
+2001-06-25  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/whocmds.c: include ircd_policy.h and implement
+       HEAD_IN_SAND_WHO_OPCOUNT--forward-port from pl15
+
+       * ircd/m_whois.c: forward-port of the idle-time hiding code from
+       pl15; this also required passing parc into do_whois(), which also
+       meant passing parc into do_wilds()--*sigh*
+
+       * include/ircd_policy.h: add a couple more HEAD_IN_SAND
+       #define's--WHOIS_IDLETIME and WHO_HOPCOUNT
+
+2001-06-22  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * tools/wrapper.c: add a wrapper program that can be used to
+       adjust file descriptor limits and root directories; program must
+       be run as root--NOT SETUID!--and given appropriate -u arguments
+
+       * doc/readme.log: documentation of how to configure logging
+
+       * doc/readme.features: documentation of each feature (except for
+       logging)
+
+2001-06-21  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * Makefile.in (config): add a deprecation notice with a pointer to
+       tools/transition
+
+       * tools/transition: shell script to convert old compile-time
+       options into new compile-time options and appropriate F-lines
+
+       * tools/mkchroot: shell-script to prepare the chroot area by
+       copying over all the necessary libraries so they can be found
+
+2001-06-20  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * INSTALL: partial update of INSTALL for u2.10.11 release...
+
+2001-06-14  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/table_gen.c (makeTables): finally got tired of the
+       "overflow in implicit conversion" warning, so just got rid of it
+       by explicitly casting UCHAR_MAX to a (default) char; diffs show no
+       differences in the tables generated
+
+2001-06-11  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/send.c (sendcmdto_match_butone): don't let the server crash
+       if a client is in the STAT_CONNECTING status
+
+2001-06-10  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/send.c: remove unused vsendcmdto_one(), consolidating it
+       into sendcmdto_one(); define new sendcmdto_prio_one(), which
+       places the message into the priority queue
+
+       * ircd/s_user.c (hunt_server_prio_cmd): definition of
+       hunt_server_prio_cmd(), which simply calls sendcmdto_prio_one()
+       instead of sendcmdto_one()
+
+       * ircd/m_settime.c: use sendcmdto_prio_one() and
+       hunt_server_prio_cmd() to send SETTIME
+
+       * ircd/m_server.c: use sendcmdto_prio_one() to send SETTIME
+
+       * include/send.h: removed declaration for unused vsendcmdto_one();
+       added a declaration for sendcmdto_prio_one()
+
+       * include/s_user.h: declare hunt_server_prio_cmd(), which calls
+       sendcmdto_prio_one()
+
+       * ircd/send.c (sendcmdto_flag_butone): oops; /wallops should be
+       put in the server's priority queue, too...
+
+       * ircd/ircd.c: don't check LPATH for accessibility at all
+
+2001-06-08  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/s_serv.c (server_estab): send a +h flag in our SERVER
+       command if we're configured as a hub; send individual server flags
+       in SERVER commands
+
+       * ircd/s_bsd.c (completed_connection): send a +h flag in our
+       SERVER command if we're configured as a hub
+
+       * ircd/m_server.c: implement parv[7] as a mode-like string; +h
+       sets the FLAGS_HUB flag for a server; +s sets the FLAGS_SERVICE
+       flag for a server; +hs sets both flags; also modify CMD_SERVER
+       format string to send the flags
+
+       * include/client.h: define two new flags, FLAGS_HUB and
+       FLAGS_SERVICE to mark services and hubs as such; define testing
+       macros, setting macros
+
+       * ircd/s_user.c: remove deprecated struct Gline* argument to
+       register_user(); remove GLINE rebroadcast; do not send GLINE
+       acknowledgement parameter to NICK; do not look for GLINE
+       acknowledgement parameter to NICK while parsing
+
+       * ircd/s_serv.c (server_estab): remove deprecated struct Jupe*
+       argument to server_estab(); do not send JUPE/GLINE acknowledgement
+       parameters for SERVER or NICK
+
+       * ircd/m_user.c (m_user): remove deprecated argument to
+       register_user()
+
+       * ircd/m_server.c: remove deprecated argument to server_estab();
+       remove documentation comment regarding JUPE acknowledgement
+       parameter to SERVER; remove JUPE rebroadcast
+
+       * ircd/m_pong.c (mr_pong): remove deprecated argument to
+       register_user()
+
+       * ircd/m_nick.c: remove documentation comment regarding GLINE
+       acknowledgement parameter to NICK
+
+       * ircd/jupe.c: use user's real name in JUPE server notices if
+       HEAD_IN_SAND_SNOTICES is defined
+
+       * ircd/ircd.c: remove deprecated chroot() code; remove deprecated
+       setuid code; correct ancient DEBUG vs DEBUGMODE typo
+
+       * ircd/gline.c: use user's real name in GLINE server notices if
+       HEAD_IN_SAND_SNOTICES is defined
+
+       * ircd/channel.c (modebuf_flush_int): make apparent source be
+       local server, not oper's server; use user's real name in hack
+       notices and DESYNC notices if HEAD_IN_SAND_SNOTICES is defined
+
+       * include/s_user.h: remove struct Gline pre-declaration; remove
+       deprecated struct Gline argument from register_user()
+
+       * include/s_serv.h: remove struct Jupe pre-declaration; remove
+       deprecated struct Jupe argument from server_estab()
+
+2001-06-07  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/s_stats.c (hunt_stats): forward-port from pl15 of all the
+       changes required to control remote stats
+
+       * ircd/s_numeric.c (do_numeric): rewrite numeric origins if
+       recipient is not an operator and HEAD_IN_SAND_REWRITE is defined
+       [forward-port from pl15]
+
+       * ircd/m_whowas.c (m_whowas): report server name only if requester
+       is an operator [forward-port from pl15]
+
+       * ircd/m_whois.c (do_whois): /whois <mynick> now correctly reports
+       my server; if HEAD_IN_SAND_REMOTE is 1, ignore the middle argument
+       and obtain the report from the user's server [forward-port from
+       pl15]
+
+       * ircd/m_who.c: add missing include for ircd_policy.h
+       [forward-port from pl15]
+
+       * ircd/m_version.c (m_version): require oper access for remote
+       /version if HEAD_IN_SAND_REMOTE is 1 [forward-port from pl15]
+
+       * ircd/m_time.c (m_time): require oper access for remote /time if
+       HEAD_IN_SAND_REMOTE is 1 [forward-port from pl15]
+
+       * ircd/m_stats.c: pass extra argument to hunt_stats(); correct
+       missing semicolon [forward-port from pl15]
+
+       * ircd/m_nick.c (ms_nick): hide the origin of certain collision
+       kills [forward-port from pl15]
+
+       * ircd/m_motd.c (m_motd): require oper access for remote /motd if
+       HEAD_IN_SAND_REMOTE is 1 [forward-port from pl15]
+
+       * ircd/m_lusers.c (m_lusers): require oper access for remote
+       /lusers if HEAD_IN_SAND_REMOTE is 1 [forward-port from pl15]
+
+       * ircd/m_burst.c (ms_burst): server-added bans are stored using
+       local server name, to hide remote server names; modes also are to
+       originate from the local server [forward-port from pl15]
+
+       * ircd/m_admin.c (m_admin): require oper access for remote /admin
+       if HEAD_IN_SAND_REMOTE is 1 [forward-port from pl15]
+
+       * ircd/channel.c (add_banid): if a server is adding a ban, use my
+       server name to hide the remote server's name [forward-port from
+       pl15]
+
+       * ircd/Makefile.in: ran make depend
+
+       * include/s_stats.h: hunt_stats() has to have an extra argument to
+       support the forward-port from pl15
+
+       * include/ircd_policy.h: #define HEAD_IN_SAND_STATS_P; add
+       HEAD_IN_SAND_{BANWHO,REWRITE,REMOTE} [forward-port from pl15]
+
+       * ircd/engine_poll.c (engine_loop): remove bogus assert that I
+       forgot to check in the events branch
+
+2001-06-06  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/res.c (init_resolver): don't start DNS expires with a 0
+       relative timeout--if the server starts slow, timeouts could be
+       messy...there's probably a better solution, but this'll do for now
+
+       * ircd/os_solaris.c: _XOPEN_SOURCE doesn't get along with Solaris
+       headers very well; include stropts.h; define an os_set_tos()
+
+       * ircd/os_generic.c (os_set_tos): added an os_set_tos() for
+       os_generic.c
+
+       * ircd/ircd.c: if there are no C-lines, we don't want to have a
+       timer that expires at the absolute time of 0--it kinda blocks all
+       the other timers!
+
+       * ircd/engine_devpoll.c: some includes for open(); declare errcode
+       and codesize in engine_loop()
+
+       * ircd/list.c (free_client): remove bogus check on timer active
+       flag
+
+       * ircd/s_auth.c: pull out destruction code in
+       auth_timeout_request() into an externally-visible
+       destroy_auth_request(); manage cli_auth pointer in client
+       structure; use it for an extra assertion check
+
+       * ircd/list.c: include s_auth.h for destroy_auth_request(); add
+       debugging notices to show flow when deallocating
+       connections/clients; call destroy_auth_request() when free'ing a
+       client that has an auth outstanding; don't free the connection if
+       the process timer is unmarked but still active
+
+       * ircd/ircd_events.c: set GEN_ACTIVE when initializing a generator
+       and reset it before calling the event handler for an ET_DESTROY
+       event
+
+       * include/s_auth.h (destroy_auth_request): declare
+       destroy_auth_request(), which can be used to destroy an
+       outstanding auth request if a client socket goes away before the
+       auth exchange is completed
+
+       * include/ircd_events.h: add an active flag to keep track of
+       whether or not particular generators are active, for the
+       convenience of functions using the API
+
+       * include/client.h: add a pointer for auth requests to struct
+       Connection so we can kill outstanding auth requests if a client
+       socket closes unexpectedly
+
+       * ircd/s_bsd.c: cli_connect() could become 0 during the course of
+       the sock or timer callback; take that into account in the assert
+
+       * ircd/list.c: add magic number checking and setting--magic
+       numbers are zero'd on frees to detect double-frees; add back
+       setting of cli_from() to 0 to break the back-link from the struct
+       Connection (duh)
+
+       * ircd/ircd.c: set me's magic number correctly
+
+       * include/client.h: define magic numbers and accessor/verifier
+       macros
+
+       * ircd/list.c: assert that dealloc_client() is called with
+       cli_connect(cptr) == 0; set cli_connect(cptr) to 0 before calling
+       dealloc_client(); don't mess with cli_from(cptr)
+
+       * ircd/s_bsd.c: only attempt to dealloc a connection if the
+       associated client has already been destroyed, or at least delinked
+
+2001-06-05  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/list.c (free_client): only try to delete the socket when
+       the fd hasn't already been closed, avoiding a double-free
+
+       * ircd/list.c (free_connection): make sure the client is really
+       gone before doing away with the connection
+
+       * ircd/s_bsd.c: record that socket has been added in con_freeflag
+       field; queue a socket_del() as soon as the socket is close()'d;
+       use con_freeflag & FREEFLAG_TIMER instead of con_timer; clear
+       FREEFLAG_SOCKET on ET_DESTROY event in client_sock_callback(),
+       then dealloc the connection if safe; mark socket as dead when
+       there's a read error or EOF; clear FREEFLAG_TIMER flag upon entry
+       to client_timer_callback(); dealloc connection if safe upon
+       ET_DESTROY event in client_timer_callback()
+
+       * ircd/list.c: use con_freeflag instead of con_timer; only dealloc
+       the connection if both socket and timer have been destroyed;
+       destroy both socket and timer explicitly and carefully
+
+       * include/client.h: replace the con_timer field with a
+       con_freeflag field, to indicate what still needs freeing; define
+       the freeflags
+
+       * ircd/engine_select.c (engine_loop): duh...sockList[i] could
+       become 0
+
+       * ircd/engine_devpoll.c (engine_loop): duh...sockList[i] could
+       become 0
+
+       * ircd/s_bsd.c: add some extra assertions to try to track down a
+       corruption problem
+
+       * ircd/engine_select.c (engine_loop): add an extra assert to try
+       to track down a corruption problem
+
+       * ircd/engine_poll.c (engine_loop): add an extra assert to try to
+       track down a corruption problem
+
+       * ircd/engine_kqueue.c (engine_loop): add an extra assert to try
+       to track down a corruption problem
+
+       * ircd/engine_devpoll.c (engine_loop): skip slots that have become
+       empty during processing; add an extra assert to try to track down
+       a corruption problem
+
+       * ircd/engine_kqueue.c (engine_delete): make sure to zero deleted
+       entries
+
+2001-06-04  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/s_bsd.c (client_sock_callback): client is no longer
+       blocked, so we must mark it as unblocked
+
+       * ircd/engine_select.c: add Debug() calls galore; add handling for
+       SS_NOTSOCK; use a dummy sock variable to keep things from
+       disappearing on us; correct timeout calculation; update nfds for
+       efficiency
+
+       * ircd/engine_poll.c: use new debugging level (DEBUG_ENGINE);
+       remove a spurious "if (sock)" which will always be true; update
+       nfds for efficiency
+
+       * ircd/engine_kqueue.c: add Debug() calls galore; add handling for
+       SS_NOTSOCK (just in case); correct timeout calculation
+
+       * ircd/engine_devpoll.c: add Debug() calls galore; add handling
+       for SS_NOTSOCK; correct timeout calculation; add EAGAIN handling
+
+       * include/s_debug.h (DEBUG_ENGINE): add new debugging level;
+       pretty-indent numbers
+
+       * ircd/engine_poll.c (engine_loop): break out SS_NOTSOCK
+       case--it's not a socket; the check for writability is most likely
+       not needed, but present for completeness
+
+2001-05-24  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/s_bsd.c: add Debug messages; call read_packet() even if the
+       no newline flag is set; call read_packet() when the timer expires,
+       regardless of what's in the buffer--read_packet() should be able
+       to deal properly
+
+       * ircd/IPcheck.c (ip_registry_connect_succeeded): correct a NOTICE
+       sent to clients to include the client nickname (duh)
+
+       * ircd/ircd_events.c: don't destroy a timer if it's already marked
+       for destruction; replace a missing ! in socket_del()
+
+       * ircd/engine_poll.c (engine_loop): reference a temporary variable
+       so we don't have to worry about sockList[i] going away
+
+       * ircd/s_bsd.c (client_sock_callback): add Debug messages
+
+       * ircd/s_auth.c: add Debug messages all over the place
+
+       * ircd/ircd_events.c: add and edit some Debug messages; add a list
+       of routines to convert some of the enums and flags from numbers
+       into human-readable strings for the Debug messages
+
+       * ircd/engine_poll.c: hack some Debug messages to use the new name
+       conversion routines in ircd_events.c; add an extra assert for a
+       condition that shouldn't ever happen; apparently recv() can return
+       EAGAIN when poll() returns readable--I wonder why...
+
+       * include/ircd_events.h: declare some helper routines under
+       DEBUGMODE
+
+2001-05-23  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/s_bsd.c (client_sock_callback): add an extra assertion
+       check
+
+       * ircd/s_auth.c: add more Debug messages
+
+       * ircd/list.c (make_client): add an extra assertion check
+
+       * ircd/ircd_events.c (socket_events): don't call the engine events
+       changer if we haven't actually made any changes to the event mask
+
+       * ircd/uping.c: add some Debug messages
+
+       * ircd/s_stats.c: document new /STATS e
+
+       * ircd/s_err.c: add RPL_STATSENGINE to report the engine name
+
+       * ircd/s_bsd.c: remove static client_timer variable; in
+       read_packet(), if there's still data in the client's recvQ after
+       parsing, add a 2 second timer (con_proc); fix the ET_DESTROY case
+       of client_sock_callback to handle destroying the timer properly;
+       rewrote client_timer_callback from scratch to be called on an
+       individual client
+
+       * ircd/m_stats.c: add /STATS e to report the engine name
+
+       * ircd/list.c: deal with con_timer field in struct Connection
+       properly; correct a core-level bug in remove_client_from_list--if
+       the client is the only one in the list, we try to update
+       GlobalClientList's cli_prev pointer--not good
+
+       * ircd/ircd.c: remove call to init_client_timer()
+
+       * ircd/engine_poll.c: made Debug messages more uniform by
+       prepending "poll:" to them all; corrected an off-by-one error that
+       caused poll_count to be 1 less than the actual count and removed
+       my work-around; added Debug messages to indicate which socket is
+       being checked and what the results are
+
+       * ircd/Makefile.in: ran a make depend
+
+       * include/s_bsd.h: remove init_client_timer(), since we're doing
+       it differently now
+
+       * include/numeric.h (RPL_STATSENGINE): a stats reply to report the
+       engine name
+
+       * include/ircd_policy.h (HEAD_IN_SAND_STATS_E): turn off /stats e
+       reports for non-opers
+
+       * include/client.h: add con_timer and con_proc fields to struct
+       Connection and define accessor macros--con_timer marks that
+       con_proc contains a valid timer, and con_proc is used to pace user
+       data
+
+       * ircd/s_bsd.c (close_connection): let free_client() destroy the
+       socket
+
+       * ircd/s_auth.c (start_auth): add a Debug call to indicate when
+       auth has begun on a client
+
+       * ircd/ircd_events.c: ensure that event_execute() is called with a
+       non-NULL event; modify event_add() macro to properly zero list
+       bits; modify gen_dequeue() to not try to clip it out of a list
+       it's already been clipped out of; change signal socket
+       initialization to use state SS_NOTSOCK; permit timeout values of
+       0 in add_timer(); add many Debug calls; change socket_del() and
+       timer_del() to always set the GEN_DESTROY flag; use GEN_MARKED in
+       timer_run() instead of GEN_DESTROY so that event_generate() will
+       pass on the events; remove the switch and replace with a simpler
+       if-then-else tree in timer_run(); don't allow destroyed sockets to
+       be destroyed again, nor their states or event masks to be changed
+
+       * ircd/ircd.c: initialize "running" to 1
+
+       * ircd/engine_poll.c: deal with SS_NOTSOCK "sockets"; add Debug
+       messages all over the place; fix a counting problem in
+       engine_add(); turn wait into a signed integer and set it to -1
+       only if timer_next() returns 0; adjust wait time to be relative;
+       don't call gen_ref_dec() if socket disappeared while we were
+       processing it
+
+       * include/ircd_events.h: the pipe for signals is not a socket, so
+       we must mark it as such--added SS_NOTSOCK for that special socket;
+       events won't be generated if GEN_DESTROY is on, so add GEN_MARKED
+       for the benefit of timer_run()
+
+       * configure.in: add --enable-pedantic and --enable-warnings to
+       turn on (and off) -Wall -pedantic in CFLAGS
+
+2001-05-21  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/s_conf.c: change "s_addr" element accesses to "address"
+       element accesses
+
+       * include/s_conf.h: on some systems, "s_addr" is a macro; use
+       "address" instead
+
+2001-05-18  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/engine_kqueue.c: include ircd_alloc.h; set_or_clear returns
+       void in this file; add a missing semi-colon; declare errcode,
+       codesize
+
+       * ircd/uping.c (uping_sender_callback): it's pptr, not uping
+
+       * ircd/s_user.c (register_user): comment out spurious reference to
+       nextping
+
+       * ircd/s_serv.c (server_estab): comment out spurious reference to
+       nextping
+
+       * ircd/s_conf.c (read_configuration_file): comment out spurious
+       reference to nextping and nextconnect
+
+       * ircd/s_bsd.c: comment out some spurious references to formerly
+       global (now non-existant) variables; correct a couple of typos
+
+       * ircd/s_auth.c: pre-declare some functions referenced in the
+       callback; correct a typo
+
+       * ircd/res.c (start_resolver): pass errno value of ENFILE
+
+       * ircd/listener.c (accept_connection): you know your API is messed
+       up when...variables that shouldn't have been global crop up in
+       other files
+
+       * ircd/list.c (free_client): substitution of == for =
+
+       * ircd/ircd_signal.c: include assert.h for assertion checking;
+       check ev_data() to find out what signal generated event
+
+       * ircd/ircd_events.c: some references to the variable "timer"
+       should have been references to the variable "ptr"
+
+       * ircd/engine_select.c: it's struct fd_set, not struct fdset;
+       ev_timer(ev) is already a timer pointer; declare codesize as a
+       size_t to correct signedness issue; use timer_next(), not
+       time_next()
+
+       * ircd/engine_poll.c: ev_timer(ev) is already a timer pointer;
+       select fd out of struct pollfd in assertion checking; declare
+       errcode and codesize; use timer_next(), not time_next()
+
+       * ircd/engine_kqueue.c: ev_timer(ev) is already a timer pointer;
+       use function timer_next(), not time_next()
+
+       * ircd/engine_devpoll.c: ev_timer(ev) is already a timer pointer;
+       use function timer_next(), not time_next()
+
+       * ircd/Makefile.in (IRCD_SRC): add ircd_events.c to the list of
+       compiled sources; do make depend
+
+       * include/list.h: pre-declare struct Connection
+
+       * include/ircd_events.h (gen_ref_inc): cast to the right structure
+       name
+
+       * include/s_auth.h: duh; missing */
+
+2001-05-10  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/send.c: update write events status after sending data or
+       accumulating data to be sent
+
+       * ircd/m_list.c (m_list): update write events status after
+       canceling a running /list
+
+       * ircd/channel.c (list_next_channels): update write events status
+       after listing a few channels
+
+       * ircd/s_bsd.c: extensive changes to update to new events model;
+       remove on_write_unblocked() and the two implementations of
+       read_message(), which have been deprecated by this change
+
+       * ircd/s_auth.c: set the socket events we're interested in for
+       clients; simplify some logic that does the connect_nonb followed
+       by the socket_add
+
+       * ircd/list.c: define free_connection() to free a connection
+       that's become freeable once the struct Socket has been
+       deallocated; fix up free_client() to take this new behavior into
+       account
+
+       * ircd/ircd.c: call init_client_timer()
+
+       * include/s_bsd.h: declare new REGISTER_ERROR_MESSAGE when unable
+       to register connect-in-progress with events system; declare
+       init_client_timer() (HACK!) to preserve rate-limiting behavior
+
+       * include/list.h: declare new free_connection()
+
+       * include/client.h: add a struct Socket to struct Connection
+
+2001-05-09  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/ircd_signal.c: massage the handlers for SIGHUP, SIGINT, and
+       SIGTERM into event callbacks; perform the actions in the
+       callbacks, since they're not called in the context of the signal;
+       set up the signal callbacks in the event engine
+
+       * ircd/ircd_events.c (signal_callback): we're supposed to look for
+       a specific signal; don't generate an event if there is no signal
+       structure for it
+
+       * ircd/ircd.c: nuke nextconnect and nextping and replace them with
+       connect_timer and ping_timer; massage try_connections() and
+       check_pings() into timer callbacks that re-add themselves at the
+       right time; remove ircd.c's "event_loop()"; initialize the event
+       system and the connect_timer and ping_timer
+
+       * ircd/uping.c: correct a couple more typos
+
+       * ircd/s_auth.c: rework to use new events system
+
+       * ircd/os_solaris.c (os_connect_nonb): update to new interface
+
+       * ircd/os_openbsd.c (os_connect_nonb): update to new interface
+
+       * ircd/os_linux.c (os_connect_nonb): update to new interface
+
+       * ircd/os_generic.c (os_connect_nonb): update to new interface
+
+       * ircd/os_bsd.c (os_connect_nonb): update to new interface
+
+       * include/s_auth.h: remove deprecated members of struct
+       AuthRequest, replacing them with struct Socket and struct Timer
+       structures; add flags to indicate when these structures have been
+       released by the event system; remove the deprecated
+       timeout_auth_queries()
+
+       * include/ircd_osdep.h (os_connect_nonb): connect could complete
+       immediately, so change the interface to handle that possibility
+
+       * ircd/uping.c (uping_server): noticed and corrected a typo
+
+       * ircd/listener.c: set up to use ircd_event's struct Socket by
+       adding an socket_add() call to inetport(), replacing
+       free_listener() with socket_del() in close_listener(), and
+       reworking accept_connection to be called as the callback
+
+       * ircd/ircd.c: add a call to IPcheck_init()
+
+       * ircd/IPcheck.c: remove IPcheck_expire(); rework
+       ip_registry_expire() to be called from a timer; write
+       IPcheck_init() to set up the expiration timer (hard-coded for a
+       60-second expiration time)
+
+       * include/listener.h: add a struct Socket to the struct Listener;
+       remove accept_connection()
+
+       * include/IPcheck.h: add IPcheck_init(), remove IPcheck_expire()
+
+2001-05-08  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/ircd_events.c: include config.h; use USE_KQUEUE and
+       USE_DEVPOLL instead of HAVE_KQUEUE and HAVE_DEVPOLL_H
+
+       * ircd/engine_select.c: include config.h; set FD_SETSIZE to
+       MAXCONNECTIONS, not IRCD_FD_SETSIZE...
+
+       * ircd/engine_poll.c: include config.h
+
+       * ircd/engine_kqueue.c: include config.h
+
+       * ircd/engine_devpoll.c: include config.h
+
+       * ircd/Makefile.in: include engine sources in compilation and make
+       depend steps
+
+       * configure.in: add checks for enabling the /dev/poll- and
+       kqueue-based engines
+
+       * acconfig.h: add lines for USE_DEVPOLL and USE_KQUEUE
+
+       * ircd/Makefile.in: work in the engine sources
+
+2001-05-07  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/m_settime.c: include ircd_snprintf.h
+
+       * ircd/ircd_relay.c: stomp a couple of gcc warnings suggesting
+       parens around a construct that had both || and &&
+
+       * ircd/chkconf.c: #include "config.h" to get some important
+       definitions
+
+       * ircd/Makefile.in: revamp ircd makefile for new build system
+
+       * doc/Makefile.in: revamp doc makefile for new build system
+
+       * config/*: Removed old build system files
+
+       * stamp-h.in: a stamp file
+
+       * install-sh: install-sh for new build system
+
+       * configure.in: configure.in for new build system
+
+       * configure: configure script for new build system (built by
+       autoconf)
+
+       * config.sub: config.sub for new build system
+
+       * config.h.in: config.h.in for new build system (built by
+       autoheader)
+
+       * config.guess: config.guess for new build system
+
+       * aclocal.m4: aclocal.m4 for new build system (built by aclocal
+       1.4)
+
+       * acinclude.m4: aclocal.m4 macros for new build system
+
+       * acconfig.h: config.h skeleton for new build system
+
+       * Makefile.in: modify for new build system
+
+2001-05-01  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/s_err.c: get rid of the last vestiges of TIME_T_FMT
+
+       * ircd/m_settime.c: get rid of the last vestiges of TIME_T_FMT
+
+       * ircd/m_server.c: get rid of the last vestiges of TIME_T_FMT
+
+2001-05-01  Perry Lorier       <Isomer@coders.net>
+       * doc/iauth.doc: Protocol for iauth server. (from hybrid).
+       * doc/linux-poll.patch: Patch to make Linux under 2.2 not deadlock
+               when you have far far too many sockets in use.
+       * {include,ircd}/iauth.c: A start on iauth support.
+
+2001-05-01  Perry Lorier       <Isomer@coders.net>
+       * ircd/s_err.c: Suggested wording change.
+       * ircd/s_user.c: Users aren't target limited against +k users.
+       * ircd/chkconf.c: Made it compile again, who knows if it works, but
+               now I can at least make install
+        * various: Cleanups on m_*.c files.
+
+
+2001-04-23  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/s_misc.c (exit_client): make netsplit server notice say the
+       right thing
+
+       * ircd/m_links.c (m_links_redirect): forward-port RPL_ENDOFLINKS
+       change to make Khaled happy...
+
+       * ircd/m_whois.c (do_whois): pull-up of m_whois() fix
+       (do_whois): duh...
+
+2001-04-21  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/msgq.c: finally remove the msgq_integrity() hack, as it's
+       turned up no more bugs
+
+       * ircd/ircd.c: use /* */ comments instead of // comments--all the
+       world's not gcc :(
+
+       * ircd/s_conf.c (conf_add_server): use /* */ comments instead of
+       // comments--all the world's not gcc :(
+
+       * ircd/runmalloc.c: finally garbage-collect unused file
+
+       * include/runmalloc.h: finally garbage-collect unused file
+
+       * ircd/<multiple files>: addition of '#include "config.h"' before
+       all other includes in most .c files
+
+       * include/<multiple files>: remove includes of config.h, which are
+       now going into the raw .c files
+
+2001-04-20  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/m_whois.c (do_whois): display proper server name if the
+       user is looking up himself
+
+       * ircd/m_who.c (m_who): disable match by servername or display of
+       server names by non-opers
+
+       * include/ircd_policy.h: add define for
+       HEAD_IN_SAND_WHO_SERVERNAME to cover full intent of sub-motion 15
+       of CFV 165
+
+2001-04-18  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/s_conf.c: keep the $R in memory so we can see it clearly
+       when we do a /stats k
+
+       * ircd/s_user.c (set_user_mode): pull-up of changes to prevent
+       users from turning on +s and +g
+
+       * ircd/s_misc.c (exit_client): pull-up of changes to turn off
+       net.split notice
+
+       * ircd/parse.c: pull-up of changes to disable /trace, /links, and
+       /map for users
+
+       * ircd/m_whois.c (do_whois): pull-up of server name masking for
+       /whois
+
+       * ircd/m_user.c (m_user): removal of umode and snomask defaulting
+       functions, pull-up
+
+       * ircd/m_stats.c (m_stats): pull-up of stats-disabling stuff
+
+       * ircd/m_map.c (m_map_redirect): pull-up of m_map_redirect()
+
+       * ircd/m_links.c (m_links_redirect): pull-up of m_links_redirect()
+
+       * ircd/channel.c (channel_modes): pull-up of channel key display
+       as *
+
+       * include/ircd_policy.h: pull-up of ircd_policy.h
+
+       * include/client.h: pull-up of Set/ClearServNotice()
+
+       * ircd/gline.c (do_gline): report client name in G-line message
+       (pull-up)
+
+       * ircd/s_user.c (register_user): pull-up--show IP address in some
+       server notices dealing only with users; report which connection
+       class has filled up
+
+       * ircd/s_stats.c (report_deny_list): use conf->flags &
+       DENY_FLAGS_IP insteaf of conf->ip_kill
+
+       * ircd/m_stats.c (report_klines): use conf->flags & DENY_FLAGS_IP
+       insteaf of conf->ip_kill
+
+       * ircd/s_conf.c: use flags field in struct DenyConf; pull-up of
+       K-line by real name
+
+       * include/s_conf.h: use a flags field in struct DenyConf; define
+       DENY_FLAGS_FILE, DENY_FLAGS_IP, and DENY_FLAGS_REALNAME for
+       pull-up of K-line by real name
+
+       * ircd/m_trace.c: pull-up of IP show for user connections
+
+       * doc/example.conf: pull-up of the realname K-line documentation
+
+       * ircd/ircd.c: forward port of pid file advisory locking mechanism
+
+2001-04-16  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/send.c (sendcmdto_flag_butone): recast to just broadcast to
+       all servers, rather than to only servers that have +w/+g/whatever
+       users on them; among other things, this removes that atrocity
+       known as sentalong[] from this function
+
+       * ircd/m_admin.c: must include ircd.h to declare "me"; must
+       include hash.h to declare FindUser()
+
+       * ircd/m_wallusers.c: implementation of WALLUSERS
+
+       * ircd/m_desynch.c (ms_desynch): only send DESYNCHs to opers
+
+       * ircd/m_wallops.c: only send WALLOPS to opers
+
+       * ircd/parse.c: add WALLUSERS command to parser table
+
+       * include/handlers.h: declare wallusers handlers
+
+       * include/msg.h: add WALLUSERS command
+
+       * ircd/send.c (sendcmdto_flag_butone): if FLAGS_OPER is or'd with
+       flag, send only to appropriate opers
+
+2001-04-13  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/uping.c: refit to use the new events interface
+
+       * ircd/res.c: refit to use the new events interface
+
+       * ircd/ircd_events.c: create timer_chg(), which permits a
+       (non-periodic) timer's expire time to be modified; change the
+       logic in timer_run() so that timers that were re-added while the
+       event was being processed will not be destroyed prematurely
+
+       * include/uping.h: include the events header, declare some extra
+       fields in struct UPing, remove timeout value, and define some
+       flags for marking which cleanup items have yet to be done
+
+       * include/ircd_events.h: add a prototype for timer_chg() to change
+       the expire time of a running timer
+
+2001-03-13 Joseph Bongaarts <foxxe@wtfs.net>
+       * ircd/os_openbsd.c: Tweaked the openbsd hack a bit.
+       
+2001-03-07  Joseph Bongaarts  <foxxe@wtfs.net>
+
+       * config/configure.in: Add check for OpenBSD
+
+       * ircd/os_openbsd.c: Add seperate os dep file for openbsd which
+       differs from generic BSD, particularly in its handling of
+       _XOPEN_SOURCE.
+       
+2001-02-12  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/m_gline.c (ms_gline): propagate a G-line that happened to
+       have been added by a U-lined server, rather than going through the
+       activate/deactivate logic; propagate G-line removals by U-lined
+       servers as well
+
+       * ircd/gline.c: rename propagate_gline() to gline_propagate();
+       make gline_propagate() return an int 0 (convenience return); only
+       update lastmod in gline_activate() and gline_deactivate() if the
+       current lastmod is non-zero, since 0 lastmod is our flag of a
+       U-lined server having added a G-line
+
+       * include/gline.h (gline_propagate): exporting the G-line
+       propagation function
+
+       * ircd/m_list.c (m_list): duh; permit explicit channel name
+       specification only when /list gets two arguments ("Kev
+       #wasteland") rather than when /list gets more than two
+       arguments--nice braino
+
+2001-01-29  Thomas Helvey <twhelvey1@home.com>
+
+       * ircd/ircd_reply.c (need_more_params): fix bug that allowed
+       unregistered clients to spam opers with protocol violation
+       messages. Note: the bugfix may have eliminated some useful
+       protocol violation messages.
+       Please send protocol violation messages explicitly from the
+       functions they are discovered in, you have much better context
+       for the error there and it helps to document the behavior of the
+       server. This was also a design bug in that it violated the
+       "A function should do one thing" heuristic. Patching this one
+       would have resulted in a continuous spawning of other bugs over
+       the next 3 years, so I killed it. Check around for stuff this
+       broke and readd the calls to protocol_violation in the functions
+       that need to send the message.
+
+2001-01-29  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/channel.c (mode_parse_ban): stopper a tiny leak--if a ban
+       already existed, then the logic would (attempt to) skip it, but
+       would not free the ban string; now the ban string is free'd and
+       the ban count is decremented, releasing the ban for use
+
+       * ircd/s_user.c: make send_umode_out() take a prop argument
+       instead of testing for the PRIV_PROPAGATE privilege itself; fix
+       set_umode() to use this new argument, calculating it before
+       calculating the new privileges for a -o'd user
+
+       * ircd/m_oper.c (m_oper): pass the new prop argument to
+       send_umode_out()
+
+       * ircd/channel.c (mode_parse_ban): turn off MODE_ADD bit in bans
+       that we're not actually going to add because they already exist;
+       test that particular bit before adding to the linked list
+
+       * include/s_user.h: add a prop argument to send_umode_out() to
+       indicate whether or not to propagate the user mode
+
+2001-01-24  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/msgq.c: ircd_vsnprintf() returns the number of bytes that
+       it would have written; upper-bound the number to prevent overflows
+       by proxy; also, tune buffer size given to ircd_vsnprintf() to take
+       into account the fact that ircd_vsnprintf() already takes the
+       terminal \0 into account
+
+2001-01-22  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/msgq.c: add an incredibly ugly hack to attempt to track
+       down an apparent buffer overflow; remove msgq_map(), since it's no
+       longer used anywhere; slight tweaks to prevent off-by-one errors,
+       but these can't explain the problems we've seen
+
+       * include/msgq.h: remove msgq_map(), since it's no longer used
+       anywhere
+
+2001-01-18  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/s_user.c (set_nick_name): call client_set_privs() after
+       parsing user modes
+
+2001-01-17  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/s_bsd.c (read_message): fix a typo in the select version of
+       read_message()
+
+       * ircd/whowas.c (whowas_free): MyFree() is a macro that expects
+       its argument to be an lvalue, which means we can't use
+       whowas_clean()'s handy-dandy "return ww" feature
+
+       * ircd/ircd_features.c: default LOCOP_KILL to TRUE--oops...
+
+2001-01-16  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/ircd_events.c (timer_run): it's possible that the timer got
+       deleted during the callback processing, so don't go to the bother
+       of requeuing it if the destroy flag is set
+
+       * ircd/engine_select.c: define FD_SETSIZE to be IRCD_FD_SETSIZE
+       out of config.h if this is a *BSD; include errno.h (oops);
+       decrement error count after an hour using a timer; use FD_SETSIZE
+       constant instead of IRCD_FD_SETSIZE constant; fill in event
+       processing code
+
+       * ircd/engine_poll.c: include errno.h (oops); decrement error
+       count after an hour using a timer; fill in event processing code
+
+       * ircd/engine_kqueue.c: include errno.h (oops); decrement error
+       count after an hour using a timer; assert events filter is either
+       EVFILT_READ or EVFILT_WRITE; fill in event processing code
+
+       * ircd/engine_devpoll.c: include errno.h (oops); decrement error
+       count after an hour using a timer; fill in event processing code
+
+2001-01-15  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/client.c: fixed feattab; basically, when I changed features
+       to use small integers specifying bit positions, instead of the
+       bits themselves, I forgot to update feattab to not | these
+       privileges together; also fixed a bug in the antiprivs masking
+       loop in client_set_privs()--last index wouldn't get parsed
+
+2001-01-11  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/ircd_events.c: call event_generate() with new data
+       argument; make it set that field in struct Event; make
+       socket_add() return the value of the eng_add callback
+
+       * ircd/engine_select.c: make engine_add() return a
+       successful/unsuccessful status; add bounds-checking outside of an
+       assert; use accessor macros; use log_write(), not the deprecated
+       ircd_log(); add an assert to engine_loop() to double-check for
+       data structure corruption
+
+       * ircd/engine_poll.c: make engine_add() return a
+       successful/unsuccessful status; add bounds-checking outside of an
+       assert; use accessor macros; use log_write(), not the deprecated
+       ircd_log(); add an assert to engine_loop() to double-check for
+       data structure corruption
+
+       * ircd/engine_kqueue.c: implementation of an engine for kqueue()
+
+       * ircd/engine_devpoll.c: implementation of an engine for /dev/poll
+
+       * include/ircd_events.h: define some accessor macros; add ev_data
+       to struct Event for certain important data--errno values, for
+       instance; make EngineAdd callback tell us if it was successful or
+       not; add extra argument to event_generate(); make socket_add()
+       return the status from EngineAdd
+
+2001-01-10  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/ircd_events.c: pass initializer information about how many
+       total _filedescriptors_ may be opened at once
+
+       * ircd/ircd.c: use exported "running" instead of unexported
+       thisServer.running
+
+       * ircd/engine_select.c: implementation of an event engine based on
+       select()
+
+       * ircd/engine_poll.c: implementation of an event engine based on
+       poll()
+
+       * include/ircd_events.h: pass the engine initializer an integer
+       specifing how many _filedescriptors_ may be opened at once
+
+       * include/ircd.h: running has to be exported for the engine_*
+       event loops
+
+2001-01-09  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/ircd_events.c: include some needed headers; add some
+       comments; make evEngines[] const; bundle sig_sock and sig_fd into
+       a struct named sigInfo; rework struct evInfo to have a queue of
+       _generators_, and only when threaded; added a gen_init() function
+       to centralize generator initialization; fix various compile-time
+       errors; rework event_add() for new queueing scheme and checked for
+       compile-time errors; add casts where needed; spell evEngines[]
+       correctly; make engine_name() return const char*
+
+       * include/ircd_events.h: type EventCallBack depends on struct
+       Event, so pre-declare it; put _event_ queue into generators, and
+       only when threaded; give engine data a union to store both ints
+       and pointers; make engine name a const; fix gen_ref_dec() macro;
+       make engine_name() return a const char*
+
+       * ircd/ircd_events.c: gen_dequeue() is now exported, so move it
+       down with the non-static functions; modify event_execute() to use
+       the new gen_ref_dec() to simplify code; make sure event_generate()
+       does not generate new events for generators marked for destruction
+
+       * include/ircd_events.h: the engines, at least, may need to modify
+       reference counts to keep generators from going away while
+       something still points at them, so add reference counter
+       manipulators and export gen_dequeue() for them
+
+       * ircd/ircd_events.c: set up the list of engines to try; set up
+       the signal struct Socket; rename netInfo to evInfo; move static
+       functions near the beginning of the file; do away with
+       signal_signal() (since we no longer keep a signal count ourselves)
+       and call event_generate() directly from signal_callback--also
+       renamed some functions; allow signal_callback() to read up to
+       SIGS_PER_SOCK at once from the signal pipe; add event_init() to
+       initialize the entire event system; add event_loop() to call the
+       engine's event loop; initialize new struct GenHeader member,
+       gh_engdata; remove timer_next(); add socket_add() function to add
+       a socket; add socket_del() to mark a socket for deletion; add
+       socket_state() to transition a socket between states; add
+       socket_events() to set what events we're interested in on the
+       socket; add engine_name() to retrieve event engine's name
+
+       * include/ircd_events.h: add engine data field to struct
+       GenHeader; rename SOCK_ACTION_REMOVE to SOCK_ACTION_DEL; add a
+       note about states vs s_events; remove signal count; fold union
+       Generator back into struct Event; remove count members from struct
+       Generators; redefine engine callbacks to not take a struct
+       Engine*; add explanatory comments to callback definitions; add
+       some engine callbacks to handle operations; remove struct Engine
+       flag member--can detect single flag from eng_signal member; add
+       event_init(), event_loop(), engine_name(), and the socket_*()
+       functions; make timer_next() a macro to avoid a function call
+
+2001-01-08  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * include/ircd_events.h: rename to ircd_events.h, since it handles
+       events, not just networking stuff; add signal support; more
+       structural rearrangement
+
+       * ircd/ircd_events.c: rename to ircd_events.c, since it handles
+       events, not just networking stuff; add signal support; more
+       structural rearrangement
+
+2001-01-07  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/ircd_network.c: implement timer API; add reference counts
+       appropriately
+
+       * include/ircd_network.h: firm up some pieces of the interface;
+       split out members everything has into a separate structure; add
+       reference counts; add timer API
+
+2001-01-06  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/ircd_network.c: static data and event manipulation
+       functions for new event processing system
+
+       * include/ircd_network.h: data structures for new event processing
+       system
+
+2001-01-03  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/whowas.c: Completely re-did the old allocation scheme by
+       turning it into a linked list, permitting the
+       NICKNAMEHISTORYLENGTH feature to be changed on the fly
+
+       * ircd/s_debug.c (count_memory): use FEAT_NICKNAMEHISTORYLENGTH
+       feature instead of old #define
+
+       * ircd/ircd_features.c: add NICKNAMEHISTORYLENGTH feature as an
+       integer feature with a notify callback (whowas_realloc)
+
+       * ircd/client.c (client_set_privs): second memset was supposed to
+       be over antiprivs, not privs; thanks, Chris Behrens
+       <cbehrens@xo.com> for pointing that out...
+
+       * include/whowas.h: new elements for an extra linked list in
+       struct Whowas; a notify function for feature value changes
+
+       * include/ircd_features.h: new feature--FEAT_NICKNAMEHISTORYLENGTH
+
+       * config/config-sh.in: NICKNAMEHISTORYLENGTH is now a feature
+
+2001-01-02  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * config/config-sh.in: get rid of DEFAULT_LIST_PARAMETER
+       compile-time option--now in features subsystem
+
+       * ircd/motd.c (motd_init): rework motd_init() to be called as the
+       notify function for MPATH and RPATH features (should probably
+       split it up a bit, though...)
+
+       * ircd/m_privs.c (mo_privs): if called with no parameters, return
+       privs of the caller, rather than an error
+
+       * ircd/m_list.c: pull usage message into its own function; pull
+       list parameter processing into its own function that does not
+       modify the contents of the parameter; add list_set_default() to
+       set the default list parameter (uses the notify hook); rework
+       m_list() to make use of these functions; removed dead code
+
+       * ircd/ircd_log.c (log_feature_mark): make sure to return 0, since
+       we have no notify handler
+
+       * ircd/ircd_features.c: add notify callback for notification of
+       value changes; give mark callback an int return value to indicate
+       whether or not to call the notify callback; fix up feature macros
+       for new notify callback; add DEFAULT_LIST_PARAM feature; rewrite
+       string handling in feature_set() to deal with def_str being a null
+       pointer; wrote feature_init() to set up all defaults appropriately
+
+       * ircd/ircd.c (main): call feature_init() instead of
+       feature_mark(), to avoid calling notify functions while setting up
+       defaults
+
+       * ircd/client.c: updated to deal with new privileges structure
+
+       * ircd/class.c: updated so init_class() can be called should one
+       of PINGFREQUENCY, CONNECTFREQUENCY, MAXIMUM_LINKS, or
+       DEFAULTMAXSENDQLENGTH be changed
+
+       * include/ircd_log.h: log_feature_mark() updated to fit with new
+       API changes
+
+       * include/ircd_features.h: added DEFAULT_LIST_PARAM feature and
+       feature_init() function (found necessary since adding the notify
+       stuff and notifying motd.c during start-up...before we defined
+       RPATH!)
+
+       * include/client.h: move privs around to enable addition of more
+       bits if necessary; based on the FD_* macros
+
+       * include/channel.h: declare list_set_default (actually located in
+       m_list.c *blanche*)
+
+       * ircd/s_user.c: retrieve MAXSILES and MAXSILELENGTH (now
+       AVBANLEN*MAXSILES) from features subsystem
+
+       * ircd/s_debug.c (debug_serveropts): CMDLINE_CONFIG doesn't go to
+       anything anymore
+
+       * ircd/s_bsd.c: retrieve HANGONGOODLINK and HANGONRETRYDELAY from
+       the features subsystem
+
+       * ircd/s_auth.c (start_auth): NODNS migrated to the features
+       subsystem
+
+       * ircd/random.c: created random_seed_set() function to set seed
+       value, along with some stuff to make ircrandom() a little more
+       random--state preserving, xor of time instead of direct usage,
+       etc.; it's still a pseudo-random number generator, though, and
+       hopefully I haven't broken the randomness
+
+       * ircd/m_version.c: FEATUREVALUES makes use of feature_int() calls
+
+       * ircd/m_join.c: use features interface to retrieve
+       MAXCHANNELSPERUSER
+
+       * ircd/ircd_features.c: add NODISP flag for super-secret features;
+       add a whole bunch of new features migrated over from make config
+
+       * ircd/ircd.c: use features interface to retrieve PINGFREQUENCY,
+       CONNECTTIMEOUT, and TIMESEC
+
+       * ircd/client.c (client_get_ping): use features interface to
+       retrieve PINGFREQUENCY
+
+       * ircd/class.c: use features interface to retrieve PINGFREQUENCY,
+       CONNECTFREQUENCY, MAXIMUM_LINKS, and DEFAULTMAXSENDQLENGTH
+
+       * ircd/chkconf.c (DEFAULTMAXSENDQLENGTH): since it's now in the
+       features subsystem, we have to add something explicit
+
+       * ircd/channel.c: use features interface to retrieve
+       KILLCHASETIMELIMIT, MAXBANLENGTH, MAXBANS, and MAXCHANNELSPERUSER;
+       note that MAXBANLENGTH is now calculated dynamically from MAXBANS
+       and AVBANLEN
+
+       * ircd/Makefile.in: run make depend
+
+       * include/supported.h (FEATURESVALUES): update to reference
+       feature settings
+
+       * include/random.h: add prototype for random_seed_set
+
+       * include/ircd_features.h: add several more features
+
+       * include/channel.h: move MAXBANS and MAXBANLENGTH into feature
+       subsystem
+
+       * config/config-sh.in: feature-ized some more stuff
+
+       * include/motd.h: some new elements in motd.h for motd.c changes
+
+       * ircd/motd.c: motd_cache() now searches a list of already cached
+       MOTD files; saves us from having duplicate caches in memory if
+       there are two identical T-lines for two different sites...
+
+2001-01-02  Perry Lorier <isomer@coders.net>
+       * ircd/motd.c: don't core if the motd isn't found.  Bug found by
+       Amarande.
+
+2001-01-02  Perry Lorier <isomer@coders.net>
+       * ircd/s_err.c: Added third param to 004 - the channel modes that tage params.  Used by hybrid/epic.
+       * ircd/s_channels.c: Added fix for msg'ing a -n+m channel - thanks
+               to guppy for noticing, and hektik for providing the fix.
+       * misc others: Minor cleanups, added more protocol_violations, ripped
+               out more P09 stuffs, bit more protocol neg stuff.
+
+2000-12-19  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/m_ison.c (m_ison): Dianora says that ISON has to end with a
+       space (*sigh* stupid clients...)
+
+       * ircd/s_user.c: make WALLOPS_OPER_ONLY a feature managed through
+       ircd_features.[ch]
+
+       * ircd/s_err.c: get rid of GODMODE conditionals
+
+       * ircd/s_debug.c (debug_serveropts): switch to using appropriate
+       calls into the features subsystem for various serveropts
+       characters
+
+       * ircd/s_conf.c (find_conf_entry): get rid of USEONE conditional
+
+       * ircd/s_bsd.c: remove GODMODE conditional; use features subsystem
+       to get value of VIRTUAL_HOST and CLIENT_FLOOD; remove
+       NOFLOWCONTROL conditional
+
+       * ircd/s_auth.c: use features subsystem to determine value of
+       KILL_IPMISMATCH
+
+       * ircd/parse.c: get rid of NOOPER and GODMODE conditionals; use
+       features subsystem to determine the setting of IDLE_FROM_MSG
+
+       * ircd/numnicks.c: get rid of EXTENDED_NUMERICS conditionals
+
+       * ircd/motd.c: get value of NODEFAULTMOTD from features subsystem;
+       use features subsystem to get motd file names
+
+       * ircd/m_settime.c: get value of RELIABLE_CLOCK from features
+       subsystem
+
+       * ircd/m_server.c: get rid of CRYPT_LINK_PASSWORD, since it does
+       us no good; use features subsystem to figure out if we need to do
+       HUB-type stuff; make TESTNET debugging sendto_opmask_butone's use
+       the Debug(()) macro instead; get value of RELIABLE_CLOCK from
+       features subsystem
+
+       * ircd/m_privmsg.c: get IDLE_FROM_MSG from the features subsystem
+
+       * ircd/m_oper.c: get CRYPT_OPER_PASSWORD from the features
+       subsystem
+
+       * ircd/m_connect.c: get SERVER_PORT from the features subsystem
+
+       * ircd/ircd_log.c (log_set_file): fix a bug that kept log files
+       from getting marked if they were already set to something...
+
+       * ircd/ircd_features.c: add a flag to indicates read-only access;
+       add several new features that used to be compile-time selected
+
+       * ircd/ircd.c: grab pidfile out of feature subsystem; don't check
+       access to motd files (what the heck?); make sure to initialize the
+       feature subsystem before trying to write the config file
+
+       * ircd/dbuf.c: use feature_int() to retrieve BUFFERPOOL settings;
+       use feature_bool() to figure out if we're using the FERGUSON
+       flusher
+
+       * ircd/Makefile.in: MPATH and RPATH are now done differently, so
+       remove the clause that creates empty files of that name; also ran
+       make depend
+
+       * include/sys.h: CLIENT_FLOOD is now a feature; unfortunately,
+       there is no easy way to bounds-check it at present
+
+       * include/querycmds.h: make sure ircd_features.h is included; use
+       feature_str(FEAT_DOMAINNAME) in calls to match()
+
+       * include/ircd_features.h: many new features that used to be
+       compile-time selected
+
+       * config/config-sh.in: add * to DOMAINNAME; try also using first
+       argument to search in /etc/resolv.conf; removed many compile-time
+       options that now can be configured through the features system
+
+2000-12-18  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * doc/api/log.txt: how to use the logging API
+
+       * doc/api/features.txt: how to use the features API
+
+       * doc/api/api.txt: how to write API documentation
+
+       * include/ircd_features.h: rearranged a couple of features for
+       neatness purposes
+
+       * ircd/ircd_features.c: cleaned up the macros some; rearranged
+       some code to all go into the switch; rearranged a couple of
+       features for neatness purposes
+
+2000-12-16  Greg Sikorski <gte@atomicrevs.demon.co.uk>
+       * ircd/os_bsd.c: Added os_set_tos for BSD users.
+
+2000-12-16  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/ircd_features.c: Isomer almost got it right; you need to
+       use F_I(), since it's an integer value, not a boolean value.  The
+       asserts in feature_int would catch you out...  Also made the F_*
+       macros take flags
+
+       * ircd/s_err.c: define RPL_PRIVS reply
+
+       * ircd/parse.c: put new PRIVS command into command table
+
+       * ircd/m_privs.c (mo_privs): message handler to report operator
+       privileges
+
+       * ircd/ircd_features.c: declare new features OPER_SET and
+       LOCOP_SET; redo boolean testing routine to accept TRUE, YES, and
+       ON for boolean TRUE, and FALSE, NO, and OFF for boolean FALSE
+
+       * ircd/client.c: simplify client_set_privs() with a table that
+       defines what features to test for; add new client_report_privs()
+
+       * ircd/Makefile.in: compile new m_privs.c; run make depend
+
+       * include/numeric.h (RPL_PRIVS): new reply numeric for displaying
+       an operator's privileges
+
+       * include/msg.h: define new command: PRIVS
+
+       * include/ircd_features.h: create new features OPER_SET and
+       LOCOP_SET for controlling access to /set
+
+       * include/handlers.h (mo_privs): declare message handler for
+       reporting oper privileges
+
+       * include/client.h (client_report_privs): declare function to
+       report what privileges an oper has
+
+       * ircd/m_whois.c (do_whois): fix a bug that caused /whois to
+       report that a user is an oper if the oper doing the /whois had
+       PRIV_SEE_OPERS
+
+2000-12-17  Isomer <Isomer@coders.net>
+       * ircd/listener.c: added support for TOS twiddling as a 'feature'.
+
+2000-12-17  Isomer <Isomer@coders.net>
+       * ircd/os_linux.c: add TOS stuffs
+
+       * ircd/listener.c: add TOS stuffs
+
+2000-12-16  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/whocmds.c (do_who): use HasPriv to determine whether or not
+       to indicate a user is an oper
+
+       * ircd/s_user.c: clear privileges setting when deopping; don't
+       propagate +o unless user has PRIV_PROPAGATE privilege
+
+       * ircd/s_debug.c (debug_serveropts): created debug_serveropts()
+       function and replaced how the server option string is generated
+
+       * ircd/parse.c: remove conditional on CONFIG_OPERCMDS
+
+       * ircd/m_whois.c (do_whois): use HasPriv to determine whether or
+       not to indicate the user is an operator
+
+       * ircd/m_who.c: use HasPriv to determine whether or not a user
+       should be displayed in the list of opers
+
+       * ircd/m_version.c: call debug_serveropts() to get server option
+       string
+
+       * ircd/m_userip.c (userip_formatter): use HasPriv to determine
+       whether or not to show oper status
+
+       * ircd/m_userhost.c (userhost_formatter): use HasPriv to determine
+       whether or not to show oper status
+
+       * ircd/m_restart.c (mo_restart): replace ugly #ifdef conditional
+       checks with HasPriv check; remove dead code
+
+       * ircd/m_rehash.c (mo_rehash): replace ugly #ifdef conditional
+       checks with HasPriv check
+
+       * ircd/m_opmode.c (mo_opmode): use HasPriv to check permissions;
+       use feature_bool to check if disabled
+
+       * ircd/m_oper.c (m_oper): set oper priviliges
+
+       * ircd/m_mode.c (m_mode): replace #ifdef conditional with HasPriv
+       check
+
+       * ircd/m_kill.c (mo_kill): use HasPriv checks to determine if we
+       can kill
+
+       * ircd/m_kick.c (m_kick): replace #ifdef conditional with HasPriv
+       check
+
+       * ircd/m_jupe.c (mo_jupe): rework permissions checking structure;
+       use feature_bool to check if disabled
+
+       * ircd/m_join.c (m_join): remove BADCHAN conditional; replace
+       #ifdef conditional with a HasPriv check
+
+       * ircd/m_gline.c (mo_gline): rework permissions checking
+       structure; use feature_bool to check if any part is disabled
+
+       * ircd/m_die.c: replace ugly #ifdef conditionals with HasPriv
+       check; remove dead code
+
+       * ircd/m_clearmode.c: use feature_bool() to detect if we're
+       disabled; use HasPriv to figure out what we're permitted to do;
+       only allow clearmode on moded channels
+
+       * ircd/ircd_features.c: define various features; use HasPriv to
+       verify permissions to set/reset
+
+       * ircd/gline.c (gline_add): use HasPriv instead of #ifdef
+       conditionals
+
+       * ircd/client.c (client_set_privs): function to set an oper's
+       privileges
+
+       * ircd/channel.c: use HasPriv calls instead of #ifdef conditionals
+
+       * include/whocmds.h: deconditionalize several macros and
+       substitute appropriate calls to HasPriv()
+
+       * include/s_debug.h: get rid of global serveropts[]; define new
+       function debug_serveropts() to build that string on the fly
+
+       * include/ircd_features.h: define some features
+
+       * include/client.h: add privs member to struct Connection; define
+       various priviledges
+
+       * include/channel.h: no longer using IsOperOnLocalChannel; remove
+       conditional of MAGIC_OPER_OVERRIDE on OPER_WALK_THROUGH_LMODES
+
+       * doc/Configure.help: remove help information for deprecated
+       options
+
+       * config/config-sh.in: remove certain deprecated options having to
+       do with what opers can and cannot do--first stage in moving
+       compile-time constants into the .conf
+
+2000-12-16  Isomer <Isomer@coders.net>
+       * ircd/parse.c: detect if the prefix is missing and try and recover
+       instead of coring.
+
+2000-12-15  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/ircd_log.c: found and fixed some bugs in the debug logging
+       code that would sometimes result in the log file not being
+       reopened--which meant that a user could connect and get the
+       logging output--oops
+
+       * ircd/Makefile.in: run make depend...
+
+       * ircd/s_stats.c: get rid of report_feature_list()
+
+       * ircd/s_err.c: add the 'bad value' error message, shift error
+       messages over somewhat
+
+       * ircd/s_debug.c (debug_init): call log_debug_init with the
+       use_tty flag
+
+       * ircd/s_conf.c (read_configuration_file): unmark features before
+       reading the config file, then reset unmarked features after
+       reading the config file
+
+       * ircd/m_stats.c: use feature_report() instead of
+       report_feature_list()
+
+       * ircd/ircd_log.c: fix log_debug_file (bogus assertion); add
+       special 'mark' flags and use them; add the stuff needed by the
+       features API
+
+       * ircd/ircd_features.c: rework the features API and add gobs of
+       comments to try to explain what some of these complex functions
+       are actually doing
+
+       * include/s_stats.h: get rid of report_feature_list(); use
+       feature_report() instead
+
+       * include/numeric.h: added a new error message and shifted old
+       values over some--this is, after all, an alpha
+
+       * include/ircd_log.h: log_debug_init now takes an integer to tell
+       it if it should be using the tty; added a couple of functions
+       required by the features API
+
+       * include/ircd_features.h: add an enum and some more functions to
+       flesh out the feature API--it should now be possible to put all
+       those compile-time constants in the config file!
+
+       * ircd/send.c: got the direction of the assert incorrect...
+
+       * ircd/send.c: implement the efficiency of flush_connections by
+       creating a linked list of struct Connection's with queued data;
+       also get rid of flush_sendq_except and make sure to yank
+       connections out of the list when their sendQs become empty (notice
+       the assertion in flush_connections!)
+
+       * ircd/s_bsd.c (close_connection): must yank the Connection out of
+       the sendq list
+
+       * ircd/list.c (dealloc_connection): must yank the Connection out
+       of the sendq list
+
+       * ircd/dbuf.c (dbuf_put): call flush_connections instead of the
+       deprecated flush_sendq_except
+
+       * ircd/client.c: define a couple new helper functions for sendq
+       threading--this will make the flush_connections function in send.c
+       considerably more efficient by creating a linked list of
+       Connections that have queued data to send
+
+       * include/send.h: remove flush_sendq_except, as it's not used
+       anymore
+
+       * include/client.h: declare a couple new helper functions for the
+       sendq threading system
+
+2000-12-14  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/m_ison.c (m_ison): Apply Diane Bruce's patch to make ISON
+       parse all arguments
+
+       * ircd/s_debug.c (count_memory): modify to report for clients and
+       connections, not local clients and remote clients
+
+       * ircd/list.c: fiddle with the client-fiddling functions to take
+       into account the divorce of struct Connection from struct Client
+
+       * ircd/ircd.c: define a struct Connection for me, initialize it,
+       and link it into the right place (ewww, globals!)
+
+       * include/client.h: remove CLIENT_{LOCAL,REMOTE}_SIZE; split
+       struct Client into struct Client and struct Connection; redefine
+       local-portion accessor macros to go through struct Client to the
+       struct Connection; define struct Connection accessor macros
+
+2000-12-13  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/whowas.c: missed a couple of accesses to a struct Client
+
+       * ircd/uping.c: missed a couple of accesses to a struct Client
+
+       * ircd/send.c: missed a couple of accesses to a struct Client
+
+       * ircd/s_user.c: missed a couple of accesses to a struct Client
+
+       * ircd/s_misc.c: missed a couple of accesses to a struct Client
+
+       * ircd/s_conf.c: missed a couple of accesses to a struct Client
+
+       * ircd/s_bsd.c: missed a couple of accesses to a struct Client
+
+       * ircd/s_auth.c: missed a couple of accesses to a struct Client
+
+       * ircd/res.c: missed a couple of accesses to a struct Client
+
+       * ircd/parse.c: missed a couple of accesses to a struct Client
+
+       * ircd/m_whois.c: use new accessor macros for struct Client
+
+       * ircd/m_who.c: use new accessor macros for struct Client
+
+       * ircd/m_wallchops.c: use new accessor macros for struct Client
+
+       * ircd/m_version.c: use new accessor macros for struct Client
+
+       * ircd/m_userip.c: use new accessor macros for struct Client
+
+       * ircd/m_userhost.c: use new accessor macros for struct Client
+
+       * ircd/m_user.c: use new accessor macros for struct Client
+
+       * ircd/m_uping.c: use new accessor macros for struct Client
+
+       * ircd/m_trace.c: use new accessor macros for struct Client
+
+       * ircd/m_topic.c: use new accessor macros for struct Client
+
+       * ircd/m_time.c: use new accessor macros for struct Client
+
+       * ircd/m_stats.c: use new accessor macros for struct Client
+
+       * ircd/m_squit.c: use new accessor macros for struct Client
+
+       * ircd/m_silence.c: use new accessor macros for struct Client
+
+       * ircd/m_server.c: use new accessor macros for struct Client;
+       remove dead code
+
+       * ircd/m_rpong.c: use new accessor macros for struct Client
+
+       * ircd/m_rping.c: use new accessor macros for struct Client
+
+       * ircd/m_quit.c: use new accessor macros for struct Client
+
+       * ircd/m_privmsg.c: use new accessor macros for struct Client
+
+       * ircd/m_pong.c: use new accessor macros for struct Client; remove
+       dead code
+
+       * ircd/m_ping.c: use new accessor macros for struct Client
+
+       * ircd/m_pass.c: use new accessor macros for struct Client
+
+       * ircd/m_part.c: use new accessor macros for struct Client
+
+       * ircd/m_oper.c: use new accessor macros for struct Client
+
+       * ircd/m_notice.c: use new accessor macros for struct Client
+
+       * ircd/m_nick.c: use new accessor macros for struct Client
+
+       * ircd/m_names.c: use new accessor macros for struct Client
+
+       * ircd/m_mode.c: use new accessor macros for struct Client
+
+       * ircd/m_map.c: use new accessor macros for struct Client
+
+       * ircd/m_list.c: use new accessor macros for struct Client
+
+       * ircd/m_links.c: use new accessor macros for struct Client;
+       remove some dead code
+
+       * ircd/m_kill.c: use new accessor macros for struct Client; remove
+       some dead code
+
+       * ircd/m_kick.c: use new accessor macros for struct Client
+
+       * ircd/m_join.c: use new accessor macros for struct Client; remove
+       some dead code
+
+       * ircd/m_ison.c: use new accessor macros for struct Client
+
+       * ircd/m_invite.c: use new accessor macros for struct Client
+
+       * ircd/m_info.c: use new accessor macros for struct Client
+
+       * ircd/m_gline.c: use new accessor macros for struct Client
+
+       * ircd/m_error.c: use new accessor macros for struct Client
+
+       * ircd/m_create.c: use new accessor macros for struct Client
+
+       * ircd/m_connect.c: use new accessor macros for struct Client;
+       removed some dead code
+
+       * ircd/m_burst.c: use new accessor macros for struct Client
+
+       * ircd/m_away.c: use new accessor macros for struct Client
+
+       * ircd/m_admin.c: use new accessor macros for struct Client
+
+       * ircd/hash.c: missed a couple of accesses to a struct Client
+
+       * ircd/gline.c: missed a couple of accesses to a struct Client
+
+       * ircd/crule.c: missed a couple of accesses to a struct Client
+
+       * ircd/class.c: missed an access to a struct Client
+
+       * ircd/channel.c: missed a couple of accesses to a struct Client
+
+       * ircd/IPcheck.c: missed an access to a struct Client
+
+       * include/querycmds.h: fix a couple of stats macros to use
+       structure accessor macros
+
+       * include/client.h: change structure member names to highlight any
+       places in the code I've missed
+
+2000-12-12  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/whowas.c: use new struct Client accessor macros
+
+       * ircd/whocmds.c: use new struct Client accessor macros
+
+       * ircd/send.c: use new struct Client accessor macros
+
+       * ircd/s_user.c: use new struct Client accessor macros; removed
+       some dead code
+
+       * ircd/s_serv.c: use new struct Client accessor macros; removed
+       some dead code
+
+       * ircd/s_numeric.c: use new struct Client accessor macros
+
+       * ircd/s_misc.c: use new struct Client accessor macros
+
+       * ircd/s_debug.c: use new struct Client accessor macros
+
+       * ircd/s_conf.c: use new struct Client accessor macros
+
+       * ircd/s_bsd.c: use new struct Client accessor macros
+
+       * ircd/s_auth.c: use new struct Client accessor macros
+
+       * ircd/parse.c: use new struct Client accessor macros
+
+       * ircd/packet.c: use new struct Client accessor macros
+
+       * ircd/numnicks.c: use new struct Client accessor macros
+
+       * ircd/motd.c: use new struct Client accessor macros
+
+       * ircd/listener.c: use new struct Client accessor macros
+
+       * ircd/list.c: use new struct Client accessor macros
+
+       * ircd/jupe.c: use new struct Client accessor macros
+
+       * ircd/ircd_snprintf.c: use new struct Client accessor macros
+
+       * ircd/ircd_reply.c: use new struct Client accessor macros
+
+       * ircd/ircd_relay.c: use new struct Client accessor macros
+
+       * ircd/ircd.c: use new struct Client accessor macros
+
+       * ircd/gline.c: catch some instances of me.<stuff> I missed
+       previously
+
+       * ircd/client.c: use cli_ instead of con_
+
+       * ircd/class.c: use cli_ instead of con_
+
+       * ircd/channel.c: use cli_ instead of con_
+
+       * ircd/IPcheck.c: use cli_ instead of con_; catch some instances
+       of me.<stuff> I missed previously
+
+       * include/client.h: use cli_ instead of con_...seemed like a good
+       idea at the time *shrug*
+
+2000-12-11  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/hash.c: use struct Client accessor macros
+
+       * ircd/gline.c: use struct Client accessor macros
+
+       * ircd/crule.c: use struct Client accessor macros
+
+       * ircd/client.c: use struct Client accessor macros; remove some
+       dead code
+
+       * ircd/class.c: use struct Client accessor macros
+
+       * ircd/channel.c: use struct Client accessor macros; remove some
+       dead code
+
+       * ircd/IPcheck.c: use struct Client accessor macros
+
+       * include/numnicks.h: use struct Client accessor macros
+
+       * include/client.h: first step to divorcing struct Client and
+       struct Connection--define accessor macros and use them
+
+       * ircd/gline.c: When Uworld removed Uworld-set G-lines, only the
+       uplink would remove them.  This is because the removal protocol
+       message wasn't being sent to the uplinks.  This is fixed by fixing
+       propagate_gline() to send the proper number of arguments depending
+       on whether or not we're adding or deleting the Uworld gline, and
+       by having gline_deactivate() make sure to turn off the active bit
+       and call propagate_gline() if it's a Uworld gline
+
+2000-12-10  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/os_generic.c: make sure IOV_MAX gets defined, just in case
+
+       * ircd/os_bsd.c: apparently BSD doesn't have IOV_MAX defined
+       anywhere intelligent...
+
+2000-12-09  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/send.c (send_queued): call deliver_it with appropriate
+       arguments
+
+       * ircd/s_serv.c: reorder a couple of headers--cosmetic
+
+       * ircd/s_bsd.c (deliver_it): make deliver_it work with a struct
+       MsgQ
+
+       * ircd/os_solaris.c (os_sendv_nonb): function for calling writev
+       with appropriate iovec
+
+       * ircd/os_linux.c (os_sendv_nonb): function for calling writev
+       with appropriate iovec
+
+       * ircd/os_generic.c (os_sendv_nonb): function for calling writev
+       with appropriate iovec
+
+       * ircd/os_bsd.c (os_sendv_nonb): function for calling writev with
+       appropriate iovec
+
+       * ircd/msgq.c (msgq_mapiov): add a len_p argument for totalling up
+       exactly how much we're trying to write out to the fd
+
+       * include/s_bsd.h: make deliver_it take a struct MsgQ
+
+       * include/msgq.h: add a len_p argument to msgq_mapiov to help
+       detect short writes that indicate possible socket blocking
+
+       * include/ircd_osdep.h: declare os_sendv_nonb()
+
+       * ircd/channel.c (modebuf_mode): don't add empty modes...
+
+2000-12-08  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * include/send.h: add prio argument to send_buffer to select
+       between normal and priority queues
+
+       * ircd/s_user.c (send_user_info): add prio argument to send_buffer
+       call
+
+       * ircd/m_ison.c (m_ison): add prio argument to send_buffer call
+
+       * ircd/ircd_reply.c (send_reply): add prio argument to send_buffer
+       call
+
+       * ircd/channel.c (send_channel_modes): add prio argument to
+       send_buffer call
+
+       * ircd/send.c (send_buffer): add a prio argument to select the
+       priority queue; update send.c functions to use it
+
+       * ircd/msgq.c (msgq_add): remove msgq_prio; fold msgq_link and
+       msgq_add; add a prio argument to msgq_add to select the priority
+       queue
+
+       * include/msgq.h: remove msgq_prio; add a prio argument to
+       msgq_add
+
+       * ircd/send.c: remove sendbuf; remove GODMODE code; switch to
+       using msgq functions instead of dbuf functions; remove old, dead
+       sendto_* functions; redo send_buffer to take a struct MsgBuf;
+       rework sendcmdto_* functions to make use of the new struct MsgBuf
+
+       * ircd/s_user.c: remove hunt_server; restructure send_user_info to
+       make appropriate use of struct MsgBuf
+
+       * ircd/s_debug.c (count_memory): count memory used by the MsgQ
+       system and report it
+
+       * ircd/s_conf.c (read_configuration_file): use
+       sendto_opmask_butone instead of the now dead sendto_op_mask
+
+       * ircd/s_bsd.c: switch to using appropriate MsgQLength and other
+       calls on sendQ
+
+       * ircd/parse.c (parse_server): get rid of a piece of GODMODE code
+
+       * ircd/msgq.c: add msgq_append and msgq_bufleft; fix a bug in
+       msgq_clean
+
+       * ircd/m_version.c: fix spelling in comments marking dead code
+
+       * ircd/m_userip.c (userip_formatter): restructure to make use of
+       struct MsgBuf
+
+       * ircd/m_userhost.c (userhost_formatter): restructure to make use
+       of struct MsgBuf
+
+       * ircd/m_stats.c: use MsgQLength on a sendQ
+
+       * ircd/m_settime.c: use MsgQLength instead of DBufLength on a
+       sendQ; mark a piece of dead code
+
+       * ircd/m_names.c: use send_reply instead of sendto_one
+
+       * ircd/m_mode.c: use new mode; remove old dead code
+
+       * ircd/m_ison.c (m_ison): restructure to make use of struct MsgBuf
+
+       * ircd/m_burst.c: use BUFSIZE instead of IRC_BUFSIZE; remove old
+       dead code
+
+       * ircd/listener.c (accept_connection): use sendto_opmask_butone
+       instead of sendto_op_mask
+
+       * ircd/list.c (free_client): use MsgQClear to clear sendQ
+
+       * ircd/ircd_reply.c: remove send_error_to_client; restructure
+       send_reply to make use of struct MsgBuf
+
+       * ircd/dbuf.c (dbuf_put): remove argument to flush_sendq_except,
+       since its no longer used (at least currently)
+
+       * ircd/channel.c: restructure send_channel_modes to make use of
+       struct MsgBuf; remove set_mode, add_token_to_sendbuf, cancel_mode,
+       and send_hack_notice; use BUFSIZE instead of IRC_BUFSIZE
+
+       * ircd/Makefile.in: add msgq.c to list of sources; run make depend
+
+       * ircd/IPcheck.c: use sendcmdto_one instead of sendto_one
+
+       * include/send.h: send_buffer now takes a struct MsgBuf * instead
+       of a char *; flush_sendq_except now takes no arguments, as sendq
+       flushing currently only happens in dbuf.h and sendQ is a struct
+       MsgQ; remove prototypes for a lot of old sendto_* functions that
+       aren't used anymore; remove sendbuf and IRC_BUFSIZE--the former is
+       no longer needed, and the latter is identical to BUFSIZE in
+       ircd_defs.h
+
+       * include/s_user.h: make InfoFormatter take a struct MsgBuf*
+       instead of a char *; also make it return void, instead of char *
+
+       * include/msgq.h: add msgq_append and msgq_bufleft functions
+
+       * include/client.h: use a struct MsgQ instead of a struct DBuf for
+       sendq
+
+       * doc/Configure.help: Remove help for compile-time options that
+       have gone away
+
+       * config/config-sh.in: remove CONFIG_NEWMODE
+
+       * ircd/m_server.c (mr_server): don't send server IPs in any server
+       notices
+
+       * ircd/msgq.c (msgq_vmake): add \r\n to messages
+
+2000-12-07  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * include/msgq.h: declare the MsgQ API
+
+       * ircd/msgq.c: implementation of new MsgQ system
+
+2000-12-06  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/ircd_features.c: #include was supposed to be for
+         ircd_features.h, not features.h--missed when I had to do a
+         rename because of namespace collision
+
+2000-12-05  Greg Sikorski <gte@atomicrevs.demon.co.uk>
+       * ircd/m_topic.c: Added missing braces that caused all remote
+         topics to be ignored.
+
+2000-12-04  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/m_create.c: I'm tired of the exit_client warning :)
+       (ms_create): discovered that exit_client() was being called with
+       too few arguments
+
+       * ircd/s_misc.c (exit_client): remove all dependance on
+       FNAME_USERLOG, since that's now gone; log only to LS_USER
+
+       * ircd/s_debug.c: USE_SYSLOG no longer means anything
+
+       * ircd/m_oper.c (m_oper): no longer log to LS_OPERLOG--we already
+       log to LS_OPER
+
+       * ircd/m_kill.c: no longer conditionalize on SYSLOG_KILL
+
+       * ircd/ircd_log.c: remove LS_OPERLOG, LS_USERLOG
+
+       * include/ircd_log.h: remove LS_OPERLOG, LS_USERLOG--they serve
+       the same purpose as LS_USER and LS_OPER
+
+       * config/config-sh.in: remove no longer relevant log config
+       variables
+
+       * ircd/uping.c (uping_init): use log_write instead of ircd_log
+
+       * ircd/s_misc.c (exit_client): use log_write instead of ircd_log
+
+       * ircd/s_conf.c: use log_write instead of ircd_log
+
+       * ircd/s_bsd.c (report_error): use log_write instead of ircd_log
+
+       * ircd/s_auth.c (timeout_auth_queries): use log_write instead of
+       ircd_log
+
+       * ircd/res.c (send_res_msg): use log_write instead of ircd_log
+
+       * ircd/m_who.c: use log_write instead of write_log; no longer
+       conditionalize on WPATH; mark dead ircd_log calls
+
+       * ircd/m_uping.c: mark dead ircd_log call
+
+       * ircd/m_server.c (mr_server): use log_write instead of ircd_log
+
+       * ircd/m_restart.c: use log_write instead of ircd_log; mark dead
+       ircd_log calls
+
+       * ircd/m_rehash.c (mo_rehash): use log_write instead of ircd_log
+
+       * ircd/m_oper.c: use log_write instead of ircd_log; no longer
+       conditionalize on FNAME_OPERLOG; mark dead ircd_log calls
+
+       * ircd/m_kill.c: mark dead ircd_log calls
+
+       * ircd/m_connect.c: use log_write instead of ircd_log; mark dead
+       ircd_log
+
+       * ircd/m_clearmode.c: use log_write instead of write_log; no
+       longer conditionalize on OPATH
+
+       * ircd/jupe.c: use log_write instead of write_log; no longer
+       conditionalize on JPATH
+
+       * ircd/ircd_log.c: add USER subsystem; remove ircd_log() compat
+       function; fix a couple of bugs
+
+       * ircd/ircd_alloc.c: fixed a comment
+
+       * ircd/ircd.c: use log_write instead of ircd_log; fold server
+       notice generation in a couple of cases
+
+       * ircd/gline.c: use log_write instead of write_log; no longer
+       conditionalize on GPATH
+
+       * ircd/channel.c (modebuf_flush_int): use log_write instead of
+       write_log; no longer conditionalize on OPATH
+
+       * ircd/Makefile.in: run make depend, since dependencies have
+       changed
+
+       * doc/example.conf: add system USER to documentation
+
+       * include/ircd_log.h: add system USER; remove old ircd_log()
+       declarations
+
+2000-12-04  Isomer <isomer@coders.net>
+       * ircd/m_names.c: Add NAMES_EON to do_names to say add a
+       'end_of_names' reply when done.
+       * ircd/m_join.c: use NAMES_EON as mentioned above
+
+2000-12-01  net  <simms@LUCIDA.QC.CA>
+
+       * ircd/motd.c: add a freelist for struct Motds
+
+2000-11-30  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/s_stats.c (report_feature_list): report features--only
+       local opers can see logging configuration, since it doesn't really
+       mean anything to users
+
+       * ircd/s_err.c: add reply messages for new feature subsystem
+
+       * ircd/s_conf.c: add F lines to .conf
+
+       * ircd/parse.c: add the message descriptions for /set, /reset, and
+       /get
+
+       * ircd/m_stats.c: add /stats f
+
+       * ircd/m_set.c (mo_set): implement /set
+
+       * ircd/m_reset.c (mo_reset): implement /reset
+
+       * ircd/m_rehash.c: /rehash m now flushes MOTD cache, and /rehash l
+       reopens log files (for log file rotation)
+
+       * ircd/m_get.c (mo_get): implement /get
+
+       * ircd/ircd_log.c: use int instead of void return value; add
+       log_report_features() and log_canon(); fix a function that
+       disappears if DEBUGMODE not #define'd
+
+       * ircd/ircd_features.c: functions to manipulate feature settings
+       either from the config file or with the new /set, /reset, and /get
+       commands
+
+       * ircd/Makefile.in: add new .c files, run make depend
+
+       * include/s_stats.h: declare report_feature_list() (/stats f
+       handler)
+
+       * include/numeric.h: add RPL_STATSFLINE, RPL_FEATURE,
+       ERR_NOFEATURE, ERR_BADLOGTYPE, ERR_BADLOGSYS, and ERR_BADLOGVALUE
+       reply numerics
+
+       * include/msg.h: add defines for SET, RESET, and GET
+
+       * include/ircd_log.h: add a function to canonicalize subsystem
+       names; change some void return values to int
+
+       * include/ircd_features.h: new features subsystem handles all the
+       manipulation of special features, like log files
+
+       * include/handlers.h: declare new mo_{s,res,g}et message handlers
+       for fiddling with features run-time
+
+       * include/client.h (SNO_DEFAULT): don't set SNO_DEBUG by default;
+       seemed like a good idea at the time...
+
+       * doc/example.conf: document new F lines
+
+2000-11-29  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/s_debug.c: rewrite debug_init() and vdebug() in terms of
+       new logging functions, which have special support for the debug
+       log; added loop detection to vdebug(), so that I can
+       sendto_opmask_butone() from log_vwrite() without incurring another
+       call to vdebug()
+
+       * ircd/s_conf.c (rehash): call log_reopen() from rehash routine;
+       this allows log file rotations
+
+       * ircd/m_kill.c: call log_write_kill() instead of ircd_log_kill()
+
+       * ircd/ircd_log.c: much more work fleshing out the interface;
+       removed old interface; included backwards-compat ircd_log()
+       function that logs to subsystem LS_OLDLOG
+
+       * ircd/ircd.c: switch to new log_init()/log_close()/log_reopen()
+       functions
+
+       * include/ircd_log.h: include stdarg.h for va_list; move ordering
+       warning to top of file; fill out LogSys enum; declare new
+       log_debug_init(), log_vwrite(), log_write_kill(), and
+       log_[sg]et_*() functions; add flags argument to log_write();
+       defined flags to inhibit various logging actions
+
+       * include/client.h: added support for new SNO_DEBUG, enabled only
+       if DEBUGMODE is defined
+
+2000-11-28  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/ircd_log.c: make sure the various LOG_* constants are
+       defined (probably not needed, since #include <syslog.h> isn't
+       conditional); various static data needed for the new logging
+       functions; definitions of new logging functions
+
+       * include/ircd_log.h: new LogSys enum, declarations for part of
+       new logging API
+
+       * ircd/motd.c: we were setting type to MOTD_CLASS unconditionally,
+       which was of course stupid; switched to using switch/case in
+       initialization in motd_create(); zero the MotdList.other pointer
+       from motd_clear()
+
+       * ircd/ircd.c (main): motd_init() has to come before init_conf(),
+       or we overwrite init_conf()'s hard work with respect to T-lines
+
+2000-11-27  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/s_stats.c: comment out report_motd_list and include a
+       reference to motd_report()
+
+       * ircd/s_conf.c: rip out the old MOTD manipulation functions; call
+       motd_add() from the conf parser; call motd_clear() from the rehash
+       routine; remove the no longer needed memory clearing and reloading
+       stuff from the rehash service routine
+
+       * ircd/motd.c: loads new API, including static internal functions
+       to do allocation/deallocation, etc.
+
+       * ircd/m_stats.c: use new motd_report() instead of
+       report_motd_list()
+
+       * ircd/m_motd.c: use new syntax for motd_send()
+
+       * ircd/ircd.c: use new motd_init() function
+
+       * ircd/Makefile.in (SRC): forgot to add motd.c to SRC in
+       Makefile.(in); also ran make depend
+
+       * include/motd.h: don't need config.h, but now do need time.h;
+       define new structures and constants; redefine old API and define
+       new functions
+
+2000-11-22  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/s_user.c (register_user): use motd_signon() instead of
+       calling m_motd; much cleaner this way
+
+       * ircd/motd.c: write the new motd_* stuff to make MOTD handling
+       less of a crock
+
+       * ircd/m_motd.c: rewrite m{,s}_motd to call out to new motd_*
+       functions
+
+       * include/motd.h: define new MOTD API stuff
+
+2000-11-20  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/ircd_reply.c (protocol_violation): rewrite
+       protocol_violation so it'll actually work
+
+       oh, yeah, use %s -> cptr->name, instead of %c -> cptr, so we get
+       the client's real name in there.
+
+       * ircd/m_motd.c (m_motd): Iso's addition of get_client_class(sptr)
+       resulted in core dumps if NODEFAULTMOTD is defined, because m_motd
+       gets called from register_user with a NULL sptr.  This is probably
+       a design problem, but this bandaid will do for now...
+
+2000-11-19  Isomer <isomer@coders.net>
+       * ircd/ircd_reply.c: added 'protocol_violation', thus alerting us
+       to problems in the server<->server protocol.
+
+       * ircd/m_connect.c: allow remote connects with a port of '0'
+       meaning to use the port in the config file.
+
+       * ircd/m_create.c: Enable hacking protection, lets see how far we
+       get.
+
+       * ircd/m_error.c: The RFC says never accept ERROR from unreg'd
+       clients, so we don't any more.
+
+       * ircd/m_kill.c: The kill path is now made up of numnicks of servers,
+       and the user@host is displayed of the victim.
+
+       * ircd/m_map.c: reloaded 'dump_map'.
+
+       * ircd/m_trace.c: allow per class T:
+
+       * ircd/m_stats.c: allow local opers /remote stats anywhere on the 'net.
+
+2000-11-17  Isomer <isomer@coders.net>
+
+       * ircd/m_topic.c: Fixed bug where we'd only send to clients topics
+       that were the *same* instead of different.  Oh the embarrasment!
+
+       * ircd/IPcheck.c: Merged net's fix.
+
+2000-11-02  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/m_whois.c: remove compiler warning by adding a newline to
+       end of file
+
+       * ircd/m_names.c: moved the flags up to s_user.h
+
+       * ircd/m_join.c: call do_names instead of m_names; restructure
+       ms_join to never transmute a JOIN into a CREATE, but use the TS in
+       the JOIN (if present) to timestamp the channel
+
+       * ircd/channel.c: send JOINs individually, instead of grouping
+       them, so that we can send the channel's creation time
+
+       * include/s_user.h: declare do_names()
+
+2000-10-30  Isomer <isomer@coders.net>
+       * ircd/m_oper.c: Fixed warning
+
+2000-10-30  Isomer <isomer@coders.net>
+       * ircd/m_oper.c: Fixed over agressive cut and no paste
+
+2000-10-30  Isomer <isomer@coders.net>
+
+       * ircd/m_topic.c: Restructured, fixed bug where topics on local
+       channels are propergated (I forget who pointed this out to me, but
+       thanks anyway).  Also to save bandwidth don't send the topic to
+       users if the topic is already the same on the server (but still
+       propergate to other servers).  X/W's "autotopic" feature must
+       chew a lot of bandwidth, hopefully this will help reduce this.
+
+       * doc/rfc1459.rfc: Updated documentation on /topic.
+
+       * ircd/listener.c: snotice warnings about failed accept()'s
+       potentially warning admins that they're running out of fd's.
+
+       * ircd/stats.c, ircd/class.c: Removed /stats v, added number of
+       people in a class in /stats y
+
+       * ircd/m_create.c: Checks for timewarp hacking and squit's
+       evil servers. (currently disabled)
+       
+
+2000-10-30  net <simms@lucida.qc.ca>
+       
+       * ircd/gline.c: Fixed various bugs Isomer left behind.
+
+2000-10-26  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/m_join.c (m_join): reply on attempt to join a BADCHANed
+       channel is now ERR_BANNEDFROMCHAN instead of ERR_BADCHANNAME
+
+2000-10-24  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/channel.c: ok, now last mode rules; mode +ps will always
+       result in +s (and won't send a mode if the channel is already +s);
+       mode +sp will always result in +p; -n+n on a +n channel results in
+       no mode change; -n+n on a -n channel results in a +n mode change;
+       etc.
+
+2000-10-23  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/channel.c: add "add" and "del" elements to ParseState to
+       avoid not-too-pretty -p+s when +s is sufficient; fix a bug in
+       mode_parse_limit that caused it to clear all channel modes
+       prematurely; restructure mode_parse_mode to avoid calling
+       modebuf_mode too early (ties in with first mentioned change);
+       better logic for +p/+s mutual exclusivity; initialize "add" and
+       "del" elements in mode_parse; send simple modes down to
+       modebuf_mode after the loop in mode_parse
+
+2000-09-28  Greg Sikorski <gte@atomicrevs.demon.co.uk>
+       * ircd/m_names.c: Fixed a non-lethal logic error that 
+       triggers an assert() in find_member_link while debugging.
+       (Spotted by Maniac-).
+2000-09-19  Thomas Helvey <helveytw@home.com>
+       * ircd/s_conf.c: move K:lines to their own list and data
+       structures, add supporting code.
+       * ircd/m_stats.c: cleanup stats processing a bit move
+       kline listing code to a new function, haven't figured
+       out where it goes yet tho'
+       * ircd/s_stats.c: added K:line bulk lister
+       * include/s_conf.h: added new DenyConf struct
+       * *[ch]: fixeup code that depended on changes
+
+2000-09-17  Thomas Helvey <helveytw@home.com>
+       * ircd/class.c: encapsulate class list
+       * include/class.h: clean up classes
+       * * fixup code that depended on changes
+
+2000-09-17  Thomas Helvey <helveytw@home.com>
+       * ircd/s_conf.c: add me to local conf
+       * include/s_conf.h: move CONF_ME macro to chkconf.c
+       * ircd/s_bsd.c: cleanup initialization, allow virtual host
+       to be changed by rehash
+
+2000-09-17  Thomas Helvey <helveytw@home.com>
+       * include/class.h: add missing prototype
+       * ircd/class.c: make argument to get_conf_class const
+
+2000-09-17  Thomas Helvey <helveytw@home.com>
+       * ircd/*.c: merged in changes from 2.10.10.pl12, cleanup
+       merge conflicts.
+       * ircd/*.h: merged in changes from 2.10.10.pl12, cleanup
+       merge conflicts
+
+2000-09-16  Thomas Helvey <helveytw@home.com>
+       * ircd/s_conf.c: add code for server struct
+       * ircd/client.c: copy of class.c sort of, new file for client
+       specific operations, will move things here as appropriate,
+       currently only one function is exported from here.
+       * ircd/*.c: general logic cleanups, convert negatives to
+       positives in places.
+
+2000-09-16  Thomas Helvey <helveytw@home.com>
+       * ircd/s_conf.c: add code for new crule data structs, strip quotes
+       * ircd/crule.c: clean up scary casting a bit, type safety stuff
+       * include/s_conf.h: add CRuleConf struct and support, remove
+       unused constants
+       * include/crule.h: type safety cleanups
+       * ircd/*.c: fixup code that depended on stuff I changed
+
+2000-09-15  Thomas Helvey <helveytw@home.com>
+       * ircd/s_conf.c: start adding code for new conf data structs, changed
+       listeners, admin line, motd lines, class lines. Move validate_hostent
+       to resolver. General mayhem.
+       * include/s_conf.h: new data structs and accessors
+       * ircd/res.c: move validate_hostent here, rewrite, use regular
+       expression for validation.
+       * doc/example.conf: update docs for port
+
+2000-09-14  Thomas Helvey <helveytw@home.com>
+       * ircd/s_conf.c (conf_init): rewrite conf file parser, start to break
+       up conf_init into managable chunks.
+       * ircd/listener.c (set_listener_mask): fix logic bug core dump.
+       * include/s_conf.h: add new data struct for local info (unwinding the mess).
+
+2000-09-13  Thomas Helvey <helveytw@home.com>
+       * ircd/list.c: put Clients in free lists, pre-allocate MAXCONNECTIONS
+       local clients.
+       * ircd/list.c: put SLinks in free lists
+       * ircd/channel.c: put Memberships in free lists
+       * ircd/ircd.c: rearrange initializations a bit in main
+       Note: With these changes, ircd NEVER frees Clients, SLinks or
+       Memberships. It will also rarely need to allocate new
+       ones during net bursts and other disruptions. This should
+       cut down on memory fragmentation a bit as well.
+
+2000-08-30  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/m_names.c (do_names): pull-up from do_names fix in
+       u2.10.10.pl11
+
+2000-07-15  Perry Lorier       <Isomer@coders.net>
+       * various: IP only k:'s and G:'s now do bit tests instead of two(!) 
+                 match()'s.  Major Major cpu savings.  Also speed up the
+                 other case slightly.  As a side effect you can now
+                k/Gline *@10.0.0.0/8.  I'll do bans tomorrow, it's nearing
+                3am.
+
+2000-07-15  Perry Lorier       <Isomer@coders.net>
+       * various: Fixed warnings after compiling on an alpha.
+2000-07-09  Perry Lorier       <Isomer@coders.net>
+       * doc/ircd.8: Applied grammitical changes by Liandrin, applied
+                     changes suggested by various other people.
+       * ircd/IPcheck.c: More bug fixes.  Current problem appears to be
+                       that it gets a corrupt entry somehow.
+2000-07-09  Greg Sikorski <gte@atomicrevs.demon.co.uk>
+       * ircd/m_oper.c: Clean up compiler warning.
+
+2000-07-08  Perry Lorier       <Isomer@coders.net>
+       * doc/ircd.8: Updated the documentation, it was slightly out of date
+                     being updated around 1989.
+       * ircd/m_whois.c: Rewrote for clarity, and probably a bit more speed.
+                         fixed a few minor glitches.
+       * doc/rfc1459.unet: Updated.
+       * ircd/IPcheck.c: Fixed more bugs.
+       * ircd/s_bsd.c: We now keep track of servers we've conected.
+
+2000-07-02  Perry Lorier       <Isomer@coders.net>
+       * ircd/s_misc.c: Fixed remote IPcheck bug.  Ok, I'm a moron, so sue
+                       me.  Thanks to Hektik, thanks thanks thanks thanks
+                       thanks thanks thanks thanks thank thanks thank thanks
+
+2000-07-01  Perry Lorier       <Isomer@coders.net>
+       * ircd/s_conf.c: "Fixed" the "bug" where people would "evade" K:'s.
+       * ircd/s_conf.c, include/IPcheck.h: Fixed compile warnings.
+
+2000-06-22  Perry Lorier       <Isomer@coders.net>
+       * ircd/IPcheck.c: Large chunks redone.
+       * ircd/s_conf.c: Changes due to IPcheck - ONE nolonger supported,
+                       single AND double digit limits are allowed now.
+       * misc other: Changes to IPcheck.
+
+2000-06-30  Perry Lorier       <Isomer@coders.net>
+       * ircd/ircd.c: Fix command line parameter bugs.
+
+2000-06-30  Perry Lorier       <Isomer@coders.net>
+       * ircd/m_kill.c: Fixed bug with LOCAL_KILL_ONLY
+       * ircd/m_nick.c: Tidied things up.
+
+2000-06-12 Joseph Bongaarts <foxxe@trms.com>
+       * ircd/m_stats.c: Iso forgot mo_stats when he added /stats v
+       
+2000-05-29  Perry Lorier       <Isomer@coders.net>
+       * ircd/m_stats.c: add /stats v to do only the last part of the /trace
+       * ircd/IPcheck.c: Cosmetic change, if we meddle with it enough do
+                       you think it'll get bored and fix itself?
+
+2000-06-09  Greg Sikorski <gte@atomicrevs.demon.co.uk>
+
+       * ircd/m_names.c: Clean up compiler warnings.
+
+2000-06-09  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/channel.c (mode_parse_client): don't send warning if
+       there's not enough arguments for a +/-o/v; means the habit of
+       doing "/mode #channel +oooooo bob" doesn't result in a bunch of
+       error messages
+
+2000-06-04  Greg Sikorski <gte@atomicrevs.demon.co.uk>
+
+       * ircd/m_names.c: Re-factor code to remove unneccessary
+       GlobalChannelList iteration every time someone joins a channel.
+
+2000-06-02  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/s_user.c: add struct Gline * argument to register_user;
+       look up global glines and repropagate them if necessary; send
+       acknowledgement of gline to remote servers when registering users
+
+       * ircd/s_serv.c (server_estab): don't send acknowledgement of
+       local glines to remote servers; do send gline acknowledgement of
+       bursted users
+
+       * ircd/m_user.c (m_user): pass new struct Gline * argument to
+       register_user
+
+       * ircd/m_pong.c: pass new struct Gline * argument to register_user
+
+       * ircd/m_nick.c (ms_nick): document protocol change
+
+       * ircd/gline.c: support GLINE_LASTMOD
+
+       * include/s_user.h: add struct Gline * argument to register_user
+
+       * include/gline.h: add GLINE_LASTMOD to look up non-zero lastmods
+
+       * ircd/s_conf.c (find_kill): add unsigned int argument to
+       gline_lookup()
+
+       * ircd/gline.c: add GLINE_GLOBAL to lookup or find only global
+       glines; add unsigned int argument to gline_lookup()
+
+       * include/gline.h: add GLINE_GLOBAL flag; add unsigned int
+       argument to gline_lookup()
+
+       * ircd/m_server.c: Resend jupe only when there is no %<lastmod>
+       parameter, or when it falls out of bounds: see comments prior to
+       call to jupe_resend(); call server_estab with struct Jupe
+       parameter, so that we place the appropriate %<lastmod> in the
+       appropriate place.
+
+       * ircd/s_serv.c (server_estab): send %<lastmod> for introduced
+       server, as well as for servers when we're sending the BURST
+
+       * include/s_serv.h: add a struct Jupe * to the arguments for
+       server_estab() so that we can send the appropriate lastmod
+       parameter
+
+       * ircd/m_gline.c (ms_gline): actually, this should be the
+       slightest bit more efficient...
+
+       * ircd/m_jupe.c (ms_jupe): actually, this should be the slightest
+       bit more efficient...
+
+       * ircd/m_gline.c (ms_gline): inhibit GLINE processing resends
+       during netburst
+
+       * ircd/m_jupe.c (ms_jupe): inhibit JUPE processing resends during
+       netburst
+
+       * ircd/channel.c (joinbuf_join): really remove user from local
+       channels
+
+2000-05-29  Perry Lorier       <Isomer@coders.net>
+       * ircd/m_names.c: Removed redundant space. 
+       * ircd/s_bsd.c: Fixed incorrect syntax on ERROR line.
+
+2000-05-18  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/m_burst.c (ms_burst): er...that should have been a ",", not
+       a " "
+
+2000-05-04  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/channel.c: replace bogus assertions with returns, which is
+       logically correct; only wipe out limit/key if they were originally
+       set in the first place; remove user from channel when doing a
+       PARTALL; only send MODE +o for user CREATEing channel if user is
+       not MyUser--CREATE will only be used if the channel did not
+       originally exist, therefore we can assume no one local is on the
+       channel anyway, and we don't exactly need for the user to see an
+       explicit +o for themselves
+
+       * doc/readme.gline: describe the syntax of the GLINE command
+
+       * doc/readme.jupe: update to reflect a couple of changes to JUPE
+
+       * ircd/gline.c: don't propagate local changes
+
+       * ircd/jupe.c: don't propagate local changes
+
+       * ircd/m_gline.c (mo_gline): force local flag when deactivating
+       glines with 0 lastmod
+
+       * ircd/gline.c (gline_deactivate): G-lines with zero lastmod time
+       are now removed instead of being deactivated
+
+       * ircd/m_gline.c (ms_gline): make G-lines of the form "GLINE *
+       -<mask>" be accepted
+
+       * ircd/channel.c (send_channel_modes): deal with one of the last
+       vestiges of sendbuf
+
+       * ircd/m_burst.c (ms_burst): debugged ban processing; removed
+       debugging hooks
+
+       * ircd/channel.c (modebuf_extract): remove debugging
+       sendto_opmask_butone calls
+
+2000-05-03  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/channel.c: support a couple of new flags to support using
+       mode_parse; fix some bugs with 0 struct ModeBuf *; implementation
+       of modebuf_extract to extract added flags for use by ms_burst
+
+       * include/channel.h: a couple of new flags to support using
+       mode_parse inside ms_burst
+
+       * ircd/m_burst.c (ms_burst): brand new implementation of BURST
+
+       * ircd/m_endburst.c: add loop to processing of end_of_burst to
+       free empty channels after the BURST is over.
+
+       * ircd/m_server.c: convert to use new send.c functions--I wanted
+       to rewrite it from scratch, but the logic's pretty complex; I may
+       still rewrite it, though...
+
+2000-05-02  Thomas Helvey <tomh@inxpress.net>
+
+       * ircd/ircd.c: fix broken header include ordering
+
+2000-05-02  Thomas Helvey <tomh@inxpress.net>
+       
+       * ircd/IPcheck.c: cleanups for ZenShadow's cleanups
+        review emailed privately
+
+       * include/IPcheck.h: removed unneeded include
+
+2000-05-02  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/s_user.c (hunt_server): throw in a comment so I know what
+       the sendto_one is for
+
+       * include/querycmds.h (Count_unknownbecomesclient): convert to
+       sendto_opmask_butone
+
+       * ircd/send.c: start removing dead code
+
+       * include/send.h: start removing dead code
+
+       * ircd/m_rping.c: convert to sendcmdto_one / send_reply /
+       hunt_server_cmd
+
+       * ircd/m_rpong.c: convert to sendcmdto_one / send_reply
+
+2000-05-01  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/m_stats.c: convert to sendcmdto_one / send_reply
+
+       * ircd/m_kick.c: Completely reimplement m_kick
+
+       * ircd/channel.c: send_user_joins removed; it was dead code,
+       anyway...
+
+2000-05-01  Perry Lorier <isomer@coders.net>
+       * ircd/m_invite.c: Fix for the rest of m_invite.c, and again.
+       * ircd/channels.c: My fix for the part problem.  Untested, probably
+               won't work.  Can't be much worse than the current problem.
+               it'll either work or core, take your pick.
+
+
+2000-04-30  Perry Lorier <isomer@coders.net>
+       * config/config-sh.in: Fix for CONNEXIT
+       * ircd/s_{user,misc}.c: Fix for CONNEXIT
+       * ircd/m_invite.c: Fix for incorrectly numnickified invite.
+                       (Kev: Want to come talk to me about this?)
+
+2000-04-30  Steven M. Doyle <steven@doyle.net>
+       * ircd/ircd.c
+         - general cleanups and readability enhancements
+         - rewrite of setuid/chroot code.
+         - server will no longer run as root
+         - -DPROFIL compile option removed
+         - Fixed IPcheck API calls
+       * config/config-sh.in
+         - Fixed up chroot compile options
+         - Added options for debug and profile compiles
+       * config/gen.ircd.Makefile
+         - Support for new debug/profile options
+       * ircd/Makefile.in
+         - Support for new debug/profile options
+       * ircd/ircd_signal.c
+         - Removed -DPROFIL
+
+       * include/IPcheck.h
+         - Removed old API prototypes, added new ones
+       
+       * ircd/IPcheck.c
+         - Readability cleanups (well, I -think-...)
+         - Changed IPRegistryEntry.last_connect to a time_t.  The previously
+           used unsigned short was probably causing interesting things after
+           a client had been connected longer than about 65,535 seconds...
+         - Removed old API functions.
+
+       * ircd/whocmds.c
+         - Removed IPcheck.h include
+       
+       * Additionally modified IPcheck API calls in:
+         - ircd/m_nick.c
+         - ircd/m_auth.c
+         - ircd/s_bsd.c
+         - ircd/s_conf.c
+         - ircd/s_misc.c
+         - ircd/s_serv.c
+         - ircd/s_user.c
+       
+       
+2000-04-30  Perry Lorier <isomer@coders.net>
+       * ircd/s_bsd.c: Sigh. :)
+        * ircd/m_mode.c: fix for modeless channels by poptix.
+
+2000-04-29  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/m_join.c: reimplement JOIN in terms of struct JoinBuf
+
+       * ircd/channel.c (clean_channelname): make clean_channelname also
+       truncate long channel names
+
+2000-04-28  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/m_create.c: reimplement CREATE in terms of struct JoinBuf
+
+       * ircd/channel.c: implemented joinbuf_init, joinbuf_join,
+       joinbuf_flush
+
+       * include/channel.h: definitions and declarations for the struct
+       JoinBuf abstraction
+
+2000-04-29  Perry Lorier <isomer@coders.net>
+       * ircd/s_bsd.c: Ok, so I thought I compiled and tested this...
+
+2000-04-29  Perry Lorier <isomer@coders.net>
+       * ircd/s_bsd.c: Add debugging code to IPcheck
+
+2000-04-28  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * include/ircd_reply.h (SND_EXPLICIT): use instead of RPL_EXPLICIT
+
+       * ircd/ircd_reply.c (send_reply): use SND_EXPLICIT instead of
+       RPL_EXPLICIT
+
+       * ircd/m_userhost.c (m_userhost): add a dead code comment
+
+       * ircd/m_desynch.c: forgot one...
+
+       * ircd/m_rehash.c (mo_rehash): er, duplicates :)
+
+       * ircd/m_proto.c (proto_send_supported): just change a comment so
+       it doesn't show up in my scans
+
+       * ircd/ircd_reply.c (send_reply): fix a slight bug...
+
+       * ircd/s_numeric.c (do_numeric): use new sendcmdto_* functions,
+       kinda hackish...
+
+       * ircd/parse.c (parse_server): argument wrangling to make
+       processing in do_numeric a little easier to deal with
+
+       * ircd/s_serv.c (server_estab): SERVER should come from
+       acptr->serv->up, not &me
+
+       * ircd/m_lusers.c: accidentally left out sptr for a %C
+
+       * ircd/send.c: hack to support doing wallchops...
+
+       * ircd/m_whowas.c: convert to new send functions
+
+       * ircd/m_whois.c: convert to new send functions
+
+       * ircd/m_who.c: convert to new send functions
+
+       * ircd/m_wallops.c: convert to new send functions
+
+       * ircd/m_wallchops.c: convert to new send functions
+
+       * ircd/m_version.c: convert to new send functions
+
+       * ircd/m_userip.c: convert to new send functions
+
+       * ircd/m_userhost.c: convert to new send functions
+
+       * ircd/m_uping.c: convert to new send functions
+
+       * ircd/m_trace.c: convert to new send functions
+
+       * ircd/m_topic.c: convert to new send functions
+
+       * ircd/m_time.c: convert to new send functions
+
+       * ircd/m_squit.c: convert to new send functions
+
+       * ircd/m_silence.c: convert to new send functions
+
+       * ircd/m_settime.c: convert to new send functions
+
+       * ircd/m_restart.c: convert to new send functions
+
+       * ircd/m_rehash.c: convert to new send functions
+
+       * ircd/m_privmsg.c: convert to new send functions
+
+       * ircd/m_pong.c: convert to new send functions
+
+       * ircd/m_ping.c: convert to new send functions
+
+       * ircd/m_pass.c: convert to new send functions
+
+       * ircd/m_opmode.c: convert to new send functions
+
+       * ircd/m_oper.c: convert to new send functions
+
+       * ircd/m_notice.c: convert to new send functions
+
+       * ircd/m_nick.c: convert to new send functions
+
+       * ircd/m_names.c: convert to new send functions
+
+       * ircd/m_motd.c: convert to new send functions
+
+       * ircd/m_mode.c: convert to new send functions
+
+       * ircd/m_map.c: convert to new send functions
+
+       * ircd/m_lusers.c: convert to new send functions
+
+       * ircd/m_list.c: convert to new send functions
+
+       * ircd/m_links.c: convert to new send functions
+
+       * ircd/m_kill.c: convert to new send functions
+
+       * ircd/m_jupe.c: convert to new send functions
+
+       * ircd/m_invite.c: convert to new send functions
+
+       * ircd/m_info.c: convert to new send functions
+
+       * ircd/m_help.c: convert to new send functions
+
+       * ircd/m_gline.c: convert to new send functions
+
+       * ircd/m_error.c: convert to new send functions
+
+       * ircd/m_endburst.c: convert to new send functions
+
+       * ircd/m_die.c: convert to new send functions
+
+       * ircd/m_destruct.c: convert to new send functions
+
+       * ircd/m_defaults.c: convert to new send functions
+
+       * ircd/m_connect.c: convert to new send functions
+
+2000-04-28  Perry Lorier <isomer@coders.net>
+       * RELEASE.NOTES: Describe a few more undocumented features.
+       * config/config-sh.in: change the default paths for logging
+       and the recommended number of channels.
+       * include/supported.h: Rearrange slightly, added CHANTYPE's
+
+2000-04-27  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/m_close.c: convert to send_reply
+
+       * ircd/m_clearmode.c: convert to send_reply, sendcmdto_serv_butone
+
+       * ircd/m_away.c: convert to send_reply and sendcmdto_serv_butone
+
+       * ircd/m_admin.c: convert to send_reply and hunt_server_cmd
+
+       * ircd/s_user.c (hunt_server_cmd): new hunt_server replacement
+       that takes cmd and tok arguments, etc.  NOTE: THIS IMPLEMENTATION
+       HAS A MAJOR HACK!!!  The whole hunt_server architecture should be
+       carefully rethought...
+
+       * ircd/s_stats.c (hunt_stats): use new hunt_server_cmd
+
+       * include/s_user.h: hunt_server_cmd -- replacement for hunt_server
+
+       * ircd/s_misc.c: *sigh* 2.10.10 doesn't support squitting by
+       numeric nick; therefore, we have to use the server name
+
+       * ircd/m_squit.c (ms_squit): allow to squit by server numeric nick
+
+       * ircd/send.c: fix minor bugs
+
+       * ircd/s_user.c (check_target_limit): mark dead code so I filter
+       it when I grep
+
+       * ircd/s_serv.c (exit_new_server): mark dead code so I filter it
+       when I grep
+
+       * ircd/parse.c: mark dead code so I filter it when I grep
+
+       * ircd/map.c: mark dead code so I filter it when I grep
+
+       * ircd/ircd.c: mark dead code so I filter it when I grep
+
+       * ircd/ircd_relay.c: convert over to new sendcmdto_*, send_reply
+       functions
+
+       * ircd/channel.c: mark dead code so I filter it when I grep
+
+       * ircd/s_stats.c: use send_reply instead of sendto_one w/rpl_str;
+       hope I'm not stepping on toes...
+
+       * ircd/s_conf.c: more sendto_opmask_butone / send_reply
+       conversions; use ircd_snprintf in a couple of cases to negate the
+       possibility of buffer overflow
+
+2000-04-26  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/channel.c: convert as much as possible to new send
+       semantics
+
+       * ircd/send.c (sendcmdto_common_channels): fix a subtle bug --
+       test member->user->from->fd, not from->fd
+
+       * ircd/gline.c (gline_add): go ahead and add badchans; we just
+       won't look for them in m_gline; this way, they always work...
+
+       * ircd/jupe.c: use ircd_vsnprintf conversion specifiers
+
+       * ircd/gline.c: since write_log now uses ircd_vsnprintf, use
+       ircd_vsnprintf conversion specifiers
+
+       * ircd/support.c (write_log): use ircd_vsnprintf for write_log, so
+       I have my conversion specifiers
+
+       * ircd/gline.c (do_gline): use send_reply for ERR_YOUREBANNEDCREEP
+
+       * ircd/send.c (sendcmdto_flag_butone): explicitly send WALLOPS to
+       local users
+
+       * ircd/s_serv.c (exit_new_server): rewrite exit_new_server to be a
+       little less brain-dead
+
+       * ircd/s_misc.c: use sendcmdto_one, sendrawto_one, and send_reply
+
+       * ircd/s_debug.c: use send_reply with RPL_EXPLICIT for
+       RPL_STATSDEBUG
+
+       * ircd/res.c (cres_mem): use send_reply with RPL_EXPLICIT for
+       RPL_STATSDEBUG
+
+       * ircd/list.c (send_listinfo): use send_reply with RPL_EXPLICIT
+       for RPL_STATSDEBUG
+
+       * ircd/m_pong.c: use RPL_EXPLICIT for ERR_BADPING
+
+       * ircd/ircd.c: use RPL_EXPLICIT for ERR_BADPING
+
+       * ircd/s_user.c (register_user): use RPL_EXPLICIT for
+       ERR_INVALIDUSERNAME
+
+       * ircd/ircd_reply.c (send_reply): support RPL_EXPLICIT
+
+       * include/ircd_reply.h (RPL_EXPLICIT): somewhat of a hack to mark
+       a numeric as needing to use an explicit pattern, which will be the
+       first argument in the variable argument list
+
+       * ircd/s_user.c: use sendrawto_one instead of sendto_one to send
+       non-prefixed nospoof PING
+
+       * ircd/s_bsd.c: use sendrawto_one instead of sendto_one to send
+       non-prefixed SERVER login
+
+       * ircd/ircd.c (check_pings): fix last sendto_one calls (except for
+       a numeric usage further up)
+
+       * include/send.h: declare sendrawto_one
+
+       * ircd/send.c (sendrawto_one): new function to use ONLY for
+       non-prefixed commands, like PING to client, or PASS/SERVER on
+       server registration
+
+2000-04-25  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/ircd_snprintf.c (doprintf): implement %H for possible
+       future expansion (channel numerics?)
+
+       * include/ircd_snprintf.h: added documentation to # to explain use
+       with %C; added documentation for : to explain use with %C; added
+       documentation for %H for channels
+
+       * ircd/whocmds.c: use send_reply
+
+       * ircd/userload.c: use sendcmdto_one
+
+       * ircd/uping.c: use sendcmdto_one
+
+       * ircd/send.c: use new flags to %C format string; ':' prefixes
+       client name with a colon for local connects, '#' uses
+       nick!user@host form for local connects
+
+       * ircd/s_user.c: use send_reply, sendto_opmask_butone,
+       sendcmdto_one, sendcmdto_serv_butone, sendcmdto_flag_butone
+
+       * ircd/s_serv.c: use sendcmdto_one, sendto_opmask_butone
+
+       * ircd/s_bsd.c: use sendto_opmask_butone, send_reply,
+       sendcmdto_one
+
+       * ircd/s_auth.c: use sendto_opmask_butone
+
+       * ircd/res.c: use sendcmdto_one
+
+       * ircd/ircd_snprintf.c (doprintf): minor bug fixes and some
+       debugging assertions
+
+2000-04-24  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/support.c: dumpcore is no longer used, so get rid of it
+
+       * ircd/parse.c: use send_reply, sendcmdto_one
+
+       * ircd/map.c: use send_reply
+
+       * ircd/listener.c: use send_reply
+
+       * ircd/jupe.c: use sendto_opmask_butone, send_reply
+
+       * ircd/ircd_reply.c: use send_reply
+
+       * ircd/ircd.c: use sendto_opmask_butone
+
+       * ircd/gline.c: use sendto_opmask_butone, send_reply
+
+       * ircd/ircd_snprintf.c (doprintf): make it deal with incompletely
+       registered clients; make FLAG_ALT print nick!user@host; make
+       FLAG_COLON print :blah
+
+       * ircd/class.c (report_classes): use send_reply instead of
+       sendto_one
+
+       * ircd/hash.c (m_hash): replace sendto_one with sendcmdto_one
+
+       * ircd/IPcheck.c (ip_registry_connect_succeeded): replace
+       sendto_one with sendcmdto_one
+
+2000-04-21  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/send.c: clean up logic in sendcmdto_channel_butone; use
+       MyConnect() instead of IsServer() in sendcmdto_flag_butone; define
+       sendcmdto_match_butone
+
+       * include/send.h: declare sendcmdto_match_butone
+
+2000-04-20  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/jupe.c: update to use send_reply()
+
+       * ircd/gline.c: update to use send_reply()
+
+       * include/ircd_reply.h: declare send_reply
+
+       * ircd/ircd_reply.c (send_reply): send_error_to_client, but for
+       replies; uses ircd_snprintf
+
+       * ircd/send.c: added comments to redirect searchers to appropriate
+       sendcmdto_* function; moved new functions to end of file; added
+       explanatory comments; reordered arguments; defined new functions
+       mentioned below
+
+       * ircd/m_jupe.c: reorder arguments to sendcmdto_* functions
+
+       * ircd/m_gline.c: reorder arguments to sendcmdto_* functions
+
+       * ircd/jupe.c: reorder arguments to sendcmdto_* functions
+
+       * ircd/gline.c: reorder arguments to sendcmdto_* functions
+
+       * include/send.h: reorder arguments, add explanatory comments,
+       declare new functions sendcmdto_flag_butone, sendto_opmask_butone,
+       and vsendto_opmask_butone
+
+2000-04-19  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/send.c: define sendcmdto_channel_butone, wrote a simplified
+       vsendto_op_mask that uses '*' instead of the receiving client
+       nickname
+
+       * include/send.h: declare sendcmdto_channel_butone; takes a skip
+       argument that allows you to skip (or not to skip) deaf users,
+       users behind bursting servers, and non channel operators
+
+2000-04-17  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/send.c: new sendcmdto_channel_butserv -- note that old
+       sendto_channel_butserv has a subtle bug; also wrote
+       sendcmdto_common_channels.
+
+       * include/send.h: declare new sendcmdto_* functions
+
+       * ircd/jupe.c: support local deactivations of jupes
+
+       * ircd/gline.c: support local deactivations of glines
+
+       * include/jupe.h: JUPE_LDEACT allows jupes to be locally
+       deactivated; if they aren't locally deactivated, then it slaves to
+       the net-wide activation status; JupeIsRemActive() tests only
+       whether the jupe is active everywhere else
+
+       * include/gline.h: GLINE_LDEACT allows glines to be locally
+       deactivated; if they aren't locally deactivated, then it slaves to
+       the net-wide activation status; GlineIsRemActive() tests only
+       whether the gline is active everywhere else
+
+       * ircd/gline.c: detect overlapping G-lines; if an existing, wider
+       gline expires after the new one will, we drop the new one,
+       otherwise we add the G-line after that one (so the wide one will
+       apply first); if the new one contains an existing G-line and if it
+       will expire after the existing one, we drop the existing one to
+       save memory
+
+       * ircd/m_gline.c (mo_gline): opers could issue remote local
+       glines when CONFIG_OPERCMDS was off; fixed
+
+2000-04-16  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/m_jupe.c (mo_jupe): allow target argument to be dropped if
+       this is a local JUPE
+
+       * ircd/gline.c: add flags argument to gline_activate and
+       gline_deactivate for future expansion
+
+       * ircd/m_gline.c: pass flags to gline_activate and
+       gline_deactivate
+
+       * include/gline.h: add flags argument to gline_activate and
+       gline_deactivate
+
+       * ircd/jupe.c: add flags argument to jupe_activate and
+       jupe_deactivate for future expansion
+
+       * include/jupe.h: add flags argument to jupe_activate and
+       jupe_deactivate
+
+       * ircd/m_jupe.c: pass a flags argument to jupe_add instead of
+       local, active; pass flags to jupe_activate and jupe_deactivate
+
+       * include/gline.h: remove dead code
+
+       * ircd/gline.c: make gline expire times relative to CurrentTime,
+       since that should be monotonically increasing, instead of
+       TStime(), which can be set backwards, and which can therefore
+       cause an expire time to increase; make local glines be removed
+       instead of just deactivated; don't let gline_find() look for
+       user@host glines if the mask being looked up is a channel mask
+
+       * ircd/send.c (vsendcmdto_one): forgot to account for the case
+       where origin is a server and destination is a user
+
+       * ircd/jupe.c: make jupe expire times relative to CurrentTime,
+       since that should be monotonically increasing, instead of
+       TStime(), which can be set backwards, and which can therefore
+       cause an expire time to increase; make local jupes be removed
+       instead of just deactivated
+
+       * ircd/ircd_snprintf.c: d'oh, thanks for catching that; short for
+       limit is fine.  any other warnings I should know about?
+
+2000-04-15  Thomas Helvey <tomh@inxpress.net>
+
+       * ircd/*.c: const correctness and type safety cleanups to
+       get code to compile with C++ compiler. Still has
+       signed/unsigned comparison warnings.
+
+2000-04-15  Greg Sikorski <gte@atomicrevs.demon.co.uk>
+
+       * ircd/userload.c: change <sys/time.h> include to <time.h> for
+         portability.
+
+2000-04-14  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/m_gline.c (mo_gline): d'oh, target isn't a numeric; use %C
+       and convert acptr...
+
+       * ircd/s_user.c: move gline_lookup function call into
+       register_user, where it'll have a username to lookup!
+
+       * ircd/m_gline.c: modify to utilize new sendcmdto_* series of
+       functions; also stuff send_error_to_client into return clauses
+
+       * ircd/m_jupe.c: modify to utilize new sendcmdto_* series of
+       functions; also use send_error_to_client where that makes sense
+
+       * ircd/jupe.c: modify to utilize new sendcmdto_* series of
+       functions; also use send_error_to_client where that makes sense
+
+       * ircd/gline.c: modify to utilize new sendcmdto_* series of
+       functions; also fix gline_lookup() to deal properly with remote
+       clients--boy, do struct Client and struct User need to be cleaned
+       up!
+
+       * ircd/ircd_snprintf.c (doprintf): a dest of &me is a server,
+       too...
+
+       * ircd/send.c: wrote sendcmdto_one(), vsendcmdto_one(), and
+       sendcmdto_serv_butone(), all utilizing the %v conversion of
+       ircd_snprintf()
+
+       * include/send.h: define IRC_BUFSIZE, max size of a message;
+       declare sendcmdto_one(), vsendcmdto_one(), and
+       sendcmdto_serv_butone()
+
+       * include/msg.h: define all the CMD_* constants needed to utilize
+       the new sendcmdto_* series of functions
+
+       * ircd/Makefile.in (SRC): list ircd_snprintf.c; run make depend
+
+       * ircd/gline.c: remove old, dead code.
+
+       * ircd/m_gline.c (mo_gline): disallow setting of global G-lines
+       unless CONFIG_OPERCMDS is enabled; disallow listing of all G-lines
+       (don't advertise proxies); remove dead code
+
+       * ircd/parse.c: oper handler for JUPE only lists jupes unless
+       CONFIG_OPERCMDS is enabled
+
+       * ircd/m_jupe.c (mo_jupe): don't compile mo_jupe() if
+       CONFIG_OPERCMDS is not enabled; we'll disable it in parse.c
+
+       * ircd/m_opmode.c (mo_opmode): if CONFIG_OPERCMDS is not enabled,
+       always return ERR_DISABLED
+
+       * ircd/m_clearmode.c (mo_clearmode): if CONFIG_OPERCMDS is not
+       enabled, always return ERR_DISABLED
+
+       * ircd/s_err.c: add error message to indicate disabled commands
+
+       * include/numeric.h (ERR_DISABLED): to indicate disabled commands
+
+       * doc/Configure.help: add documentation for CONFIG_OPERCMDS
+
+       * config/config-sh.in: add CONFIG_OPERCMDS, default both it and
+       CONFIG_NEW_MODE to 'y' for now
+
+       * ircd/gline.c (gline_list): fix a minor formatting bogon
+
+       * BUGS: since I fixed that bug, might as well mark it fixed.
+
+       * ircd/m_join.c: look up badchans with GLINE_EXACT
+
+       * ircd/m_gline.c: fix parc count problems; look up existing
+       G-lines with GLINE_EXACT; only set new lastmod when
+       activating/deactivating existing glines if old lastmod was not 0
+
+       * ircd/gline.c: forgot to copy the gline reason over; don't
+       propagate a gline with 0 lastmod if origin is user; add
+       GLINE_EXACT to force exact matching of gline mask
+
+       * ircd/ircd_snprintf.c (doprintf): forgot to deal with the zero
+       flag properly
+
+       * ircd/s_conf.c (find_kill): gline_find() takes a char *userhost,
+       but gline_lookup() actually takes a client--d'oh.
+
+2000-04-13  Thomas Helvey <tomh@inxpress.net>
+       * ircd/IPcheck.c: Back port BLMet's bugfix from 2.10.10
+
+2000-04-13  Greg Sikorski <gte@atomicrevs.demon.co.uk>
+
+       * ircd/whocmds.c: Don't make idle flag default in /who, to prevent:
+         "/who * x"
+         "Gte3 H*iwg Gte@212.49.240.217 :1 :0 I am the one that was."
+         (Found by Plexus).
+
+       * ircd/whocmds.c: Change idle time calc from socket idle to user
+         idle.
+
+2000-04-13  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * config/aclocal.m4 (unet_CHECK_TYPE_SIZES): check size of void *,
+       too, for ircd_snprintf.c
+
+       * include/ircd_snprintf.h: documentation for ircd_(v)snprintf, in
+       comments; mostly descended from the Linux manpage for printf, but
+       also documenting the extensions.
+
+       * ircd/ircd_snprintf.c: NULL dest is equivalent to going to a
+       client; make 'q' be the same as 'L'; remove __inline__; only
+       define EXTENSION if HAVE_LONG_LONG is defined
+
+       * include/handlers.h: declare m_gline()
+
+       * ircd/parse.c: gline can be called by users, but it only lists
+       the glines.
+
+       * ircd/s_user.c (set_nick_name): resend gline if a remote server
+       introduces a glined client
+
+       * ircd/s_serv.c (server_estab): burst glines, too
+
+       * ircd/gline.c: fix up all the expire times to be offsets;
+       simplify gline_resend()
+
+       * ircd/m_gline.c: begin coding replacements for ms_gline(),
+       mo_gline(), and m_gline()
+
+       * ircd/gline.c (gline_add): allow *@#channel to work correctly;
+       also, prohibit local BADCHANs if LOCAL_BADCHAN not defined
+
+2000-04-13  Greg Sikorski <gte@atomicrevs.demon.co.uk>
+
+       * tools/Bouncer/*: Add comments/documentation/tags.
+       * tools/Bouncer/*: Add debug defines, make task fork().
+
+2000-04-12  Thomas Helvey <tomh@inxpress.net>
+       * ircd/s_err.c: Cleanup s_err.c make one table so we
+       don't have to do anything tricky to get an error string.
+
+2000-04-12  Greg Sikorski <gte@atomicrevs.demon.co.uk>
+       * Add port bouncer for http (x/w)
+
+2000-04-12  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/s_conf.c (find_kill): replaced call to find_gline() with a
+       call to gline_find(); also used GlineReason() instead of direct
+       reference to structure member
+
+       * ircd/m_join.c (m_join): replace bad_channel() calls with calls
+       to gline_find(name, GLINE_BADCHAN), and also check to see if gline
+       is active
+
+       * ircd/channel.c: nothing seems to be called anywhere...
+
+       * ircd/s_err.c: update a couple of replies to dovetail with new
+       semantics
+
+       * ircd/gline.c: begin complete re-implementation of gline.c along
+       the lines of the final design of jupe.c
+
+       * include/gline.h: begin complete re-implementation of gline.c
+       along the lines of the final design of jupe.c
+
+       * ircd/channel.c (mode_process_clients): fix "Deop of +k user on
+       %s by %s" message...
+
+       * ircd/ircd_snprintf.c: my new snprintf()-like functions
+
+       * include/ircd_snprintf.h: my new snprintf()-like functions
+
+2000-04-11  Thomas Helvey <tomh@inxpress.net>
+       * ircd/IPcheck.c: removed old dead code
+       * ircd/s_user.c (send_user_info): removed non-standard
+          user not found message for userhost/userip
+
+2000-04-11  Greg Sikorski <gte@atomicrevs.demon.co.uk>
+
+       * ircd/s_err.c: Added missing quotes to ERR_DONTCHEAT numeric.
+       * doc/p10.html: Work on chapter 4.
+
+2000-04-10  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/channel.c (mode_parse_client): fix coredump on /mode
+       #foobar +o nosuchnick
+
+2000-04-10  Perry Lorier  <Isomer@coders.net>
+       * BUGS: Added bug.
+
+2000-04-09  Thomas Helvey <tomh@inxpress.net>
+       * include/IPcheck.h: fix prototype
+       * ircd/s_user.c: fix usage of IPcheck_remote_connect
+       * ircd/IPcheck.c: removed unused args
+
+2000-04-09  Thomas Helvey <tomh@inxpress.net>
+       * include/IPcheck.h: add proto for IPcheck_expire
+
+       * ircd/IPcheck.c: Rewrote
+
+       * ircd/ircd.c: Add IPcheck_expire to main message loop
+
+       * ircd/s_user.c: Redo target hashing, refactor target code
+
+       * include/numeric.h: Cleaned up numerics, added which ones are
+       in use by other networks and what they are in use for.
+
+       * ircd/channel.c: cleaned can_join(), allow anyone through anything
+       if /invited, simplified the function.  Opers overusing OPEROVERRIDE
+       will get a message explaining to them not to cheat.
+
+       * ircd/m_join.c: cleaned up the various join functions, should be
+       a lot more efficient.  Still needs work.  Now assumes that s<->s
+       won't send it a JOIN 0.  Service coders - note this and tread with
+       care.
+
+       * ircd/m_stats.c: added Gte-'s stats doc patch.
+
+       * ircd/m_version.c: /version now returns the 005 numeric as well.
+       as requested by Liandrin.
+
+
+2000-04-07  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/m_clearmode.c: add include for support.h for write_log()
+
+       * configure: move ircd/crypt/* to tools/*
+
+2000-04-06  Thomas Helvey <tomh@inxpress.net>
+       * ircd/s_auth.c: Shorten auth connect timeout to 60 seconds
+          set client host to server alias if connection from localhost
+
+2000-04-06  Perry Lorier <isomer@coders.net>
+       * ircd/ircd.c: Fix core during pinging (oops)
+       
+2000-04-06  Perry Lorier <isomer@coders.net>
+       * ircd/send.c: fixed wrong ident being sent to channels bug.
+       * include/numerics.h: Updated some of the numerics from other
+       networks.  Flagged some as 'unused' by undernet.
+
+2000-03-30  Perry Lorier <isomer@coders.net>
+       * ircd/ircd.c: Lets see if this helps the ping problem at all.
+       * ircd/whocmds.c, /doc/readme.who: Added %l specifier to get idle
+       time for local clients. (as requested), extended who now returns all
+       the flags (@+!) so you can tell the complete state of a client.
+
+2000-03-30  Thomas Helvey <tomh@inxpress.net>
+       * m_rping.c m_rpong.c: add Gte's rping/rpong fixes
+
+2000-03-30  Perry Lorier <isomer@coders.net>
+       * ircd/parse.c: oops, missed opers.
+
+2000-03-30  Perry Lorier <isomer@coders.net>
+       * ircd/parse.c: fixed mystifying ping bug thats been plaguing us
+       for so long.  Remember: m_ping MUST be in the parse array. :)
+
+2000-03-30  Perry Lorier <isomer@coders.net>
+       * ircd/ircd.c: test in check_pings was wrong.  I move that we
+       disallow cvs commit after 10pm localtime....
+
+2000-03-30  Perry Lorier <isomer@coders.net>
+       * ircd/m_pong.c: Fix it for servers too.
+
+2000-03-30  Perry Lorier <isomer@coders.net>
+       * ircd/m_pong.c: Fix ping timeout bugs
+
+2000-03-30  Perry Lorier <isomer@coders.net>
+       * ircd/channel.c: Bans had CurrentTime in their when field instead
+       of TStime()
+
+2000-03-31  Thomas Helvey <tomh@ixpress.net>
+       * ircd/numnicks.c (SetXYYCapacity): fix for extended
+       numerics.
+
+2000-03-30  Perry Lorier <isomer@coders.net>
+       * ircd/m_nick.c: send kills both ways so when we add nick change
+       on collision we don't desync the network.
+
+       * ircd/map.c: Fixup the map a bit more.
+
+2000-03-31  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/m_clearmode.c (do_clearmode): Log the CLEARMODE to OPATH
+
+       * ircd/m_opmode.c: Log the mode changes to OPATH
+
+       * ircd/channel.c (modebuf_flush_int): Log the mode changes to
+       OPATH
+
+       * include/channel.h (MODEBUF_DEST_LOG): Log the mode changes to
+       OPATH
+
+       * doc/Configure.help: help text for CONFIG_LOG_OPMODE / OPATH
+
+       * config/config-sh.in: added OPATH for opmode log file
+
+       * ircd/m_clearmode.c (do_clearmode): updated uses of
+       modebuf_mode_string() for the new usage
+
+       * ircd/channel.c: added flag MODE_FREE and an int argument to
+       modebuf_mode_string() to indicate that the string must be free'd;
+       updated calls to modebuf_mode_string() for the new usage; called
+       collapse(pretty_mask()) on the ban string and use allocated memory
+       for it; added ban list length accounting; fixed a number of small
+       bugs in ban processing
+
+       * include/channel.h: added flag MODE_FREE and an int argument to
+       modebuf_mode_string() to indicate that the string must be free'd
+
+       * ircd/m_clearmode.c (do_clearmode): made sure clearmode removed
+       keys and limits that are set
+
+2000-03-30  Perry Lorier <isomer@coders.net>
+       * ircd/ircd.c: rewrote check_pings() for maintainability
+       and speed.  Also changed quit msg's so they don't have
+       redundant nick[host] info in them.
+
+       * ircd/send.c: Changed write errors to report what error
+       occured (if possible).
+
+       * ircd/gline.c: added gline comment to the quit.
+
+       * ircd/m_server.c: Added suggestions to server quits mentioning
+       what went wrong so the admin can fix it earlier instead of asking
+       questions...
+
+       * ircd/map.c: Changed m_map() to hide numerics, show a * beside
+       servers that aren't fully burst yet.  And show '(--s)' for servers
+       where its not sure.
+
+       * doc/example.conf: Fixed wrapped U:
+
+2000-03-30  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/m_mode.c (ms_mode): implemented a new m_mode in terms of
+       mode_parse() (version selectable at compile time)
+
+       * ircd/m_clearmode.c (mo_clearmode): clean_channelname(parv[1])
+
+       * ircd/m_opmode.c (mo_opmode): clean_channelname(parv[1])
+
+       * config/config-sh.in: add new config option to enable new m_mode
+       implementation
+
+       * doc/Configure.help: add documentation for new config option
+       CONFIG_NEW_MODE
+
+       * ircd/channel.c (mode_parse_client): /opmode #foobar -o -- 461
+       MODE -v : Not enough parameters
+
+       * ircd/m_clearmode.c (do_clearmode): do_clearmode() would remove
+       +k and +l even if they weren't set...
+
+       * ircd/m_opmode.c: implement the OPMODE command using mode_parse()
+
+       * ircd/channel.c: make mode_process_clients() clear the DEOPPED
+       flag; fix +s+p exclusivity; add MODE_ADD/MODE_DEL to flag list
+       for; test the 0-th member, not the i-th member, of the client
+       change state stuff
+
+       * ircd/m_clearmode.c (do_clearmode): use the new
+       mode_invite_clear() function
+
+       * ircd/channel.c: cleared up all the compile-time warnings and
+       errors
+
+       * include/channel.h: added declarations for mode_ban_invalidate()
+       and mode_invite_clear()
+
+       * ircd/channel.c: finished mode_parse(), then broke it up into a
+       dozen or so helper functions to make the code easier to read
+
+2000-03-29  Thomas Helvey <tomh@inxpress.net>
+       * ircd/ircd.c: refactor server initialization a bit, use
+       getopt for parsing command line, refactor init_sys, main,
+       and other bits.
+
+       * ircd/s_bsd.c: add functions for initialization to clean
+       up logic a bit and remove duplicated code.
+
+       * include/ircd.h: add struct for server process related
+       variables.
+
+2000-03-29  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/channel.c: initial definition of mode_parse(); flags to
+       prevent doing the same thing multiple times; helper method
+       send_notoper() to send a "Not oper"/"Not on channel" notice
+
+       * include/channel.h: declare mode_parse() and helper flags
+
+       * ircd/channel.c (modebuf_flush_int): fiddled with timestamp
+       sending to match the current action of set_mode() closely enough
+       that hopefully there won't be major conflicts
+
+       * ircd/channel.c (modebuf_flush_int): consolidated the mode string
+       building logic, reversed the order of the arguments to mode
+       commands to have '-' preceed '+'
+
+2000-03-29  Thomas Helvey <tomh@inxpress.net>
+       * ircd/s_bsd.c (add_connection): don't disable socket options
+       let OS tune itself and allow important performance tweaks to 
+       work.
+
+2000-03-28  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/channel.c (modebuf_flush_int): use %d, not %-15d; I got
+       confused by set_mode, which is doing some really weird logic;
+       guess what I'm going to rewrite next?  ;)
+
+2000-03-28  Kevin L. Mitchell  <klmitch@emc.com>
+
+       * include/channel.h: added MODE_SAVE for the bounds checking stuff
+       in modebuf_flush
+
+       * ircd/channel.c: make modebuf_flush into modebuf_flush_int and
+       make it do bounds checking on the buffer; all modes are sent only
+       if the all parameter is 1; modebuf_flush is the exported wrapper
+
+       * include/channel.h: add BOUNCE, renumber flags to get a little
+       more space
+
+       * ircd/channel.c (modebuf_flush): don't overload HACK2, add
+       BOUNCE; send DESYNCH message
+
+2000-03-27  Kevin L. Mitchell  <klmitch@emc.com>
+
+       * ircd/m_clearmode.c (do_clearmode): only mark the modes the
+       channel actually has in effect for deletion
+
+       * ircd/channel.c: added explanatory comments to all added
+       functions; made flushing take place at the correct place even if
+       the MODEBUF_DEST_DEOP flag is set; rewrote build_string() helper
+       to bash some stupid bugs; made modebuf_flush() return if ModeBuf
+       is empty, fixed the apparent source, removed some bogus string
+       termination code, properly terminate the mode strings, add support
+       for HACK2 and HACK3, made limit strings not be sent if the limit
+       is being removed, changed where '+' and '-' come from in sent
+       strings, added support for DEOP flag, set up bouncing code for
+       HACK2
+
+       * ircd/Makefile.in: ran make depend
+
+       * include/channel.h: added new defines for future functionality,
+       made modebuf_flush() return int so I can use tail recursion
+
+       * ircd/m_clearmode.c: add msg.h to includes; other misc cleanups
+       to make it all compile
+
+       * ircd/m_opmode.c: add msg.h to includes...
+
+       * ircd/m_clearmode.c: implemented mo_clearchan()/ms_clearchan()
+
+       * ircd/channel.c (modebuf_flush): realized I forgot to
+       nul-terminate addbuf/rembuf properly...
+
+       * ircd/m_clearmode.c (do_clearmode): wrote do_clearmode()...
+
+       * ircd/channel.c (modebuf_flush): correct sendto_server_butone to
+       sendto_serv_butone--blah^2
+
+       * ircd/send.c (sendto_serv_butone): stupid comments confused me
+
+       * ircd/channel.c (modebuf_flush): if there are no mode changes to
+       propagate, we're done...
+
+       * ircd/channel.c (modebuf_flush): duh; it's sendto_server_butone,
+       not sendto_all_butone
+
+       * ircd/m_clearmode.c: define skeleton for m{o,s}_clearmode
+
+       * ircd/m_opmode.c: define skeleton for m{o,s}_opmode
+
+       * ircd/Makefile.in (SRC): added m_opmode() and m_clearmode() to
+       the list
+
+       * ircd/parse.c: added messages for opmode and clearmode
+
+       * include/handlers.h: added declarations for mo_opmode(),
+       ms_opmode(), mo_clearmode(), and ms_clearmode()
+
+       * include/msg.h: define MSG_OPMODE, TOK_OPMODE, MSG_CLEARMODE, and
+       TOK_CLEARMODE
+
+       * include/channel.h (MODEBUF_DEST_OPMODE): Define the
+       MODEBUF_DEST_OPMODE flag
+
+       * ircd/channel.c (modebuf_flush): added new flag,
+       MODEBUF_DEST_OPMODE; causes channel MODE/HACK(4) notice to appear
+       to originate from source's server (or source itself, if
+       IsServer(source)); also causes a server-level MODE to be sent as
+       OPMODE instead
+
+       * include/channel.h: defined MODEBUF_DEST_SERVER,
+       MODEBUF_DEST_HACK4
+
+       * ircd/channel.c: Add another argument to build_string() to handle
+       numeric nicks; implemented MODEBUF_DEST_SERVER to send MODEs to
+       servers; implemented MODEBUF_DEST_HACK4 to cause HACK(4) notices
+       to be sent out
+
+2000-03-27  Perry Lorier <isomer@coders.net>
+
+       * ircd/s_bsd.c: fixed missing 'u' typo.
+
+2000-03-26  Kevin L. Mitchell  <klmitch@emc.com>
+
+       * ircd/channel.c: implement modebuf_init(), _mode(), _mode_uint(),
+       _mode_string(), _mode_client(), _flush(); also implemented a
+       simple build_string()
+
+       * include/channel.h: added definition of ModeBuf, modebuf_*
+       manipulation functions, and a couple of helper macros
+
diff --git a/doc/history/Manual b/doc/history/Manual
new file mode 100644 (file)
index 0000000..37a31a1
--- /dev/null
@@ -0,0 +1,316 @@
+/************************************************************************
+ *   IRC - Internet Relay Chat, doc/MANUAL
+ *   Copyright (C) 1990, Karl Kleinpaste
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 1, or (at your option)
+ *   any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+                                        Date: 04 Apr 1989
+                                      Author: Karl Kleinpaste
+                                              karl@cis.ohio-state.edu
+                                                
+                           Last modification: 15 May 1992
+                                          by  Mauri Haikola 
+                                              mjh@stekt.oulu.fi
+
+                      Modified for undernet: 7 Feb 1995
+                                         by  Carlo Wood
+                                             carlo@runaway.xs4all.nl 
+
+
+                     INTERNET RELAY CHAT (IRC)
+                 a real-time conversational system
+
+
+* 1: IRC - replacement for talk(1)
+
+IRC is a functional replacement for and improvement to talk(1).  Talk
+is an old, primitive, atrocious, minimalist sort of keyboard/screen
+conversation tool, using a grotesque, machine-dependent protocol.
+IRC does everything talk does, but with a better protocol, allowing
+more than 2 users to talk at once, with access across the aggregate
+Internet, and providing a whole raft of other useful features.
+
+Note (added Apr 7, 1998): The above statement has been left there for
+historical reasons.  It should be noted however that IRC is not any
+longer a replacement for talk(1).  At the time IRC was first developed,
+people connected to internet all were using accounts on UNIX Operating
+Systems, which almost all did run a non-restricted fingerd and a talkd.
+This allowed to see if someone was logged in (with finger) and then
+summon him to talk by connecting to his talk daemon.  For IRC however it
+is necessary to already be connected to an IRC server and one needs
+to pay attention to the window of the IRC client in order to see if someone
+wants to talk to you.  Therefore IRC has become more of a 'chat box':
+a Real Time Chat environment for chatting, making friends and exchanging
+information.  It has little resemblance anyore with talk(1).
+
+* 2: Entering Internet Relay Chat
+
+To enter Internet Relay Chat you need to run a client, which will start
+connecting to its default server.  More info on clients can be achieved
+from ftp://ftp.undernet.org/pub/irc/docs/faq/underfaq.1.  A lot of clients
+for all kinds of Operating Systems and (programming) languages can be
+found in ftp://ftp.undernet.org/pub/irc/clients/index.html.
+
+* 3: How much can be seen from here
+
+The universe - seriously.
+
+This is most formally called Internet Relay Chat.  Server hosts are
+connected via a tree structure.  The various servers relay control and
+message data among themselves to advertise the existence of other
+servers, users, and the channels and other resources being occupied by
+those users.
+
+* 4: Structure
+
+There is quite a lot of structure to the operation of IRC, as compared
+to crufty old talk(1).  Since so little could be done with talk(1), it
+needed little structure.  But to keep track of people spread literally
+around the world, the structure is useful so that one can speak to exactly
+those people with whom one wishes to speak.  The structure is outlined in
+more detail in the paragraphs below.
+
+** 4.1: Nicknames
+
+All users of IRC are known to the system by a `nickname.'  A nickname
+can be chosen at the moment the client connects, but can be changed at
+any time.  Nickname clashes are not allowed; this is enforced by the servers.
+If one's intended nickname clashes with someone else as one enters chat, one
+will not be able to complete entry to IRC until one changes one's nickname
+to something else.
+
+** 4.2: Presence on a channel
+
+Fundamental to the operation of IRC is the concept of a channel.  All
+users are `on a channel' while inside IRC.  One enters the `null
+channel' first.  One cannot send any messages while not in any
+chatting channel unless one has set up a private conversation in some
+way.  The number of channels is virtually unlimited - whatever will
+fit in a string of 200 characters and starts with a #, & or + sign.
+A channel which is prefixed with a '#' (pound sign) is a global channel;
+available to everyone on the network.  A channel prefixed with a
+'&' (ampersand) is a local channel; only available to users on the server
+you are connected to.  While a channel prefixed with a + (addition sign)
+are global and modeless; those channels do accept mode changes.
+
+** 4.3: Main modes of #channels
+
+Public
+
+This is the default mode for a channel.  When one is on a public
+channel, one can be seen by all other users (if one's own user mode
+permits this).  Anyone can notice users on a public channel and join
+such a channel's conversation.
+
+Private
+
+This means that, although anyone can see that one is using chat, no
+one can tell what channel one is using unless one is already on that
+channel with oneself.  Since the number of potential channels is in
+the billions, this is quite some security - all one gives away is the
+acknowledgement that one is using chat.
+
+Secret
+
+While one is on a secret channel, no one who is not on one's channel
+with oneself can even see that one is there.  One's name does not show
+up in a wildcard search of active users.  Of course, making a channel
+like '#test' secret gives a huge change to be discovered anyway.
+
+Changing the mode
+
+The mode of a channel (private, secret, invite-only, moderated,
+topic-limited, person-number-limited, no-messages-to-channel, ban
+someone from channel, etc.) is set by a channel operator, who is the
+first person to join a channel, or someone who has had channel
+operatorship bestowed on them by another channel operator. 
+
+Local channels
+
+Channels which are prefixed with the ampersand (&) sign are local
+channels which mean they can only be accessed to users who are on
+the same server.  For example, &help may exist on every server on
+the network, however each of them are different channels whereas
+global (#) channels are just one channel for the entire network.
+
+Modeless channels
+
+Channels that have a name that start with a plus sign (+) instead,
+are modeless.  This means that nobody is channel operator and hence
+no mode changes can be done.  The default mode of a +channel is "+nt".
+The intention of modeless channels is to avoid channel wars by making
+all users on that channel a-priori equal.  The only possible abuse,
+channel flooding, should be solved with /ignore.
+
+*** 4.4: Conversations not using channels
+
+It is possible to conduct conversations with others without using the
+formalized channel structure.  Doing so requires that two people set
+themselves up for private conversation using special commands; see
+User Commands below.
+
+** 5: Getting help
+
+Type "/help."  Follow the instructions.  Since this is a client feature
+it might not work for you, in which case you'd have to consult your
+local IRC guru or someone on the net.
+
+** 5.1: User commands
+
+In most clients, commands must start with a '/' (for example: /join #test).
+The most important commands supported by IRC are:
+
+      help      quit       who     whois
+      list     topic      join      part
+     links       msg    invite   silence
+     names     stats      nick      away
+      info     clear     query    ignore
+      mode
+
+Also read the file ADD-TO-IRCRC for a description of Undernet specific
+commands and an example script for the ircII client.
+
+*** 5.1.1: /quit [comment]
+
+/quit exits chat.  Optional comment may be included; see above.
+
+*** 5.1.2: /who [channelname_mask | user@host.mask]
+
+/who returns information on who is using chat.  Users of public channels
+show up with one of their channels identified, if any.  Users of private
+channels appear, but they are specified as being on a private, unspecified
+channel.  Users of secret channels and users whose user mode is +i (invisible)
+do not appear at all.
+
+Giving a channel name as an argument to /who returns only those users of the
+specified channel.  This still doesn't show users of secret channel or
+invisible users one is actually on the same channel with them.  Users
+of private channels are shown, if an exact channel name is given.
+
+For a detailed explanation of the many options of /who, see doc/readme.who !
+
+*** 5.1.3: /whois <nickname>
+
+This returns information about individual users.  Type "/whois nickname"
+to get information on the login name and host from which the nicknamed
+user comes.  You can specify multiple nicknames to query by seperating
+each with a comma.
+
+*** 5.1.4: /topic <some topic string>
+
+Channels can be given off-the-cuff "topics."  Saying "/topic some
+string of text" will associate that topic with the current channel.
+
+*** 5.1.5: /list [options] [channel.mask]
+
+/list will give lists of active channels, the number of users of each,
+and the topics therewith associated.  Again, secret channels do not
+appear and private channels only appear as Prv.
+
+[options] is a comma seperated list of one or more of the following options:
+
+       >nnn
+       <nnn
+       C<ccc
+       C>ccc
+       T<ttt
+    and T>ttt
+
+This comma seperated list may not contain spaces.
+Here `nnn' is the minimum or maximum number of users on a channel,
+`ccc' is the minimum or maximum age or creation time of a channel, in
+respectively seconds or UTC.  And `ttt' is the minimum or maximum age
+or creation time of the topic of the channel, in respectively seconds
+or UTC.
+
+On most servers, if no options are given, the server will use a
+default option (like "T<10") in order to strongly reduce the of number
+of listed channels.
+
+*** 5.1.6: /join <channel> [key]
+
+/join <channel_name> is the means to enter a channel.  Give the channel
+name as an argument.  If this is a secret or hidden channel, /who
+commands will show oneself and any other users of one's channel.
+
+One's arrival on a channel is announced to the rest of the users
+already on that channel.  Silent, anonymous "lurking" is not
+supported.
+
+If the channel is locked with a key, you need to add the [key]
+parameter which acts as a password (cannot contain spaces).
+
+*** 5.1.7: /msg <nick> <some text string>
+
+A single message can be sent privately to a certain user with /msg.
+Type /msg nickname and the text to be sent.  It will be sent privately
+to the indicated nickname.
+
+*** 5.1.8: /invite <nick> <#channel>
+
+If there is a user online to whom one wishes to speak, one may invite
+that user to join oneself on a certain channel.  One types "/invite
+nickname" with an optional channel name.  The receiving user gets a
+one-line message indicating the sender and the invitation.  The
+receiving user is free to ignore the invitation, of course.  You
+cannot invite users to a modeless channel.
+
+*** 5.1.9: /ignore <nick!user@host.mask>
+
+If one wants to ignore messages sent by some other user or users, it
+may be done with /ignore command.  One can ignore someone by their
+nickname, or by their user@host data.  Wildcards may be used.  /ignore
+is only intended to ignore annoying public messages (messages sent to
+a channel), to stop flooding (a huge number of messages per second)
+you have to use banning for channel messages, and /silence for private
+messages.  /mode <your nick> +d stops all messages from ALL channels.
+
+*** 5.1.12: /silence [nick!user@host.mask]
+
+This command effectively stops private message flooding at the server
+of the flooder.  You can use "/silence nick" to get a list of the
+silence masks of 'nick'.  This command is undernet specific and therefor
+not supported by all clients unless you add specifically a line to your
+clients configuration file.
+
+*** 5.1.11: /nick <new_nick>
+
+One can change nicknames by issuing "/nick new-nickname."  All users
+on one's channel will be informed about the change.  NOTE: If one enters
+chat with a nickname clash (e.g., one's login name is the same as
+someone else's, and the other user got there first), the system will
+not let one enter until one issues a /nick command with a unique
+nickname.  Nicknames are limited to nine characters in length on the
+Undernet.
+
+*** 5.1.12: /mode #channel [lots of parameters]
+
+This command can be used for altering the various modes of a channel
+(see the explanation of channel modes above).  /mode command can only
+be issued by channel operators.  Please use /help, or the manual of
+your client to find out about this command.
+
+If you would like a list of the current modes in the channel, type
+/mode <channel> (you do not need to be a channel operator to do this).
+For a list of channel bans, type /mode <channel> +b.
+
+* 6: Questions, problems, troubles?
+
+If you have problems, please get and read the FAQs from
+ftp.undernet.org:/pub/irc/docs/underfaq.1 and underfaq.2.
+You can also ask for help on some of the operator channels on IRC,
+for example #help.  They will be able to assist you in whatever
+problems you are having with IRC.
diff --git a/doc/history/README-2.6 b/doc/history/README-2.6
new file mode 100644 (file)
index 0000000..6ba8ada
--- /dev/null
@@ -0,0 +1,71 @@
+/************************************************************************
+ *   IRC - Internet Relay Chat, README
+ *   Copyright (C) 1990
+ *
+ *   For the list of authors and their e-mail addresses, see
+ *   file doc/AUTHORS
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 1, or (at your option)
+ *   any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+To install the new server, there is just a few changes to be made.
+
+* General Comments
+
+  Tue Nov 13 12:43:46 1990  Armin Gruner <gruner@informatik.tu-muenchen.de>
+
+      (APOLLO: Be sure to have NEED_INET_NETOF, NEED_INET_ADDR and
+       NEED_INET_NTOA undefined.)
+
+  Mon Nov 26 20:10:37 1990  Armin Gruner <gruner@informatik.tu-muenchen.de>
+
+      Comment: I just found that compiling on our SUN SPARC with GCC produces
+      code that dumps core.. (that might not happen on your machine, try it,
+      we may have out-of-date libraries). See netnews gnu.gcc.bug for a dis-
+      cussion about the matter. It seems that gcc passes struct's in a
+      different manner.
+
+* Server configuration
+
+  Edit the include/config.h to your hearts content, avoiding going
+  beyond the warning line, unless you are *absolute* sure you know
+  what you are doing.
+  If you happen to not take to this warning, you may end up with
+  a server that will not function properly and annoy not only you,
+  but users all around the world.
+
+  Old irc client can be found in this package and if you want to use it,
+  check Makefile in directory irc before compiling. There are other,
+  better irc clients in distribution and the client distributed with
+  this version is simply something to begin with if you don't happen
+  to have other clients available.
+
+  This version was brought to you by jto@tolsun.oulu.fi and send any
+  bug fixes and suggestions to me.
+
+NOTE: This server does *NOT* have MAIL system installed by default.
+      The reason is that it doesn't work with many systems.
+
+This version introduces you string channels, starting with
+a plus (+) sign. The first person joining a string channel
+claims it's ownership and after that is entitiled to use /mode
+command. Ownerships can be given and taken away with
+/mode <channel> +o <nickname>  and /mode <channel> -o <nickname>
+Other flags are: s - secret, p - private, l - limited, i - inviteonly.
+                 m - moderated, n - no private messages to channel,
+                 t - topic settable by operator only
+New command /KICK <channel> <user> kicks a user off channel.
+
+--Jarkko (jto@oulu.fi)
diff --git a/doc/history/README.patches b/doc/history/README.patches
new file mode 100644 (file)
index 0000000..cfc917b
--- /dev/null
@@ -0,0 +1,1901 @@
+
+The available patches for 2.8*mu servers are:
+
+Tp8 = TimeStampPre8 - A protocol which disallows netsplit ops and channel
+                      desynchs.
+
+Bquiet - does not allow a person who is banned to speak over the channel
+
+Silence - Cuts off flooding at local server
+
+Anc = Anti-Nick collide - *Intentional* nick collides are impossible with
+                          this wonderful patch.
+
+W = Wallops - lets you send messages to other IRC ops
+
+ban = BanInformation - Lets you see who did a ban and when, as well
+
+sw = /stats w - lets you gather statistics on average client connects
+
+To = TopicInformation - Lets you see who set the topic for a channel and when
+
+S = Signon Time - Tells you when a local user signed onto IRC
+
+Cl = Client connect - Notifies opers on your server of client connects/
+                      disconnects (with disconnect reason)
+
+TT = Trace Times - displays the time (in secs) since your server last heard
+                   anything from a client/server, when you do /trace.
+
+KL = K-line comments - Allows you to modify the lame "no ghosts allowed" default 
+                       comment to whatever you wish, or alternately, display a 
+                        file to a rejected client.
+
+OF = Oper fail patch - displays a warning to current ops when someone fails
+                       in entering the right oper password.
+
+MC = Mixed case patch - useful for those pesky clone bots and hacked logins;
+               disallows userids which have mixed case or control chars
+
+N = Note - allows you keep a "note" for other users, amongst other things
+
+-----------------------------------------------------------------------------
+Explanations for these patches follow.....
+
+Help on patches written by Mandar Mirashi (mmmirash@mailhost.ecn.uoknor.edu)
+                           Mmmm on IRC.
+
+
+=============================================================================
+                                TIMESTAMP 
+=============================================================================
+Author: Carlo, carlo@sg.tn.tudelft.nl, Run on IRC.
+Info on TS protocol:
+
+                               TSpre7
+
+------
+Effects of the TS protocol:
+
+> No mode wars possible.
+  When you take someones op there are three possibilities:
+  - You were too late (You was already de-opped on your server).
+  - You take it (On the *whole* net).
+  - You start taking it (on your server, but it is 'bounced' (ie your mode
+    change is cancelled); This occurs when you try to do mode change
+    direct after a net re-connection in a situation were you hacked op by
+    net-break riding.
+> No desynchronisation possible.
+> No unnecessary MODE msg send. You can't send 'double' mode's that don't
+  make sense. Servers don't send unnecessary MODE's either.
+> Hacking op is from now on *only* possible by admins that hacked their
+  servercode, and therefor easier to prosecute. Also you can 'hack' op still
+  exactly like now (by riding net break) on an *opless* channel.
+> The protocol is fully compatible with older servers: It is invisible
+  and it works with old servers like this: Every 'block' of direct connected
+        2.8.x.TS servers will stay synchronized, Hacking op is impossible by means
+        of riding a net break between two TS-servers on channels that were created
+        within that block. In all other cases the same happens as without TS.
+
+Here follow technical details implemented in TSpre7:
+
+------
+
+Reference: 2.8.14/15.TSpre7
+Full list of TS-MODE-Change protocol:
+
+-Mode changes (originating by clients) are refused only:
+ 1) from a client that is directly connected and has no chan ops on 
+    the channel on its server.
+ 2) when not being a change of the internal state of a server (Well, refused
+    is to strong, propagation of the mode is just unnecessary and thus not
+    done).
+ 3) from someone flagged as de-opped-by-server. (flag is reset when this
+    person is opped again by anyone) (The server detecting this mode change
+    cancels the mode change, by bouncing it upstream, thus keeping the net
+    synchronized).
+
+-An extra parameter is added behind MODE changes *done* by servers, sended
+ *to* other servers. It is a Universal Time in ascii seconds. This extra
+ parameter is NOT sended when it is 0 (can happen with old servers on the
+ net), 0 means <NONE> rather then Jan 1st 1970 :).
+ This parameter is the creationtime of the channel being: the universal time at
+ which the channel was created by a *local* client; or the non-zero received
+ creation time from an other server (as parameter with a mode change) that
+ was earlier then its own; or equal 0 when the channel was created by
+ a non-local client and no MODE with TS was received (yet).
+
+-Of the channel_flags is 1 bit more used: CHFL_DEOPPED, set when de-opped
+ by a server (compare CHFL_CHANOP, set when channel operator). It's reset
+ when opped. (And starts reset on joining (creation?) of a channel, this
+ will be changed to 'set' on join, when all servers have TS; making detection
+ of op hacking by admins a bit easier).
+
+-Timestamps (sended by TS-servers) are handled as follows:
+ Received TS      Own TS      Bounced/Propagated
+    equal          equal       propagated
+    later          >0,earlier  if ops: bounced with own TS
+                               if no ops: propagated with own TS
+                               (own TS is sended upstream too, to make sure
+                                TS stays synchronized).
+    earlier        later       TS copied, propagated
+    none           any         propagated, own TS sended.
+    >0             none        if ops: propagated, no TS sended, own TS stays 0.
+                               if no ops: TS copied, propagated.
+
+-A mode change +/-o nick (+/- v) from a person that is deopped by a server
+ results in a -/+o nick back up stream (and is not propagated) if it was
+ an attempt to change the internal state of the receiving server.
+
+-kick is handled as mode -o, internal state 'not on channel' being 'already
+ de-opped'. Bounce includes JOIN and restoring o and v flags.
+ (Effect: You don't even *see* the kick on one side, on the other side
+  the person joins again and gets his flags back from the bouncing server).
+
+-A received TimeStamp that claims a creation time *earlier* then that
+ this server dissapeared from the net results in a HACK: notice (with
+ time difference in seconds). Bye OPER.. (This meaning, to hack op
+ on an existing channel that was created 15 minutes before you disconnected
+ your server, you will have generated a HACK notice: Clock set back at least
+ 900 seconds by <nick>.) (Not yet implemented, prob. in pre8).
+
+
+                               TSpre8
+
+
+From: Carlo Kid - Runaway <carlo@sg.tn.tudelft.nl>
+Subject: *** IMPORTANT; RFC
+To: wastelanders@rush.cc.edu (New Wastelanders MailingList)
+Date: Thu, 14 Apr 94 18:03:38 METDST
+Mailer: Elm [revision: 66.33]
+Status: RO
+
+Hi, please read this carefully and respond if you think it will result
+in INCORRECT behaviour under any circumstances:
+
+Here follow technical details implemented in TSpre8:
+
+------
+
+Reference: 2.8.17.TSpre8
+Full list of TS-MODE-Change protocol:
+
+-Mode changes (originating by clients) are refused only:
+ 1) from a client that is directly connected and has no chan ops on 
+    the channel on its server.
+ 2) when not being a change of the internal state of a server (Well, refused
+    is to strong, propagation of the mode is just unnecessary and thus not
+    done).
+ 3) from someone flagged as de-opped-by-server. (flag is reset when this
+    person is opped again by anyone) (The server detecting this mode change
+    cancels the mode change, by bouncing it upstream, thus keeping the net
+    synchronized).
+ 4) When a '0' as timestamp is received, originating from a server (see below).
+    Then the whole mode is ignored, a HACK notice is sent to all ops and the
+                string is propagated as received.
+
+-An extra parameter is added behind MODE changes *done* by servers, sent
+ *to* other servers *containing* a +o, -o, +v or -v.
+ It is a Universal Time in ascii seconds.
+ Whenever a HACK is detected, a HACK: notice is sent to all local opers,
+ and the full MODE is propagated with a '0' as timestamp, generating
+ a HACK notice on all other servers.
+ Otherwise this parameter is the creationtime of the channel being: the
+ universal time at which the channel was created by a *local* client;
+ or the non-zero received creation time from an other server (as parameter
+ with a mode change) that was earlier then its own; or equal 0 when the
+ channel was created by a non-local client and no MODE with TS was received
+ (yet).
+
+-Of the channel_flags is 1 bit more used: CHFL_DEOPPED, set when de-opped
+ by a server (compare CHFL_CHANOP, set when channel operator). It's reset
+ when opped. It starts *set* on joining (creation?) of a channel, making
+ detection of op hacking by admins a bit easier.
+
+-Timestamps (sent by TS-servers) are handled as follows:
+ Received TS      Own TS      Bounced/Propagated
+    equal          equal       propagated
+    later          >0,earlier  if ops: bounced with own TS
+                               if no ops: TS copied, propagated
+    earlier        later       TS copied, propagated
+    0 or none      any         HACK generated, 0 propagated, own TS is kept
+    >0             none        TS copied, propagated.
+
+-A mode change +/-o nick (+/- v) from a person that is deopped by a server
+ results in a -/+o nick back up stream (and is not propagated) if it was
+ an attempt to change the internal state of the receiving server.
+
+-kick is handled as mode -o, internal state 'not on channel' being 'already
+ de-opped'. Bounce includes JOIN and restoring o and v flags.
+ (Effect: You don't even *see* the kick on one side, on the other side
+  the person joins again and gets his flags back from the bouncing server).
+
+-A received TimeStamp that claims a creation time *earlier* then that
+ this server dissapeared from the net results in a HACK: notice (with
+ time difference in seconds). Bye OPER.. (This meaning, to hack op
+ on an existing channel that was created 15 minutes before you disconnected
+ your server, you will have generated a HACK notice: Clock set back at least
+ 900 seconds by <nick>.)
+
+
+
+
+From: Carlo Kid - Runaway <carlo@sg.tn.tudelft.nl>
+Subject: TSpre8 can work! :)
+To: wastelanders@rush.cc.edu (New Wastelanders MailingList)
+Date: Wed, 20 Apr 94 11:44:39 METDST
+Mailer: Elm [revision: 66.33]
+Status: RO
+
+Well... it took me a few days (a night and some dreams actually), but
+I think I found a solution for the problem I mentioned during the meeting :)
+
+Let me first repeat the problem:
+
+- I stated that TSpre8 would prevent op hacking by admins, but... later
+  I realized that that was impossible the way wanted it :(
+  My idea was at first: Simply generate a HACK notice when a server
+  comes on the net with a creation time earlier then when it did split off
+  (and earlier then my own creation time). This sounds nice, but in
+  even this simple case it doesn't work:
+
+Server A and B, users a and b:
+
+  A -- B 
+  |    
+ @a       TS=100
+
+Split at t=200
+
+  A    B
+  |    
+ @a 
+
+b joins at t=300
+
+  A(TS=100)  B(TS=300)
+  |          |
+ @a         @b
+
+Net joins:
+
+  A -- B
+  |    |
+  a    b
+
+Both are de-opped: b because he sends a TS of 300 with is greater (later)
+then 100 (correctly: he used the netbreak). And a is deopped with a
+HACK notice by B, because he introduces 1) a TS earlier then the existing
+TS (100<300) and 2) the 100 is earlier then the time the split occured.
+
+The reason why this goes wrong is simply because B *forgets* the channel
+AND the TS of 100, after the split... If B would *keep* in memory that
+the channel existed on A and with what TS, it would be possible, but only
+at cost of a lot of extra memory usage...
+
+Now my new idea :) It allows hacking, but only in not so very interesting
+cases... And at least it makes it extremely difficult for a newbee, so we
+might at least catch 99% before they understand how it works :)
+
+(This explanation should not be on a public ftp site anymore after a while :)
+
+New rules:
+
+- Servers that are OFF the net for more then one day are forgotten.
+- New servers (or forgotten servers), are always bounced except on channels
+  that have no ops (when they create a channel of their own thus :) unless
+  the receiving server is younger then one day and the introduced TS is
+  earlier then the start up time (minus 10 minutes :/) of the receiving server.
+  'Birthdays' of those servers are also kept.
+- A server that splitted off while a channel already existed, and thus
+  has a creation time earlier then the "received squit time" of that
+  server, is not allowed to introduce an earlier timestamp then the
+  creationtime of the channel (HACK), and also not an equal TS when
+  younger then one day.
+- A server introducing a server with an earlier "time of received squit"
+  inherrits that time as its own "time of received squit".
+
+This allows to hack op on a channel that didn't exist when you splitted
+(not interesting). You also can't keep a server off the net till you need
+it (a telnet connection), because those can't do anything for one day long,
+unless they send the TS *equal* to the existing TS (The only exception :(),
+having to connect between two and one days before the hack, break between
+zero and one day before the hack but before the channel existed, connect
+and hack with equal TS.
+
+What do you think? Just for fun? :)
+
+Apart from that it would be suspicious when someone connects/breaks every
+24 hours a "test" server, channels that exist longer then one day are
+unhackable.
+
+The "disadvantages" are: servers that break off the net for *longer* then
+one day, but keep a channel up with an op, on *both sides of the net, will
+be completely de-opped after reconnection.
+
+*** IMPORTANT:
+
+I am absolutely not sure ;) if there aren't any other disadvantages or
+unwanted effects :) Please, think this over and mail me if you find some
+objection...
+
+Run
+
+
+
+
+From: Carlo Kid - Runaway <carlo@sg.tn.tudelft.nl>
+Subject: 2.8.19.U3 RELEASED
+To: wastelanders@rush.cc.edu (New Wastelanders MailingList)
+Date: Sun, 22 May 94 14:15:41 METDST
+Cc: carlo@sg.tn.tudelft.nl
+Mailer: Elm [revision: 66.33]
+Status: RO
+
+Hi all :)
+
+Proud to present: 2.8.19.U3 :)
+
+I have spend *enormous* amounts of time in TESTING this version,
+and I really hope it is completely bug free, but the changes are
+very big, so maybe persons who only want to upgrade/compile ONCE
+should wait a little longer then the compile cracks we have here ;)
+
+For real testing we need the HUBs though! So please, don't hesitate,
+Delft (a HUB) is running it already for a long time, also linked to
+other 2.8.19.U3 test servers.
+
+Before I'll tell about whats new in U3, I want to especially thank
+President for the tremendous help in testing TSpre8 -- I would never
+have been able bring up the stength to go through the difficult
+periods without him being there to listen to my technical complaints ;)
+
+=======================================================================
+
+NEW in .U3
+----------
+
+First all, TSpre8.
+
+It did not become what I hoped/expected to be possible :(
+Hacking will still be possible, but at least it will be a LOT
+more difficult when you don't know what you are doing, and I think
+we WILL catch (new) admins that think they can abuse their powers
+to be GOD on "their" channel.
+
+Especially, nobody will be able to hack *anything* with a normal nick.
+And because server modes are more obvious a hack, this alone is a
+step forward against admin hacking prevention imho.
+
+The .patch file is 
+-rw-------   1 carlo    users      65142 May 22 01:29 irc2.8.19-TSpre8.patch
+big.
+
+I'll now brows through it and mentions changes in the order they appear
+in the .patch file, arbitrary order thus ;)
+
+Zombies
+-------
+
+As mentioned before on 'wastelanders', I changed the internal way a KICK
+is handled, to be able to stop illegal -hacked- kicks from *outside* the
+channel. This has no effect on server-server protocol nor on server-client
+protocol. But because this way it is possible to keep (a little) memory
+for channels you're not on (being kicked from) I thought it would be no
+more then logical to stop people from joining the usual 10 ten channels
+at the same time, *including* the ones you are kicked from (because they
+occupy memory). This memory is released when you 1) Try to rejoin (so with
+all people having a auto-rejoin-on kick NOTHING changed at all), or 2)
+when you do a part - this is new and only intended to use when you do
+NOT have auto-rejoin, when you do not even WANT to rejoin, or try, assuming
+you might not be banned, when you have been kicked like this of a lot of
+channels and all together are "on" 10 channels so you NEED to leave one
+before you can join another... For this rare case, you must know on
+*which* channels you "are", therefor this is visible when you do a
+/names, or /who or /whois to yourself. It is never visible for others.
+Example:
+
+12:07 * Run (Daryl@sg.tn.tudelft.nl) has joined channel #wasteland
+*** Mode change "+o Run" on channel #wasteland by Wasted
+*** #wasteland : created Fri May 13 17:08:34 1994
+<Macro> Hi Run !
+*** You have been kicked off channel #wasteland by Run (Test)
+*** Run is Daryl@sg.tn.tudelft.nl (/msg Run profile)
+*** on channels: !#wasteland 
+*** on irc via server Delft.NL.EU.undernet.org (Runaway Server
++[130.161.188.188])
+*** Run is away: Writting E-mail
+*** Run is an IRC Operator
+*** Run has been idle for 642 seconds.
+
+As you can see, the channel is marked with a '!' to show you are NOT
+not that channel... Both, a part #wasteland as well as a join (being
+not able to actually join because of ban, invite-only, key or limit), will
+remove you from this channel. The part will be sent back to (only) you, and
+everything has turned out to be 100% compatible with ircii protocol.
+Finally, of course the channel is removed when everyone is kicked and/or
+left the channel (a channel with only zombies is removed immedeately).
+
+#define RPL_CREATIONTIME     329
+--------------------------------
+
+A new numeric is sent when you ask for a MODE of a channel, by doing
+/MODE #channel
+without parameters.
+The reply is the same as before, but followed by a new numeric 329:
+
+/MODE #wasteland
+Delft.NL.EU.undernet.org 324 Run #wasteland +t
+Delft.NL.EU.undernet.org 329 Run #wasteland 768845314
+
+To supress this, you'll have to add something like:
+ON ^329 *
+to your .ircrc file. If you want to see this new numeric, you would
+add
+On ^329 "*" echo *** $1 : created $stime($2)
+
+It turns out that ircii clients ask for this mode when you join a
+channel, therefor you will see the creationtime when you join a channel,
+I'll leave it as an exercise to suppress this, but still being able to
+see it when you specifically ask for it :)
+
+New ircd.conf line
+------------------
+
+This is IMPORTANT :
+In order for Uworld to work you MUST add those lines to your ircd.conf file:
+
+U:Uworld.undernet.org::*
+U:Underworld.nl::*
+
+The later to allow the backup Underworld.nl to still function.
+If you forget this, or do it wrong, your server might refuse to accept
+certain mode changes from Uworld.undernet.org and start *bouncing*
+modes done by lusers that got op from it. The name of servers allowed
+to hack have to be agreed upon totally, by all admins. If one admin
+removes his U: line, the service will not work always correctly.
+
+When a server does a mode change that is detected to be a hack, you
+will see -as an oper, or +s luser- this notice:
+
+-> *uworld* opcom MODE #wasteland +o Mmmm
+!Uworld.undernet.org! Run is using Uworld to : MODE #wasteland +o Mmmm
+*** Notice -- HACK: Uworld.undernet.org MODE #wasteland +o Mmmm 
+*** Mode change "+o Mmmm" on channel #wasteland by Uworld.undernet.org
+
+Normally, this HACK notice would NOT take effect! You still *see* the
+HACK notice for the U: line server(s) but then they DO take effect.
+
+Every other message (some including the word HACK) do also take effect,
+and are only a warning that someone is MAYBE hacking...
+I didn't see it occur yet.
+
+Removed bugs
+------------
+
+I did find some bugs in TSpre7, never thought that was possible :)
+I forgot what it exactly was, but under (very rare) circumstances it
+could be pretty serious :/
+
+One rather important thing is that now the TimeStamp is sent during a
+net re.join when there are no ops. Before it was possible to create
+a partly TimeStamp less net on an opless channel. TSpre8 garantees
+that the TS is synchronized on the whole net at any time.
+
+Other messages
+--------------
+
+Apart from the (true) HACK notice, you can get a:
+
+BOUNCE or HACK: notice, which does take effect and is most probably
+just a bounce of a mode done by an attacker: someone immedeately after
+a net re.join with his net.ride ops trying to de-op the others.
+I don't think this will happen often because it will be clear to all lusers
+that it is useless to try.
+
+NET.RIDE on opless #channel notice, you'll see this if someone does
+really abuses a net break to get ops on some opless channel. The mode
+does take effect however.
+
+FULL bounce of modes
+--------------------
+
+When before someone would ride a net break, and try something, ONLY
+his +/- o/v modes. Other modes like +mlk 1 \\|/\|/  would still take
+effect. With TSpre8 this changed... All modes (except bans) are bounced
+when someone rides a net break. Also the bouncing is more compact, while
+with TSpre7 every o and v mode took one line, now all modes are kept into
+one line.
+
+More allowed
+------------
+
+Before you was (how lame) not allowed to mix things like k, o and v...
+Now you are allowed, why not? Also you can use up to six parameters,
+really gives you a power kick ;)
+
+*** Mode change "+vvvvvv flux epa Skip Run Mmmm gyn" on channel #wasteland by
++Run
+
+User friendly mask fixing
+-------------------------
+
+The lame way Avalon fixes a mask (for a ban) is like this:
+
+/mode * +bb *.tudelft.nl Daryl@sg*.tn.tudelft.nl
+
+becomes:
+
+*** Mode change "+bb *.tudelft!*@* Daryl!*@sg*.tn.tudelft.nl" on channel
++#wasteland by Run
+
+The same on a TSpre8 server gives:
+
+*** Mode change "+b *!*@*.tudelft.nl" on channel #wasteland by Run
+
+While just Daryl@sg*.tn.tudelft.nl results in:
+
+*** Mode change "+b *!Daryl@sg*.tn.tudelft.nl" on channel #wasteland by Run
+
+which what one would expect!
+
+
+----------------------------------------------------------------
+
+Goodluck with compiling,
+
+Run
+
+PS If you encounter any problems, realize it is VERY unlikely that
+   it is .U3, but if you really think so, then first try to compile
+   plain 2.8.19. If you succeed, save the Makefile the include/config.h
+   and the include/setup.h. Unpack .U3, replace those files and recompile.
+   With this I assume you don't put your ircd.conf inside the source
+   directories of course, that would still have the paths set wrong then.
+
+   A smart move is to make patch file once for your Makefile/config.h :
+   First ONLY edit the Makefile and config.h (or copy the them from a
+   working source tree to a empty directory), and then make a diff with:
+   diff -rc irc2.8.19.clean irc2.8.19.my.makefile > Makefile.config.h.patch
+
+   That really speeds up upgrading with later versions.
+   (irc2.8.19.my.makefile only needs to contain
+    irc2.8.19.my.makefile/Makefile
+    irc2.8.19.my.makefile/include/config.h )
+   Of course, keep the include/setup.h seperately.
+
+### KILL for Mmm. Mmmm (stop it lamer (unnecessary flooding of alexbot))
+
+
+=============================================================================
+                               BQUIET
+=============================================================================
+Author: Carlo, carlo@sg.tn.tudelft.nl, Run on IRC.
+Helpful ideas by: Aaron, agifford@sci.dixie.edu, Karll on IRC
+
+
+In order to fight flooding, and as discussed on wastelanders, banning
+someone on a channel will now also stop him from doing anything visible
+on the channel. This allows to let someone see what you think of him
+without even kicking him, he will leave by himself.
+He will still be able to appologise by private msgs of course and then
+he can be de-banned. A ban is this way a short cut for +m+vvvv everyone
+excpet the flooder. Note that even NICK floods are stopped: When you are
+on a channel where you are banned, you are not allowed to change your nick.
+
+=============================================================================
+                               SILENCE 
+=============================================================================
+Author: Carlo, carlo@sg.tn.tudelft.nl, Run on IRC.
+Helpful ideas by: Aaron, agifford@sci.dixie.edu, Karll on IRC
+
+My solution to flooders with clone bots etc :)
+Let the user that GETS flooded decide he doesn't want that and stop
+the flooder right at his own server (the server of the flooder).
+This is a new command, and the clients will need unfortunately a few
+lines in their .ircrc before it can work.
+Moreover, before this works, ALL servers must have .U3.
+
+The lines I use at the moment are:
+
+ALIAS SILENCE QUOTE SILENCE
+ALIAS SILE QUOTE SILENCE
+ON ^RAW_IRC "% SILENCE %" echo *** $*
+
+It turns out that some auto-rejoin on kick lines, like Davemans toolbox,
+disables the use of ON RAW_IRC, or at least makes it work incorrectly.
+You should disable this auto-rejoin line and you could add the one I use
+instead:
+
+ON ^RAW_IRC "% KICK % % *" {
+    IF ([$3]==[$N]) {
+        //QUOTE JOIN $2
+        ECHO $MID(11 5 $STIME($TIME())) * You have been kicked off channel $2 by $LEFT($INDEX(! $0) $0) \($MID(1 256 $4-)\) } {
+        ECHO $MID(11 5 $STIME($TIME())) * $3 has been kicked off channel $2 by $LEFT($INDEX(! $0) $0) \($MID(1 256 $4-)\) }
+}
+
+which are 6 lines, not 8.
+
+The way the silence patch works is as follows:
+
+When you add a silence mask (using the same user friendly mask fixing)
+like:
+
+/SILENCE Tsunami*@
+
+It will echo back to you how it is added:
+
+*** Run!Daryl@sg.tn.tudelft.nl SILENCE +*!Tsunami*@*
+
+Note that there is a '+' infront of the mask now.
+You can also type:
+
+/SILENCE +bot*
+
+*** Run!Daryl@sg.tn.tudelft.nl SILENCE +bot*!*@*
+
+If you want to silence one particular nick, you must add the '+', because
+when you do:
+
+/SILENCE nick
+
+and 'nick' exists, you will get the silence list of nick. Just using
+/SILENCE gives your own silence list:
+
+*** Run bot*!*@*
+*** Run *!Tsunami*@*
+*** End of Silence List
+
+However, check the silence list of someone ELSE make only really sense
+when you already did sent a message to this person. Because a silence
+mask only propagates to the server of the flooder when it is actually
+necessary. For instance: You can add up to 5 silence masks and delete them
+again and it will only be local to your own server. Only when someone
+would message you, matching a mask, the mask propagates to the server of
+the flooder. And stays there till you signoff, or till you delete it.
+If you delete a mask, it follows the same path as the +masks...
+
+As a result of this, +s lusers and opers will see the message:
+
+*** SILENCE : Unknown command (from Lausanne.CH.EU.UnderNet.org)
+
+When someone from *behind* a non .U3 server sends you a message
+(Lausanne is this case). So, you will STILL be flooded ;) UNTIL ALL
+servers are upgraded... (Or must do -s, but at least the net is flooded).
+
+
+To: wastelanders@rush.cc.edu
+From: agifford@sci.dixie.edu (Aaron Gifford)
+Subject: HELP with HELP for SILENCE
+Status: RO
+
+Hey, here's a VERY VERY VERY rough draft of a HELP entry for SILENCE,
+assuming it becomes a new command for ircII and not a replacement for
+IGNORE either via new code, or aliases like:
+    ALIAS SILENCE { QUOTE SILENCE $* }
+
+Anyway, PLEASE PLEASE PLEASE alter, modify, correct, add, hack-up, etc this
+rough draft and send me your alterations.  I just typed this up VERY
+quickly because StGeorge is now running irc2.8.19.U3.1.  The bug I mention
+in the file will hopefully disappear very soon, so that text will have to
+do likewise and vanish.  :)
+
+Here it is, draft #1 HELP for SILENCE:
+
+Usage: SILENCE [<nick>]
+       SILENCE [+|-<pattern>]
+
+  SILENCE allows you to TOTALLY ignore all private messages (PRIVMSG's)
+  and notices (NOTICE's) from any user whose nick!user@host matches
+  the <pattern> parameter.  The characters * and ? can be used
+  as wildcards in the pattern.
+
+  If you wanted to ignore all users from "somewhere.com" you would use:
+    SILENCE +*!*@somewhere.com
+
+  To ignore some with the nickname "Jerk" you would use:
+    SILENCE +Jerk
+  NOTE: The server will complete the pattern, storing it as "Jerk!*@*"
+
+  The only drawback of just SILENCE'ing someone by nickname only is
+  that the user could quickly change nicknames to avoid your pattern.
+
+  To remove a pattern, use a - before the pattern you want to remove.
+  When the command is used without any parameters, the server will list
+  all stored patterns you are currently ignoring with the SILENCE
+  command.
+
+  When used in the first form listed, you will see the SILENCE list for
+  the specified user.  This list is not necessarily complete nor accurate
+  because of how servers share SILENCE information internally.  You can
+  check to see if someone is ignoring you with SILENCE by first sending
+  that user a private message, then using the command to see the user's
+  SILENCE list.
+
+  Currently there is a bug in the servers (hopefully to be fixed soon)
+  that will add the nickname you specify to your SILENCE list when you
+  attempt to see that user's SILENCE list if that user is not currently
+  online.
+
+  Because SILENCE is a part of the IRC server protocol (on the Undernet)
+  it works much more efficiently than IGNORE, but is limited to a very
+  brief list of patterns.  Also, you don't have as may options as you
+  do with IGNORE.  If a user is flooding you, SILENCE is many times
+  more efficient than IGNORE because the offending user's PRIMSG's or
+  NOTICE's (including CTCP) are stopped at the server and never even
+  sent to your client.
+
+See Also:
+  IGNORE
+
+
+
+
+From: Carlo Kid - Runaway <carlo@sg.tn.tudelft.nl>
+Subject: Re: HELP with HELP for SILENCE
+To: agifford@sci.dixie.edu (Aaron Gifford) (Aaron Gifford)
+Date: Wed, 25 May 94 12:29:37 METDST
+Cc: wastelanders@rush.cc.edu (New Wastelanders MailingList)
+In-Reply-To: <9405250313.AA18446@sci.dixie.edu>; from "Aaron Gifford" at May 24, 94 9:20 pm
+Mailer: Elm [revision: 66.33]
+Status: RO
+
+> Here it is, draft #1 HELP for SILENCE:
+> 
+> Usage: SILENCE [<nick>]
+>        SILENCE [+|-<pattern>]
+> 
+
+As it is now (I do not consider what you mentioned as a bug, I was aware
+of this effect and didn't choose to alter it), it really is:
+
+Usage: SILENCE [+|-]<pattern>
+Or   : SILENCE <nick>
+
+When you leave the '+|-' away A '+' is assumed.
+
+The second possibility allows you to check your own silence lists, or
+allows to check if you are silenced by someone after you did message
+him but didn't get a respond (did ping him for instance).
+Indeed, this could be interpreted as a pattern, when <nick> doesn't
+exists.
+
+>   If you wanted to ignore all users from "somewhere.com" you would use:
+>     SILENCE +*!*@somewhere.com
+
+SILENCE somewhere.com
+
+would do.
+
+>   When used in the first form listed, you will see the SILENCE list for
+>   the specified user.  This list is not necessarily complete nor accurate
+>   because of how servers share SILENCE information internally.  You can
+>   check to see if someone is ignoring you with SILENCE by first sending
+>   that user a private message, then using the command to see the user's
+>   SILENCE list.
+
+Mention that a EVAL CTCP <nick> PING $TIME() is better...
+It would not be necessary to do the silence if the ping returns...
+To determine between huge lag and silence, you have to do the silence
+check after that.
+If you add something like this in the manual, people will automatically
+wait a while after the 'message' (ping), so that the servers have time
+to send the silence mask back. Otherwise they might think they can do
+a quick msg+silence at the same time. Nah... Not too important, unless
+with huge lag + silence combination.
+
+> 
+>   Currently there is a bug in the servers (hopefully to be fixed soon)
+>   that will add the nickname you specify to your SILENCE list when you
+>   attempt to see that user's SILENCE list if that user is not currently
+>   online.
+
+I didn't consider this as too bad...
+But if people want it, I can change it so that you MUST add a '+' to
+add a mask that doesn't contain a '.', '!' or '@'.
+That would lead to 2.8.19.U3.2 and a very tiny patch for the people who
+already compiled .U3
+
+Run
+
+
+=============================================================================
+                       U3 - required additions to .ircrc
+=============================================================================
+
+
+From: Carlo Kid - Runaway <carlo@sg.tn.tudelft.nl>
+Subject: Re: .ircrc codes for the new patches :)
+To: lamberdc@dad.cs.tuns.ca
+Date: Mon, 23 May 94 11:41:31 METDST
+Cc: wastelanders@rush.cc.edu (New Wastelanders MailingList)
+In-Reply-To: <9405222118.AA02415@dad.cs.tuns.ca>; from "Donald "WHIZZARD" Lambert" at May 22, 94 6:18 pm
+Mailer: Elm [revision: 66.33]
+Status: RO
+
+> hiya All
+>       I was wondering if some one could send me a copy of the script/
+>  for the new patches including the ban , topic and client connecting patches.
+> 
+>       And whatever is now out with the new .19 code :)
+> 
+>       thanks 
+> 
+>               -- Donnie
+> 
+>               aka WHIZZARD
+
+The ftp.undernet.org:/pub/undernet/servers/Patches/README file:
+
+These are lines you need to add to your .ircrc file in order
+to use all posibilities .U3 profides you:
+
+To see when a channel was created:
+
+On ^329 * echo *** $1 : created $stime($2)
+
+When your server has the .ban patch use this to see who did a ban and when:
+
+On ^367 * if ([$4] != []) {echo *** $1 \($3 - $stime($4)) $2} {echo *** $1-}
+
+---------------------------
+When ALL servers upgraded to .U3, you can use this command:
+
+ALIAS SILENCE QUOTE SILENCE
+On ^RAW_IRC "% SILENCE %" echo *** $*
+
+Use this as:
+/SILENCE +mask
+
+To add 'mask' to your silence list (will completely stop all private
+messages from people matching 'mask' with their nick!user@host).
+You can VIEW your silence list by typing:
+/SILENCE
+
+If you message someone and he doesn't react (like with ping), then you
+can check if you match a silence mask he added by viewing his silence list
+with:
+/SILENCE nick
+
+A mask can be deleted by using the command:
+/SILENCE -mask
+
+When the some messages you from behind a NON-.U3 server you will not
+receive his message but the line:
+*** Unknown command (SILENCE) (From server.name.undernet.org)
+instead, so you will still be flooded.
+We hope all servers will be upgraded within a few months.
+
+------
+And my ircd.motd from Delft* :
+
+*%*%*%*%*%*%*%*%*%*%*%*%*%*%*%*%*%*%*%*%*%*%*%*%*%*%*%
+ N E W : - This server now runs the official released
+           beta version 2.8.19.U3.1.ban
+ For you as users this means that:
+ -More security : .U3 contains the .TSpre8 patch with
+  disallows even ADMINs of servers to hack op on your
+  channel with a nick, most server modes are detected.
+ -The possibility to see the *creationtime* of a channel
+  (used with the TimeStamp (TS) protocol - unique on
+   undernet (disables the possibility of 'net.riding'))
+ -The possibility to stop EVERY kind of channel flooding
+  by *banning* someone : Now a ban stops not only
+  part/join floods, but also message floods and even
+  nick floods!
+ -The possibility to see who did when a certain ban.
+ -The possibility to stop anyone flooding you with
+  any kind of private messages at his *own* server!
+  (This will only work when ALL servers have upgraded)
+To be able to use all of this, ftp to sg.tn.tudelft.nl
+login: ftp ; password : anything ; file: /pub/README
+Put those lines in your .ircrc initialisation file !
+Have fun, Run.
+
+----
+
+Run
+
+=============================================================================
+                       U3.1 -> U3.2    
+=============================================================================
+
+
+From: Carlo Kid - Runaway <carlo@sg.tn.tudelft.nl>
+Subject: *BUG* .U3.1 found !!
+To: wastelanders@rush.cc.edu (New Wastelanders MailingList)
+Date: Wed, 25 May 94 16:45:39 METDST
+In-Reply-To: <457.9405250732@ccws-09.brunel.ac.uk>; from "James T Lowe" at May 25, 94 8:32 am
+Mailer: Elm [revision: 66.33]
+Status: RO
+
+> :-> 
+> :-> Hiya..
+> :-> 
+> :->     Here's what I observed tonight:
+> :-> 
+> :-> *** Mmmm (mandar@roosevelt.ecn.uoknor.edu) has joined channel #friendly
+> :-> *** Users on #friendly: @Mmmm 
+> :-> *** Mode change "-o Mmmm" on channel #friendly by Uxbridge.*
+> 
+> Not surprising : 
+> 
+> #friendly  RedRum    H*  cs93jtl@ccws-09.brunel.ac.uk
+> #friendly  Emmy      H   lamphear@cheshire.oxy.edu
+> #friendly  ChemBot   H@  cmrobert@hellcat.ecn.uoknor.edu
+> 
+> 
+> 
+> >From Norman : 
+> 
+> *** ChemBot is cmrobert@hellcat.ecn.uoknor.edu (Charles Michael Roberts)
+> *** on channels: @#ChatZone 
+> *** on irc via server Norman.OK.US.undernet.org
+> *** ChemBot has been idle 10 minutes
+> 
+> 
+> and from Uxbridge : 
+> 
+> ** ChemBot is cmrobert@hellcat.ecn.uoknor.edu (Charles Michael Roberts)
+> *** on channels: @#chatZone @#friendly 
+> *** on irc via server Norman.OK.US.undernet.org
+> 
+> :-> But,
+> :-> 
+> :-> *** Mmmm has left channel #friendly
+> :-> *** Mmmm (mandar@roosevelt.ecn.uoknor.edu) has joined channel #test
+> :-> *** Users on #test: @Mmmm 
+> :-> 
+> :-> works fine..
+> :-> 
+> :-> Is this due to the U lines?  Uworld was in no way involved though :-(
+> :-> 
+> :-> I personally feel that uxbridge's retaining timestamps of old channels - 
+> :-> Run, can ya take a look asap. It can prove most distressing for our users :(
+> :-> 
+> :->                           Thanks!!
+> :-> 
+> :->                                                   Mmmm
+> 
+> 
+
+Weeehhhw, yeah a real bug :/
+
+RedRum and I looked for it for almost 4 hours before it was found...
+
+I will release .U3.2  and a patch for .U3.1-U3.2 asap...
+
+Description of bug:
+
+When someone gets kicked (and doesn't (try to) rejoin), it is flagged
+as a zombie. After a net-break, users are mutual re-joined on both
+sides of the net. It turned out that a zombie is also rejoined after
+a net rejoin.
+
+What happened with ChemBot:
+
+ChemBot was on #friendly via Norman (non TSpre8). It was banned and then
+kicked. It tried to rejoin, but Norman didn't allow that (ban).
+Delft never saw this try, and ChemBot stayed as a zombie on #friendly.
+Then Delft-UxBridge broke and reconnected... Delft did send a JOIN for
+ChemBot to UxBridge, ending up in a nick-desynced state.
+When Mmmm joined #friendly, he was the first on #friendly on all of the
+net except UxBridge... He was opped by Norman, but that is considered
+as a HACK by UxBridge and was bounced (ChemBot was still there *with*
+ops (those flags aren't reset when someone is marked zombie)).
+The second time Mmmm joined, he again got ops from Norman which now
+was accepted by UxBridge because this +o could be a BOUNCE of the de-op
+by UxBridge (Generating a BOUNCE or HACK: notice on UxBridge).
+
+Run
+
+
+
+From: Carlo Kid - Runaway <carlo@sg.tn.tudelft.nl>
+Subject: Release 2.8.19.U3.2
+To: wastelanders@rush.cc.edu (New Wastelanders MailingList)
+Date: Wed, 25 May 94 23:30:57 METDST
+Mailer: Elm [revision: 66.33]
+Status: RO
+
+Hi all,
+
+I released 2.8.19.U3.2
+
+Fixed:
+
+        - Rejoining of zombies after net break :/  (ChemBot case)
+        - Silence command now give: No such nick, when doing /silence nick
+        - I fixed the way a kick is handle, because in a last minute
+          thought I realized MURC would get trouble otherwise, see below.
+
+As usual you can get it from ftp.undernet.org:/pub/undernet/servers
+
+Patches/irc2.8.19.U3.1-2.patch     : If you already had .U3.1
+
+irc2.8.19.U3.2.tar.gz              : If start from scratch (DO SO!!!)
+
+For those who use the irc2.8.19.U3.1-2.patch ...
+
+------------------------------------------
+*** EDIT include/patchlevel.h !!!!!!!! ***
+------------------------------------------
+
+This patch will change your version to irc2.8.19.U3.2  so if you run
+ .ban  EDIT it !!!
+
+=========================================================================
+
+The change in KICK handling is as follows:
+
+- A kick received from a local client, or for a local client or
+  from a direction in which the kicked client is located, is
+  simply handled as before: completely removed from channel, no zombie.
+  This means also that there is no client-server protocol change anymore:
+  /who, /whois and /names won't change.
+
+- A kick received for a local client originating from a remote client
+  lets the server sent a PART upstream. Since this results for non TSpre8
+  servers in a remote "You're not on that channel" message, this
+  message is suppressed (would never occur anyway now we are completely
+  synced).
+
+The reason why this was needed is mainly because MURC constantly kicks
+people who have auto-rejoin disabled from different channels. With U3.1
+they would get into problems after ten channels (needed to send extra
+PART's).
+
+Run
+
+--
+-------------------------------------------------------------------------------
+|  carlo@sg.tn.tudelft.nl           |  Run @ IRC                              |
+|                                   |  Admin of Delft.NL.EU.undernet.org      |
+| * Don't expect anything of live,  |  and      Ircserver.et.tudelft.nl       |
+| or you'll miss all the rest of it.|                                         |
+-------------------------------------------------------------------------------
+
+
+
+=============================================================================
+                       U3->U4, ANTI NICK COLLIDE 
+=============================================================================
+Author: Carlo, carlo@sg.tn.tudelft.nl, Run on IRC.
+
+Hi all...
+
+After we dealt with channel msg-, join/part- and nick-floods (.bquiet),
+and with private message flooding (.silence), now in a sort of follow up
+to the anti net.break.ride (.TSpre7) and anti admin.hacks (TSpre8) we are
+about to deal with one of the last vulnerabilities of our net:
+nick-collision bots.
+Called .anc (anti nick collision).
+             -    -    -
+
+Socially spoken it does the following (I hope):
+
+- Only kills the RIGHT person, when a nick collision occurs.
+
+This would mean:
+
+A) If someone tries to harash by connecting to servers that just broke off
+and then take the nick of a person on the other side, both would be
+killed on reconnection. But with the .anc patch on both connecting servers,
+only the net.break rider will be killed.
+
+B) Secondly, when your server (or side) breaks off and you connect to some
+other server on the other side, it happens sometimes that due to lag you get
+killed by a nick collision after reconnection of the net.
+
+A and B differ strongly in the sense that in case A the *new* -the youngest-
+nick must be killed, while in case B the *old* (lagged) nick must be
+killed.
+Technically this means that we have to look at the user@host.name too.
+This gives rise to some incompatible changes, and therefor, this patch
+must be done in two steps: First we deal with the nick-collision bots and
+make the server compatible with both - the old and new protocol. And then
+once all server upgraded, we deal with the last step: the nick collision
+with yourself.
+
+In the future there will be a third possible condition in which we can have
+a nick collision: (long example follows, can be skipped)
+
+C) The net breaks, and reconnects else where, and somehow a race condition
+occurs between the 'SERVER' messages of the servers of one side.
+For example:
+
+Servers:        Part A                  Part B1                 PartB2
+Nicks           a(A),b(B)               a(A),b(B)               a(A),b(B)
+Part A breaks off Part B:
+                <-- :b QUIT             --> :a QUIT
+                <-- SQUIT serversB      --> SQUIT serversA
+Result:         a(A)                    b(B)                    b(B)
+A reconnects to Part B1, but immedeately breaks off again:
+                        -->SERVERs A
+                        -->NICK a
+                        -->:a USER ...
+Break: 
+                                                -->SERVERs A
+                                                -->NICK a
+                                                -->:a USER ...
+                                        --> :a QUIT
+                                        --> SQUIT serversA
+A connects to part B2, note that 'part B1 --> part B2' is lagged and the
+"SERVERs A ... etc" didn't arrive yet on partB2.
+Servers:        Part B1                 Part B2                 Part A
+Nicks:          b(B)                    b(B)                    a(A)
+                        -->SERVERs A
+                        -->NICK a
+                        -->:a USER ...
+                --> :a QUIT
+                --> SQUIT serversA
+                                                --> SERVERs B
+                                                --> NICK b
+                                                --> :b USER ...
+                                                <-- SERVERs A
+                                                <-- NICK a
+                                                <-- :a USER ...
+Result *before* the lagged messages arive on Part B2:
+Nicks:          b(B)                    b(B),a(A)               b(B),a(A)
+                        -->SERVERs A
+                        -->NICK a
+                        -->:a USER ...
+                        -->:a QUIT
+                        -->SQUIT serversA
+And when the lagged messages arrive on Part B2, the
+'SERVERs A' get all ignored: "server exists", even more, Part B2 disconnects 
+Part B1... :/. Now we are going to deal with the "server exists" problem
+*once* (attaching a timestamp to SERVER I think), in which case 'SERVERs A'
+would only be ignored by Part B2. Then the 'NICK a' would cause a nick
+collision with 1) Same user@host.name, 2) same server A, and 3) same
+nick-TS ! This means: We need to ignore 'NICK nick' when is has the same 
+TimeStamp and the same user@host. But when the user@host differ, two people 
+signed on at exactly the same time with the same nick and we must kill 
+*both* to avoid a desync.
+----
+
+How to handle a nick collision, general
+---------------------------------------
+
+Up till now when a nick collision occurs, both nicks (when a nick change
+from 'old' to 'new' is involved) are KILLed in ALL directions.. wiped off the
+net thus.
+But even with wiping off the net in mind, it doesn't make sense to kill in
+old direction, it is sufficient to deal with "our side" of the net, because
+every nick collision occurs on two servers, both can deal with their side.
+As an example:
+
+Servers:        A               B
+Nicks:          a(A)            a(B)
+Reconnection:
+                <-- NICK a
+                    NICK a -->
+
+As you see, if A receives the 'NICK a' from B, it only has to deal with
+its own side, because it is certain that B will receive the 'NICK a' from
+A and handle it too as a nick collision (and therefore this 'NICK a' *is*
+already a 'KILL' message).
+
+Thus, when we receive a 'NICK' that gives rise to the need of purging
+a nick on *our* side, we deal with it by doing:
+sendto_serv_butone(cptr,":%s KILL ...
+which sends the KILL to all server connections except the link 'cptr' that
+generated the nick collision.
+Also then we have to destroy the memory usage of the killed client on our
+own server, and disconnect him if it is ours, so we call exit_client().
+
+Summary so far
+--------------
+
+Ok, we discussed when to kill who. Resulting rules are:
+
+We receive a "NICK new" or ":old NICK new" from a server direction, and
+we already have a registered 'new'. Then we have a nick collison and deal
+with it as follows:
+1) If the user@host differ,
+        and our 'new' is younger or equal, KILL our 'new'.
+        and our 'new' is older, ignore the 'NICK new', but kill 'old' on
+                our side if it was a nick change.
+2) If user@host is the same:
+        and our 'new' is older, KILL our 'new'.
+        and our 'new' is younger, ignore the 'NICK new', but kill
+                'old' on our side if it was a nick change.
+        and our 'new' is equal, KILL our 'new',
+                and kill 'old' on our side too if it was a nick change.
+
+Remarks:
+        The last case, where have a ':old NICK new' collission with
+the same user@host and TimeStamp, can't be case C), but it
+is possible that *we* did send a 'NICK new', and the server at
+the other side kills 'old' off... So we have to do it too.
+        With this protocol we *ignore* 'NICK new' message, but of course
+in most cases they will be followed by at least a ':new USER ...' and
+probably
+more like ':new JOIN #...'. This would cause 'Fake direction' errors and
+the current protocol KILLs such a nick in *ALL* direction (???). Now, we
+DON'T want to KILL the nick in the right direction do we? And killing the
+fake direction nick makes no sense: it will be killed automatically due to
+the fact we did send a 'NICK new' in that direction. Thus: we can/have to
+remove the Fake Direction kills.
+        Of course, when we receive a 'NICK new hopcount :TimeStamp', we
+*can't* compare with the user@host, because it takes some time before we
+will receive the 'USER'... We also can't store the nick, because it must
+be unique. To solve this, we need to change the protocol so that 'NICK new'
+contains all information and the USER message will be redundant and removed
+in a later patch. This also reduces net.bursts.
+        
+Attaching a TimeStamp (TS) to nicks
+-----------------------------------
+
+Whenever someone takes a new nick, which is available of course, either by
+changing nick or by signing on, the local server attaches a TimeStamp (TS)
+to the nick. Now there will be sent:
+
+NICK new hopcount TS user host.name server.name :Real name
+or
+:old NICK new :TS
+
+This is 100% compatible with the existing protocol.
+
+When a server receives such a nick from a neighbouring server it copies the
+TS, keeping track of the local change time. (When not all servers have
+upgraded, and no TS is received, the .anc server will fill in the time
+itself - being a slight advantage over keeping it 0. It also will assume 
+that the host.names are equal or not equal resulting a as many kills as 
+needed in the worst case).
+
+
+Examples
+--------
+
+Servers:    A                     B
+Nicks:      a(A),b(B)             b(B),a(A)
+Both change simultaneously to nick 'c', but 'a' slightly faster (at time=1,
+and b at time=2):
+            c(A),b(B)             c(B),a(A)
+                 -> :a NICK c :1
+                 :b NICK c :2 <-
+Then A receives a ':b NICK c :2' where 2 > 1, and KILLs b on its own side.
+B however receives ':a NICK c :1' where 1 < 2, and KILLs c on its own side.
+Result:     c(A)                  c(A)
+
+Due to 'lag', more :c PRIVMSG .. from B to A can follow, resulting in a
+fake direction. 'A' will simply ignore them and not kill c (kills for
+fake direction are nonsense anyway).
+
+In the case that someone signs on, taking the same nick as a nick change
+we have almost the same:
+
+Servers:    A                     B
+Nicks:      a(A)                  a(A)
+'a' changes simultaneously to nick 'c', but slightly faster (at time=1),
+as a new 'c' signs on at B (time=2).
+            c(A)                  a(A),c(B)
+                -> :a NICK c :1
+                  NICK c 1 :2 <-
+Then A receives a 'NICK c 1 :2' where 2 > 1, and ignores it simply.
+B however receives ':a NICK c :1' where 1 < 2, and KILLs c on its own side.
+Result:     c(A)                  c(A)
+
+If the new 'c' was a little bit earlier, we get:
+
+Servers:    A                     B
+Nicks:      a(A)                  a(A)
+'a' changes simultaneously to nick 'c', and slightly slower (at time=2),
+as a new 'c' signs on at B (time=1).
+            c(A)                  a(A),c(B)
+                -> :a NICK c :2
+                  NICK c 1 :1 <-
+Then A receives a 'NICK c 1 :1' where 1 < 2, and KILLs c on its own side.
+B however receives ':a NICK c :2' where 2 > 1, and KILLs a on its own side.
+
+Result:     c(B)                  c(B)
+
+Last case, two people sign on (or during a net reconnection):
+
+Server:     A                     B
+Sign on:    c(A)                  c(B)
+                -> NICK c 1 :1
+                   NICK c 1 :2 <-
+Then A receives 'NICK c 1 :2' where 2 > 1, and ignores it.
+and B receives a 'NICK c 1 :1' where 1 < 2, and KILLs c on its own side.
+Result:     c(A)                  c(A)
+
+Note: the above didn't take equal TS's into account, and I assumed
+user@hosts to be different: the nick collision bot cases.
+
+A last possibility when someone starts hacking... a 'NICK new' twice
+from the same direction, should not be accepted: we kill the earlier one
+always.
+
+Compatibility problems
+----------------------
+
+In the future, we want to also take 'user@host' into account... Therefor,
+we need to start to ignore 'NICK new' and only act upon ':new USER ...'.
+We can only do that if also 'USER contains the hopcount and TimeStamp'...
+If we change the protocol immedeately to say:
+:nick USER user host.name server.name hopcount TimeStamp :Real name
+the 'hopcount' would be treated as realname, and we the rest would be
+lost :(
+
+We can also transfer the info to 'NICK', with:
+
+:server.name NICK nick hopcount user host.name TimeStamp :Real name
+
+and later forget the USER message. Although someone lamer uses
+the C source line " if (sptr == cptr) ..." in m_nick() to determine if
+it was a 'NICK new' or a ':old NICK new' :/ Geesh (unlogical). He should
+have used " if (IsServer(sptr)) ...". You would need three upgrade steps
+or we will have to do with:
+NICK nick hopcount user host.name server.name TimeStamp :Real name
+
+The nice thing about this is, that we can check how many parameters we
+receive and then immedeately use the user@host if it is there... That way
+the .acn will immedeately work once everyone upgraded once, and the second
+step would only get rid of the 'USER' line between servers.
+
+Run
+
+
+=============================================================================
+                                WALLOPS
+=============================================================================
+Usage: /WALLOPS <message>
+
+Sends a message to IRC ops on-line. Remember that users who are /umode +w
+can see wallops as well.
+
+
+=============================================================================
+                                STATS W
+=============================================================================
+Author: Michael Vanloon (michaelv@iastate.edu) - mlv on IRC  
+Help on /stats w :
+
+I've been working on something I think would be quite a useful
+addition to the ircd.  It keeps track of the average number of local
+clients, total clients, and total connections (including servers) over
+various periods of time, currently over the last minute, hour, day and
+week.  It is invoked by "/stats w server.name".  You may try it
+yourself by "/stats w *.iastate.edu".  A sample from
+ircserver.iastate.edu looks like this:
+
+*** Minute    Hour      Day       Week      Userload for:
+***  44.91     39.4      33        33       iastate.edu clients
+*** 114.40    103.2      69        65       total clients
+*** 120.40    109.0      73        70       total connections
+*** * End of /STATS report
+
+I'm debating changing it to show average connections over the last
+minute, hour, day, prev. day, and prev. day, as I think the data
+doesn't change enough after that to really be useful to justify
+keeping it over an entire week.
+
+On smaller, less used servers, it should add a negligible amount to
+the resident memory consumed by the ircd.  On a large hub such as the
+*.bu.edu servers, penfold, or ircserver.iastate.edu, it might add as
+much as 300k to the amount of memory the ircd attempts to keep
+resident.  The amount is determined solely by the number of
+connects/disconnects the server processes over the span of time
+measured.
+
+The code is bulletproof and has undergone *extensive* debugging and
+testing before I announced it here.
+
+The reason I'm posting this is because I would like to know how many
+people think this would be a useful addition to the server.  In
+addition, I'd like feedback on whether you think this should be a
+standard part of the distributed server code.  I think it should, but
+Avalon wants me to post here first and see how others feel about it.
+I'd appreciate your input.
+
+I will be making a patched 2.7.2 server available with this included,
+for those who would like to have this and stability too.  I'll also be
+hooking it into 2.8.x soon, and giving it back to Av to include in the
+standard 2.8 distribution as it matures, if he sees fit to do so.
+
+Thanks for your time...
+
+                                --Michael (mlv)
+
+IRC log started Wed Aug 18 21:52
+*** Value of LOG set to ON
+*mlv* it's the usage of your server
+*mlv* average number of users on your server over the last minute, hour, day, yesterday, and the day before
+*mlv* local clients, total clients, and total connections (clients + servers)
+-ircserver.iastate.edu- Minute   Hour  Day  Yest.  YYest.  Userload for:
+-ircserver.iastate.edu-  23.00   23.0   16    17      11   iastate.edu clients
+-ircserver.iastate.edu-  52.00   52.8   37    35      23   total clients
+-ircserver.iastate.edu-  61.00   61.7   45    42      21   total connections
+-> *mlv* hmm...so iastate had 23 local clients in the last minute?
+*mlv* right... in the last minute the average number of local users on our server was 23
+*mlv* 23.45 actually
+-> *mlv* okie...gotcha... thanks :)   one other thing
+*mlv* there were an average of 23.1 local users on here over the last hour
+*mlv* shoot
+-> *mlv* is it possible to specify multiple domains?
+-> *mlv* for e.g.  uoknor.edu  and  okstate.edu    cos those will be local to midway
+*mlv* it could be coded in, but 1) my code doesn't support it out of the box, and 2) that would add more state info which would increase the memory usage a bit
+-> *mlv* hmm...
+*mlv* it's purely informational... i wouldn't worry about it, really that much
+-> *mlv* okay...also, the Makefile on the ftp site seems hosed.....there's junk at the end...I tried both the .Z and the .gz
+*mlv* i'm thinking about making it log by connection class... but i'll have to use a more efficient statistical algorithm (less precise) if i do that
+*mlv* that way you could put all the local domains into certain classes
+*mlv* oh yeah... it's harmless, just weird
+-> *mlv* that'll work :)
+-> *mlv* well...thanks for your help....will have a look at the stats w patch when you're finished with it :)
+IRC Log ended *** Wed Aug 18 22:22
+
+
+=============================================================================
+                        BAN/TOPIC/SIGNON INFO
+=============================================================================
+Author: Paul Foley (pfoley@kauri.vuw.ac.nz)  SIO on IRC
+
+Help on Ban/Topic/Signon :
+
+Since these patches allow the server to maintain additional information, the
+server replies have been changes for the /mode #channel +b (#367), /whois
+(#317) and an additional reply #333 has been added for topic info. The time
+is returned as a long integer in UTC format in all cases. Since the existing
+clients will ignore this additional information, you will need to either
+patch the client, or in case you're using ircII, use the foll. /on statements
+to take benefit of these patches :
+
+on ^367 * if ([$4] != []) {echo *** $1 \($3 - $stime($4)) $2} {echo *** $1-}
+on ^333 * echo *** Topic for $1 set by $2 on $stime($3)
+on ^317 * if (index(012345679 $3) != -1) {echo *** $1 has been idle for $2 seconds.  Signon at $stime($3)} {echo *** $1 has been idle for $2 seconds.}
+
+
+Once you have done this, you can see info as follows:
+/mode #wasteland +b
+*** #wasteland (Mmmm - Thu Aug 19 04:44:24 1993) test!*@*
+
+/topic #wasteland
+*** Topic for #wasteland: We all love Axl Rose!
+*** Topic for #wasteland set by rbarnes on Thu Aug 19 04:26:56 1993
+
+/whois Mmmm
+*** Mmmm is mandar@essex.ecn.uoknor.edu (Mmmm,I get high with a little help
++from my friends)
+*** on channels: @#wasteland
+*** on irc via server essex.ecn.uoknor.edu (MIDWEST HUB..HELPS YOU GET THERE
++SOONER)
+*** Mmmm is an IRC Operator
+*** Mmmm has been idle for 454 seconds.  Signon at Wed Aug 18 23:47:19 1993
+
+
+=============================================================================
+                        CLIENT NOTIFY
+=============================================================================
+Authors: Patrick Ashmore (pda@engr.engr.uark.edu) - Twilight1 on IRC
+         Mandar Mirashi  (mmmirash@mailhost.ecn.uoknor.edu) - Mmmm on IRC
+         Tony Vencill    (vencill@iastate.edu) - Tony/Tonto on IRC
+
+Help on Client Notify:
+
+This patch allows all opers on your server to see clients connecting to your
+server and disconnecting from it (with the reason why they disconnected). 
+This can help you identify troublesome clients, or redirect remote clients
+to closer servers, or troubleshoot the reason why a client disconnected.
+
+A sample output:
+
+*** Notice -- Client connecting : Karll (agifford@sci.dixie.edu).
+
+*** Notice -- Client exiting : Karll (agifford@sci.dixie.edu) [Bad link?].
+
+PS: if you wish to selectively decide when you wish to see these connection
+notices, use the foll. script
+
+on ^server_notice "% % NOTICE -- CLIENT*" if (hideit != 1) {echo *** $2-}
+alias show @ hideit = 0;echo *** You can now see clients connecting/exiting
+alias hide @ hideit = 1;echo *** You will no longer see clients connecting/exiting 
+
+If you then wish to not see client connects/exits when you are opered, simply
+type /hide. If you wish to see them again, type /show.
+
+=============================================================================
+                        TRACE TIMES
+=============================================================================
+Author: Tony Vencill    (vencill@iastate.edu) - Tony/Tonto on IRC
+
+Help on Trace Time:
+
+  This useful patch lets you identify the times since your server last
+heard from any connected servers or clients. This time is displayed in
+seconds, appended to each line of your /trace output. It can be very
+helpful in identifying which servers are going to drop off or which
+clients may ping timeout from your server.
+
+A sample output:
+
+/trace essex*
+*** Serv [30] ==> 10S 8C cancun.caltech.edu *!*@essex.ecn.uoknor.edu 73
+*** Serv [30] ==> 9S 6C imageek.york.cuny.edu *!*@essex.ecn.uoknor.edu 27
+*** Serv [0] ==> 1S 0C inga1.acc.stolaf.edu[130.71.192.16]
++*!*@essex.ecn.uoknor.edu 58
+*** Serv [0] ==> 1S 0C shadow.acc.iit.edu *!*@essex.ecn.uoknor.edu 97
+*** Serv [0] ==> 1S 2C curie.ualr.edu Mmmm!mmmirash@essex.ecn.uoknor.edu 98
+*** Serv [0] ==> 1S 1C piaget.phys.ksu.edu *!*@essex.ecn.uoknor.edu 117
+*** Oper [0] ==> Mmmm[essex.ecn.uoknor.edu] 0
+*** Serv [50] ==> 1S 0C pv1629.vincent.iastate.edu *!*@essex.ecn.uoknor.edu 7
+*** Class 0 Entries linked: 6
+*** Class 50 Entries linked: 1
+*** Class 30 Entries linked: 2
+
+
+=============================================================================
+                       K- line comments
+=============================================================================
+Author: Mandar Mirashi (mmmirash@mailhost.ecn.uoknor.edu) - Mmmm on IRC
+
+This extremely useful patch allows you to specify either a comment or an
+interval in the 2nd field of the K line (instead of the previous format
+of just a restricted interval). The "comment" can even be configured to
+be a *file* name which can then be displayed to the client rejected via
+the K line. All existing K lines will work as they are. This patch is
+an *enhancement* to the K-lines.
+
+e.g. (of a comment field)
+
+K:*.sdsu.edu:Flooding.is.not.cool.lamer:masc0482
+
+As far as possible, do not use a white space in the comment field, because
+this breaks ircII's /stats k handling. You can use the period (.) or the
+underscore instead (_).
+
+e.g (of a file to be output to a rejected client 
+     -   #define COMMENT_IS_FILE  in config.h)
+
+K:*.netcom.com:/ecn/staff0/irc/servers/vinson/sorry.txt:*
+
+
+=============================================================================
+                               OPER FAIL
+=============================================================================
+Authors: Michael Vanloon (michaelv@iastate.edu) - mlv on IRC  
+         Jon C Green (jcgreen@iastate.edu) - Jon2 on IRC
+        Bryan Collins (b@ctpm.org) - bwy on IRC
+
+This patch notifies you if someone tries to gain oper on your server and
+fails. The notice goes out only to the operators on the server.
+
+*** Notice -- Failed OPER attempt by M (mmmirash@lincoln.ecn.uoknor.edu)
+[crackit]
+
+
+=============================================================================
+                               MIXED CASE
+=============================================================================
+Authors: Michael Vanloon (michaelv@iastate.edu) - mlv on IRC
+         Jon C Green (jcgreen@iastate.edu) - Jon2 on IRC
+
+"Here's a patch mlv and I wrote that prevents clients with mixed-case usernames
+from connecting.  I don't know of many sites that allow mixed-case, so it
+is effective for stopping many clonebot attacks and also stops many
+would-be username hackers."  - Jon2
+
+This has been slightly modified by Mmmm to give an option of ignoring the
+case of the first character if desired (useful for those PC users who
+intuitevely enter their first name with the first letter capitalised).
+
+e.g.
+*** Notice -- Invalid username: buankBOT[saucer.cc.umr.edu]
+
+                               
+=============================================================================
+                               NOTE
+=============================================================================
+
+Usage:
+  \ 2NOTE\ 2 USER [&passwd] [+-flags] [+-maxtime] <nick!username@host> <msg>
+-   or  SEND|SPY|FIND|WAITFOR|NEWS <same as USER args.>
+*   or  SEND|SPY|FIND|WAITFOR|WALL|WALLOPS|DENY|NEWS|KEY <see USER args.>
+  \ 2NOTE\ 2 LS|COUNT|RM|LOG [&pwd][+-flags][#ID] <nick!user@host> [date]
+  \ 2NOTE\ 2 FLAG [&passwd] [+-flags] [#ID] <nick!username@host> <+-flags>
+*  \ 2NOTE\ 2 SENT [NAME|COUNT|USERS] <f.nick!f.name@host> <date> [RM]
+-  \ 2NOTE\ 2 STATS [MSM|MSW|MUM|MUW|MST|MSF|USED]
+-  \ 2NOTE\ 2 SENT [NAME|COUNT]
+*  \ 2NOTE\ 2 STATS [MSM|MSW|MUM|MUW|MST|MSF|USED|RESET] [value]
+*  \ 2NOTE\ 2 SAVE
+
+  The Note system have two main functions:
+  1. Let you send one line messages to irc users which 
+     they will get when they next sign on to irc.
+     Example: NOTE SEND <nick> Hi, this is a note to you.
+  2. Let you spy on people, to see when they sign on or off,
+     change nick name or join channels.
+     Example: NOTE SPY +100 <nick>  (spy on nick for 100 days)
+
+  You may fill in none or any of the arguments listed above, including
+  * or ? at any place, as nick@*.edu, !username, ni?k!username etc...
+  Other usefull features may be NOTE WAIT <nick>, making nick and
+  you get a message when you both are on at the same time.
+  Note was developed 1990 by jarle@stud.cs.uit.no (Wizible on IRC).
+
+
+*Usage: NOTE [<server>] ANTIWALL
+*  Switch off b flag for wall's which you have received on specified
+*  server. The person who queued the wall would be notified about
+*  the antiwall, and who requested this.
+
+
+Usage: NOTE COUNT [&<passwd>] [+|-flags] [#<ID>] <nick!username@host>
+  Displays the number of messages sent from your nick and username. See
+  HELP LS for more info. See HELP FLAG for more info about flag setting.
+
+
+*Usage: NOTE DENY [&<passwd>] [+|-<flags>] [+|-<maxtime>]
+*              <nick!user@host> <msg>
+*  DENY is an alias for USER +RZ (default max 1 day)
+*  This command makes it impossible for any matching recipient to
+*  queue any Note requests until timeout.
+
+
+Usage: NOTE FIND [&<passwd>] [+|-<flags>] [+|-<maxtime>]
+               <nick!username@host> <msg>
+  FIND is an alias for USER +FLR (default max 1 day)
+  This command makes the server search for any matching recipient, and
+  send a note message back if this is found. If <msg> field is used, this 
+  should specify the realname of the person to be searched for. Examples:
+    FIND -4 foo*!username@host
+    FIND @host Internet*
+    FIND nicky Annie*       
+    FIND +7 * Annie*
+
+
+Usage: NOTE FLAG [&<passwd>] [+|-<flags>] [#<ID>]
+               <nick!username@host> <+|-flags>
+  You can add or delete as many flags as you wish with +/-<flag>.
+  + switch the flag on, and - switch it off. Example: -S+RL
+  Following flags with its default set specified first are available:
+    -S > News flag for subscribing.
+    -M > Request is removed after you sign off.
+    -Q > Ignore request if recipient's first nick is equal to username.
+    -I > Ignore request if recipient is not on same server as request.
+    -W > Ignore request if recipient is not an operator.
+    -Y > Ignore request if sender is not on IRC.
+    -N > Let server send a note to you if message is delivered.
+    -D > Same as N, except you only get a message (no queued note to you).
+    -R > Repeat processing the request until timeout.
+    -F > Let server send note info for matching recipient(s). Any message
+         part specify what to match with the realname of the recipient. 
+    -L > Same as F, except you only get a message (no queued note to you).
+    -C > Make sender's nicks be valid in all cases username@host is valid.
+    -V > Make sender's "nick*" be valid in all cases username@host is valid.
+    -X > Let server display if recipient signs on/off IRC or change
+         nickname. Any message specified is returned to sender.
+    -A > Show what server matching user is on using X flag.
+    -J > Show what channel matching user is on using X flag.
+    -U > Do not display nick-change using X flag.
+    -E > Ignore request if nick, name and host matches the message text
+         starting with any number of this format: 'nick!name@host nick!... '
+*    -B > Send a message to every account who match the nick!user@host 
+*         This creates a received list with flag H set. (see LS +h)
+*    -T > Send a message not all nicks on same accounts too using B flag.
+*    -K > Give keys to unlock privileged flags by setting that flags on.
+*         The recipient does also get privileges to queue unlimited 
+*         numer of requests, list privileged flags and see all stats.
+*    -Z > Make it impossible for recipient to queue anything at all.
+  Other flags which are only displayed but can't be set by user:
+    -O > Request is queued by an operator.
+    -G > Notice message is generated by server.
+-    -B > Broadcasting message.
+*    -H > Flag list for who's received Broadcast message (B flag).
+-  Notice: Message is not sent to recipient using F, L, R or X flag.
+-  Using this flags, no message needs to be specified.
+*  Notice: Message is not sent to recip. using F, L, R, X, K, Z or H
+*  flag (except if B flag is set for R). For this flags, no msg. needed.
+
+  Examples:
+    FLAG * +cj     : Switch on c and j flag for all requests.
+    FLAG +x * +c   : Switch on c flag for all req. which have x flag.
+    FLAG nick -c+j : Switch off c flag and which on j flag for nick
+
+
+*Usage: NOTE KEY [&<passwd>] [+|-<flags>] [+|-<maxtime>] <nick!user@host>
+*  KEY is an alias for USER +KR (default max 1 day)
+*  This command is for allowing no-opers to use oper-options by specifying
+*  the flag to unlock. Be careful with this option!
+*  Example: KEY +365 +s * would make it possible for everybody to use s flag.
+
+
+Usage: NOTE LOG [&<passwd>] [+|-<flags>] [#<ID>] <nick!username@host>
+  Displays how long time since matching person was on IRC. This works 
+  only after use of NOTE SPY. The log is protected to be seen for other
+  users than the person who queued the SPY request. To get short
+  output, do not specify any arguments. Example:
+    LOG      : Print short log of all
+    LOG *    : Print long log including real names of all
+    LOG nick : Print long log for user nick.
+
+
+Usage: NOTE LS [&<passwd>] [+|-<flags>] [#<ID>]
+               <nick!username@host> [<date>]
+  Displays requests you have queued. No arguments would show you
+  all requests without the message field.
+  Use flags for matching all messages which have the specified flags set
+  on or off. See HELP NOTE FLAG for more info about flag settings. Time 
+  can be specified on the form day.month.year or only day, or day/month, 
+  and separated with one of the three '.,/' characters. You can also 
+  specify -n for n days ago. Examples: 1.jan-90, 1/1.90, 3, 3/5, 3.may.
+  If only '-' and no number is specified max time is set to all days.
+  The time specified is always the local time on your system. Example:
+    LS !user    would show you all requests to username@*
+    LS +x       would show all your SPY requests.
+    LS #300     would show you only request #300.
+
+
+Usage: NOTE NEWS [&<passwd>] [+|-<flags>] [+|-<maxtime>]
+               <group!username@host>
+  NEWS with no message is an alias for USER +RS (default max 60 days)
+  This command is for subscribing on a specified newsgroup from any
+  user(s) or host(s). Wildcards may be used anywhere. Example:
+    NEWS irc.note       : Subscribe on irc.note
+*    NEWS irc.note@*.no  : Send to group irc.note, but only for
+*                          users at host *.no
+*    NEWS irc.note       : Send to all for group irc.note
+*    NEWS Users@*.edu Hi : Send Hi to all users using note in your
+*                          server located at host *.edu.
+   (Advanced users may use User +rs <...> <filter> where filter is a 
+   string which must matches with field in received news message)
+-  Only opers can send news as default.
+*  To send news add message and use same format as subscribing, except 
+*  that username field must matches with subscribed group as alt.irc!*.irc - 
+*  everybody subscribing on a*.irc or *.irc or alt.irc... would get the news.
+*  A speciall case is the group Users which everybody using note in the server
+*  are member of.
+
+
+Usage: NOTE RM [&<passwd>] [+|-<flags>] [#<ID>] <nick!username@host>
+  Deletes any messages sent from your nick and username which matches
+  with nick and username@host. Use flags for matching all messages which
+  have the specified flags set on or off. See HELP FLAG for more info
+  about flag settings, and HELP LS for info about time.
+
+
+*Usage: NOTE SAVE
+*  SAVE saves all messages with the save flag set. Notice that the
+*  messages are automatically saved (see HELP STATS). Each time server is
+*  restarted, the save file is read and messages are restored. If no users
+*  are connected to this server when saving, the ID number for each
+*  message is renumbered.
+
+
+Usage: NOTE SEND [&<passwd>] [+|-<flags>] [+|-<maxtime>]
+               <nick!username@host> <msg>
+  SEND is an alias for USER +D (default max 60 days)
+  This command is for sending a message to recipient, and let the server
+  send a note + a notice to sender if this is on IRC - if message is sent.
+    SEND foobar Hello, this is a test.
+    SEND +7 !username@*.edu Hello again!
+
+
+-Usage: NOTE SENT [NAME|COUNT]
+*Usage: NOTE SENT [NAME|COUNT|USERS] <f.nick!f.name@host> <date> [RM]
+  Displays host and time for messages which are queued without specifying
+  any password. If no option is specified SENT displays host/time for
+  messages sent from your nick and username.
+  NAME displays host/time for messages sent from your username
+  COUNT displays number of messages sent from your username
+*  USERS Displays the number of messages in [], and names for all users
+*  who have queued any message which matches with spec. nick/name/host.
+*  RM means that the server removes the messages from the specified user.
+
+
+*Usage: NOTE SERVICE <nick> <note command>
+*  Useful in robots. Note will take the requests as if from <nick>
+
+
+Usage: NOTE SPY [&<passwd>] [+|-<flags>] [+|-<maxtime>]
+               <nick!username@host> [msg]
+  SPY is an alias for USER +RX (default 1 max day)
+  SPY makes the server tell you if any matching recipient sign(s)
+  on/off IRC or change nick name. No message needs to be specified.
+  However, if a message is specified this is returned to sender including
+  with the message about recipient. Message could for example be one or
+  more Ctrl-G characters to activate the bell on senders machine.
+  As an alternative for using C flag, <msg> field could start with
+  any number of nicks on this format: %nick1 %nick2... %nickn, with
+  no space between % and the nick name you use. Spy messages would be
+  valid for any of the nicks specified.
+  SPY with no argument would tell you what users you have spy on who are 
+  currently on IRC. The system logs last time the last matching person was 
+  on IRC for each SPY request is queued in the server. See NOTE LOG for this.
+  You may use flag +A to see what server matching user is on, 
+  and/or +J flag to see what channel. (Read HELP NOTE USER for more). Example:
+    SPY foobar!username@host <ctrl-G>
+    SPY +10 foobar
+    SPY +aj &secret * <ctrl-G>
+    SPY +365 +e !user nick!*@* <ctrl-G>
+    SPY % +7 foo!user
+    SPY +5 nicky %mynick %meenick
+
+
+-Usage: NOTE STATS [MSM|MSW|MUM|MUW|MST|MSF|USED]
+*Usage: NOTE STATS [MSM|MSW|MUM|MUW|MST|MSF|USED|RESET] [value]
+  STATS with no option displays the values of the following variables:
+    MSM: Max number of server messages.
+    MSW: Max number of server messages with username-wildcards.
+    MUM: Max number of user messages.
+    MUW: Max number of user messages with username-wildcards.
+    MST: Max server time.
+    MSF: Note save frequency (checks for save only when an user register)
+  Notice that 'dynamic' mark after MSM means that if there are more
+  messages in the server than MSM, the current number of messages are
+  displayed instead of MSM.
+  Only one of this variables are displayed if specified.
+*  You can change any of the stats by specifying new value after it.
+*  RESET sets the stats to the same values which is set when starting the
+*  server daemon if no note file exist. Notice that this stats are saved
+*  in same file as the other messages.
+
+
+Usage: NOTE USER [&<passwd>] [+|-<flags>] [+|-<maxtime>]
+               <nick!username@host> <msg>
+  With USER you can queue a message in the server, and when the recipient
+  signs on/off IRC, change nick or join any channel, note checks for
+  valid messages. This works even if the sender is not on IRC. See HELP
+  FLAGS for more info. 
+  Password can be up to ten characters long. You may specify password 
+  using the &, % or $ character. & is equal to to $, except working much
+  better cause client use $ for other things...
+  The % character works like &, except it makes the queuing silent. It
+  makess also sense to use this without any following password.
+  If any request queued is equal to any previous except time and maxtime,
+  only maxtime is changed as specified. You then get "Joined" instead of
+  "Queued". 
+  HELP FLAGS for info about flag settings. Username can be specified
+  without @host. Do not use wildcards in username if you know what it
+  is, even if it's possible. Max time before the server automatically
+  remove the message from the queue, is specified with hours with a
+  '-' character first, or days if a '+' character is specified, as
+  -5 hours, or +10 days. Default maxtime is 7 days.
+  Note: The received message is *directly* displayed on the screen,
+  without the need for a read or remove request.
+    NOTE USER &secret +WN +10 Wizible!jarlek@ifi.uio.no Howdy!
+  is an example of a message sent only to the specified recipient if
+  this person is an operator, and after receiving the message, the server
+  sends a note message back to sender to inform about the delivery.
+    NOTE USER +XR -5 Anybody <ctrl-G>
+  is an example which makes the server to tell when Anybody signs
+  on/off irc, change nick etc. This process repeats for 5 hours.
+    NOTE USER +FL @*.edu *account*
+  is an example which makes the server send a message back if any real-
+  name of any user matches *account*. Message is sent back as note from
+  server, or directly as a notice if sender is on IRC at this time.
+
+
+Usage: NOTE WAITFOR [&<pwd>] [+|-<flags>] [+|-<maxtime>]
+               <nick!username@host> [<msg>]
+  WAITFOR is an alias for USER +YD (default max 1 day)
+  Default message is [Waiting]
+  This command is for telling the recipient if this appears on IRC that
+  you are waiting for him/her and notice that this got that message. Example:
+    WAITFOR foobar
+    WAITFOR -2 foobar!username@*
+    WAITFOR foobar Waiting for you until pm3:00..
+
+
+*Usage: NOTE WALL [&<passwd>] [+|-<flags>] [+|-<maxtime>]
+*                      <nick!user@host> <msg>
+*  WALL is an alias for USER +BR (default max 1 day)
+*  This command is for sending a message once to every matching user
+*  on IRC. Be careful using this command. WALL creates a list of 
+*  persons received the message (and should not have it once more time)
+*  with H flag set. This list can be displayed using ls +h from the
+*  nick and username@host which the WALL request is queued from.
+*  Removing the headers (H) before WALL request is removed would cause
+*  the message to be sent once more to what users specified in list.
+*  WALL +7 @*.edu Do not do this! - Makes it clear for all users using 
+*  IRC on host @*.edu the next 7 days how stupid it is to send such WALL's ;) 
+
+
+*Usage: NOTE WALLOPS [&<passwd>] [+|-<flags>] [+|-<maxtime>]
+*              <nick!user@host> <msg>
+*  WALLOPS is an alias for USER +BRW (default max 1 day)
+*  This command is same as WALL, except only opers could receive it.
+=============================================================================
diff --git a/doc/history/history.pre24 b/doc/history/history.pre24
new file mode 100644 (file)
index 0000000..cac4d30
--- /dev/null
@@ -0,0 +1,51 @@
+/************************************************************************
+ *   IRC - Internet Relay Chat, doc/HISTORY
+ *   Copyright (C) 1990
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 1, or (at your option)
+ *   any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+HISTORY of Recent IRC Versions.
+
+Previous version numbering schemes have caused some confusion, which this
+document attempts to resolve.
+
+The original test versions released by WiZ were numbered 2.01?6 where
+the ? refers to a letter.  The last known stable version was U6.
+Version 2.1.0/1 was rewritten by Mike Bolotski from the U6 sources but 
+several bugs were introduced during the rewrite.  After several weeks, 
+almost all servers backed up to U6.  Version v6 contained comparatively 
+minor modifications from U6.  
+
+Version 2.2 consists of the v6 source repackaged into multiple directories, 
+and with modified documentation.  From now on, the version number will
+stay relatively constant.  As minor changes and bug fixes are added, they
+will be distributed in the form of context diffs, to be applied with the
+'patch' command.  Each bugfix will bump the patchlevel (PL) of the release
+by 1.  The PL is documented in the version.c file in the lib/misc directory.
+
+Version 2.3 was unfortunate mistake containing copyright violations
+so it was soon taken off distribution.
+
+Version 2.4 contains *very* many bug fixes, enhancements, and "hooks" for
+use in future releases. The source tree has been restructured, and the
+Makefiles rewritten to be recursive and follow the new source tree layout.
+
+Version 2.5 contains string channels and channel modes (as well as
+channel operators). Also Wizible's MAIL system was included as an option.
+
+Hopefully, whoever provides a fix will also update the respective
+ChangeLogs to summarize the changes, as well as adding a description of
+the bug to the BugList file.
diff --git a/doc/history/overview.u2.9 b/doc/history/overview.u2.9
new file mode 100644 (file)
index 0000000..e677058
--- /dev/null
@@ -0,0 +1,206 @@
+Hi fellow undernetters,
+
+I forgot if it was requested on routing-com or here, but you won't see me
+cross posting, so I did choose 'wastelanders'.
+
+The request was to mail an overview of the changes 2.8 ==> u2.9,
+especially for the new Opers, but also as a reminder for others.
+
+The patch file from irc2.8.21.mu3.1 to ircu2.9.17.mu is 446652 bytes.
+So you will understand I can't cover every little change.
+
+New commands
+------------
+
+/UPING <server.to> [<port>] [<server.from>] [<number of packets>]
+
+Sends <number of packets> (default 5, max 20) size 1024 bytes, from (remote)
+server <server.from> (default local server) to <server.to>. The default
+port is 7007 and the same on all servers. If a server is down, you can
+still use port 7 (echo). Also 2.8 echo's, on port PORTNUM (config.h).
+UPING uses udp, you need CN lines (masks as server names are allowed) but
+the connection doesn't have to exist already.
+
+/RPING <server.to> [<server.from>] [<Optional remark>]
+
+Sends one 'RPING' message using the irc protocol over an existing link.
+It allows to measure the lag of remote links, respons is in ms accuracy.
+The <Optional remark> can be used to measure to total pingtime to your
+client (like the CTCP PING) or to add a serial number for automation.
+
+/MAP [server.mask]
+
+Shows a map in the layout as Router.
+
+/SETTIME
+
+Only for debugging, isn't needed. (Oper only).
+
+Changed commands
+----------------
+
+/CONNECT
+
+No doubt the biggest impact of 2.9 is on connecting:
+When the link is physically possible, your /connect ALWAYS succeeds
+except when an H: or L: line somewhere on the net forbids it, or when
+*after* your connect another connect is done that cause a loop. The only
+restriction is that you are not allowed to make deliberately a loop:
+you must first squit. Loops only happen when to connects are done
+simultaneously and the SERVER messages had not yet time to propagate
+over the whole net.
+When a connect (manual or automatically) is done for a link that used
+to get "server exists", with 2.9 the Ghost is squitted off the net,
+making it possible to recover faster from breaks caused by bad links.
+If on the other hand a loop occurs because two parts connect at two
+points, the servers that detect the server nick collision will squit
+the most logical link to break the loop, and only one link. This results
+thus in a connected net one way or the other (for this all 2.8 servers need
+to be off the net! Till that time the net will connect and then break
+at two places, giving more messages then right now with only 2.8).
+2.9 servers also notify the Opers (or users with +s) about net.junctions
+and net.breaks. It does this even better then Router: A lot faster, always
+correct (REAL junctions), and independent of Router: You will also see
+them when Router is 'on the other side'.
+
+/TIME
+
+Has changed. Now also shows the system clock / TimeStamp clock offset.
+
+/MODE +b
+
+You only have to be joined, not be chan op anymore.
+
+/MODE <nick> +d
+
+Makes the user 'Deaf'. Needed for the channel registration service.
+Channel messages are not routed to a Deaf person decreasing bandwidth use.
+
+/LINKS
+
+Output also shows used protocol for that link.
+
+New numerics
+------------
+
+RPL_MAP, RPL_MAPMORE, RPL_MAPEND and RPL_TRACEPING.
+
+Bug fixes
+---------
+
+- A handshaking link doesn't pingtime out; That can interfere with
+  slow nameserver lookups.
+
+- U: lines (and K: lines) now active directly after a /rehash
+
+- Don't bind() a socket before connect(), thats useless on machines
+  with just one ip number (like we all have), and can confuse
+  some OS's I found out.
+
+Significant Patches
+-------------------
+
+The following patches have been the objective. To realize them I needed to
+rewrite and change huge other parts of the code also, because lot of the code
+in 2.8 is under great tension of re-re-re-patches.
+
+- Rewrote m_server. Objective:
+  = Allow ghosted servers to reconnect (solution "server exists").
+  To allow for this:
+  - Added a timestamp to SQUIT, this timestamp functions as a label
+    which matches the corresponding SERVER (connect).
+  - Added a prefix for every message, absolutely necessary to keep track
+    of the correct order (direction actually).
+
+- The oci has been added (oper sees invisibles on own server).
+
+- A new NOTE is added, many bugs removed and extremely speeded up due to
+  a better interface with the rest of the code.
+
+- The TimeStamp clocks are now automatically synchronized, so a wrong
+  system clock isn't a problem anymore.
+
+- Added a Protocol-version and detection. This allows protocol changes
+  with a *MUCH* higher backwards compatibility.
+
+- Server now keeps track of the server map. This allowed for /MAP and
+  a lot of speed ups (don't have to scan through all clients to find a
+  server) but much more important: The disconnect burst could be brought
+  back to ONE message (instead of a QUIT for ever single client).
+  Apart from decreasing bandwidth use, this was necessary for other
+  important protocol changes, and even more to allow important future
+  changes that will reduce the connect.burst as well. The most important
+  current impact is that it allows SQUIT to travel down stream AND up stream.
+  Because directionless messages can loose the order, the timestamp on
+  SQUIT was needed to check the validity.
+
+- In the client structure a pointer to the server structure is used
+  rather then the full servername, using less memory AND speeding up
+  several places because you don't need to lookup the servername
+  anymore.
+
+- USER removed from the connect burst (now all in NICK).
+
+Other patches
+-------------
+
+- exit_client() is rewritten.
+  Added are exit_client_msg() and exit_new_server().
+  This has especially impact on the possibilities within the protocol.
+  The old exit_client() was clumsy and therefor already used in an incorrect
+  way at several places. The kludges around this part of the code made it
+  impossible to make any changes without breaking something else. Only after
+  the rewrite it was possible to make changes described else where.
+  This also allowed to improve the error message handling to the point that
+  Opers see *always* the error messages involved with routing (also those
+  from remote /connects, delayed errors and squit reasons 'from the other
+  side').
+
+- send.c is more or less rewritten. varargs are fixed now and send.c is
+  highly optimized for speed (possible because of new internal server map). 
+
+- All useable dog3 code speed ups have been added.
+  These include:
+  - Added a head pointer in the dyn buffer.
+  - several code optimisations
+  - continious kill line checking removed (I added the check at
+    the place where it belongs: after a /rehash).
+
+- Useable patches from dl:
+  - Stop as much as possible flooding from unregistered connections.
+  - VERSION and ADMIN available for unregistered users.
+  - syslog (if defined) KILLs of local clients.
+
+- Many compile warnings have been removed. Also a special fix for DYNIX to
+  make UPING/RPING also work there (needed gettimeofday()).
+
+Package changes
+---------------
+
+- The irc client is removed from the package as are several old files with
+  incorrect old useless info (Like 'WHATSNEW', ChangeLog that stopped at 1992).
+- A Makefile.dist is added.
+- Slighty changed doc/Manual
+- New doc/NOTE manual
+- NO_DEFAULT_INVISIBLE removed; users are always visible by default.
+- Last but not least: patchlevel.h is rewritten so any additional patch
+  can do the version update itself, without interfering: No need to edit
+  this by hand anymore.
+
+Summary
+=======
+
+- Less memory usage
+- Speeded up code
+- Less bandwidth use, especially disconnect burst
+- "Server exists" solved
+- Error messages concerning (remote) /connects now always visible.
+- New tools to do (remote) link testing
+- Intelligent and improved SQUIT handling, should stop unwanted breaks.
+- squits comments visible everywhere.
+- net.junction and net.break notices
+- Overall protocol streamlining allowing for future improvements
+  of the protocol.
+
+Run
+
diff --git a/doc/irc.1 b/doc/irc.1
new file mode 100644 (file)
index 0000000..09b3ad3
--- /dev/null
+++ b/doc/irc.1
@@ -0,0 +1,82 @@
+.\" @(#)irc.1 2.6 7 Oct 90
+.TH IRC 1 "7 October 1990"
+.SH NAME
+irc \- User Interface to Internet Relay Chat Protocol
+.SH SYNOPSIS
+\fBirc\fP [\fB-p\fP \fIportnum\fP] [\fB-c\fP \fIchannel\fP] [ \fInickname\fP [ \fIserver\fP ]]
+.SH DESCRIPTION
+.LP
+\fBIrc\fP is a user interface to the Internet Relay Chat, a CB-like
+interactive discussion environment.  It is structured into \fIchannels\fP,
+which are public discussion forums, and also allows for private intercommunication.
+Each participant has a \fInickname\fP, which is the one specified in the command
+line or else his login name.
+.LP
+Once invoked, \fBirc\fP connects as a client to the specified server,
+\fIserver\fP or to the default one (see below).  The screen splits into a dialogue
+window (the major part
+of the screen) and a command line, from which messages can be sent and
+commands given to control irc.
+.SH COMMAND SYNTAX
+The syntax of irc commands is of the form \fB/COMMAND\fP.  The most notable
+ones are listed below.  For an uptodate list, use the \fBHELP\fP command
+of \fBirc\fP.  Case is ignored.
+.IP "\fB/ADMIN\fR [\fIserver\fP]"
+Prints administrative information about an IRC \fIserver\fP.
+.IP "\fB/AWAY\fP [\fImessage\fP]"
+Mark yourself as being away (with an automatic reply \fImessage\fP
+if specified)
+.IP "\fB/BYE\fR, \fB/EXIT\fR, \fB/QUIT\fR"
+Terminate the session
+.IP "\fB/CHANNEL\fR [\fIchannel\fP]"
+Join another \fIchannel\fP
+.IP "\fB/CLEAR\fR"
+Clear the screen
+.IP "\fB/HELP\fR [\fIcommand\fP]"
+Display a brief description of the \fIcommand\fP (or list all commands, if none
+specified).
+.IP "\fB/SUMMON\fR \fIuser\fP"
+Allows to summon a \fIuser\fP specified as a full Internet address, i.e.,
+\fIlogin@host.domain\fP, to an IRC dialogue session (in much the same
+way as the talk(1) command).  It is usable ONLY if the irc daemon runs on
+the target machine (host.domain).
+.IP "\fB/TOPIC\fR \fItopic\fP"
+Sets the \fItopic\fP for the current channel
+.IP "\fB/WHO\fR [\fIchannel\fP|*]"
+Lists all users of IRC if no argument, of the specified \fIchannel\fP or of the
+current channel (*).
+.SH ARGUMENTS
+.IP "\fB-p\fP \fIportnum\fP"
+TCP/IP "port number.  Default is 6667 and this option should seldom if ever"
+be used.
+.IP "\fB-c\fP \fIchannel\fP"
+\fIChannel\fP number to join upon beginning of the session.  Default is no channel.
+.IP "\fInickname\fP"
+\fINickname\fP used in the session (can be changed with the \fB/NICK\fP command).
+Default is user login name.
+.IP "\fIserver\fP"
+\fIServer\fP to connect to.  Default is specified in the irc system configuration
+file, and can be superseded with the environment variable IRCSERVER.
+.SH EXAMPLE
+.RS
+.nf
+tolmoon% \fBirc -p6667 Wizard tolsun\fP
+.fi
+.RE
+.LP
+connects you to irc server in host tolsun (port 6667) with nickname Wizard
+.SH COPYRIGHT
+Copyright (c) 1988 University of Oulu, Computing Center, Finland.
+.nf
+Copyright (c) 1988,1989,1990 Jarkko Oikarinen
+.nf
+All rights reserved.
+For full COPYRIGHT see LICENSE file with IRC package.
+.SH "SEE ALSO"
+ircd(8)
+.SH BUGS
+What bugs ?
+.SH AUTHOR
+Jarkko Oikarinen <jto@tolsun.oulu.fi>
+.nf
+Manual page updated by Michel Fingerhut <Michel.Fingerhut@ircam.fr>
diff --git a/doc/ircd.8 b/doc/ircd.8
new file mode 100644 (file)
index 0000000..681fbc3
--- /dev/null
@@ -0,0 +1,111 @@
+.\" @(#)ircd.8 2.0 (beta version) 29 Mar 1989 
+.TH IRCD 8 "10 July 2000"
+.SH NAME
+ircd \- The Undernet Internet Relay Chat Daemon
+.SH SYNOPSIS
+.hy 0
+.IP \fBircd\fP
+[-t] [-d directory] [-f configfile] [-x debuglevel] [-h hostname]
+.SH DESCRIPTION
+.LP
+\fIircd\fP is the Undernet Internet Relay Chat daemon.  
+\fIircd\fP is a server in that its function is to "serve"
+the client program \fIirc(1)\fP with messages and commands.  All commands
+and user messages are passed directly to \fIircd\fP for processing
+and relaying to other servers.  \fIirc(1)\fP depends upon
+there being an \fIircd\fP server running somewhere for it to connect to
+and thus allow the user to begin talking to other users.
+.LP
+There are many common clients including ircII, EPIC, and BitchX for UNIX,
+mIRC and pIRCh for Windows, and IRCle and Homer for the Macintosh.
+.SH OPTIONS
+.TP
+.B \-d directory
+This option tells the server to change to that directory and use
+that as a reference point when opening \fIircd.conf\fP and other startup
+files.
+.TP
+.B \-t
+Instructs the server run in the foreground and to direct debugging output to
+standard output.
+.TP
+.B \-x#
+Defines the debug level for \fIircd\fP. The higher the debug level, the more
+messages get directed to debugging file (or standard output if the -t option is
+used).
+.TP
+.B \-w interface
+This option is deprecated.  Outgoing connections are bound to the
+interface specified in the M: line, and incoming connections are accepted only on
+interfaces specified in the P: lines.
+.TP
+.B \-f filename
+Specifies the \fIircd.conf\fP file to be used for this server. The option
+is used to override the default \fIircd.conf\fP given at compile time.
+.TP
+.B \-c
+This flag must be given if you are running \fIircd\fP from \fI/dev/console\fP or
+any other situation where fd 0 isn't a TTY and you want the server to fork
+off and run in the background. This needs to be given if you are starting
+\fIircd\fP from an \fIrc\fP (such as \fI/etc/rc.local\fP) file.
+.TP
+.B \-h hostname
+Allows the user to manually set the server name at startup. The default
+name is hostname.domainname.
+.TP
+.B \-p portname
+This is deprecated in favor of specifying server ports in P: lines.
+
+.SH CONFIGURATION
+If you plan to connect your \fIircd\fP server to an existing IRC network,
+you will need to alter your local \fIircd\fP configuration file (typically named
+\fIircd.conf\fP) so that it will accept and make connections to other IRC
+servers.  This file contains the hostnames, network addresses, and
+passwords for connections to other IRC servers around the world.  Because 
+the description of the \fIircd.conf\fP file is beyond the scope of this
+document, please refer to the INSTALL file in the \fIircd\fP
+documentation directory.
+.LP
+BOOTING THE SERVER:  The \fIircd\fP server can be started as part of the
+UNIX boot procedure or just by placing the server into Unix Background.
+Keep in mind that if it is *not* part of your UNIXES Boot-up procedure 
+then you will have to manually start the \fIircd\fP server each time your
+UNIX is rebooted.  This means if your UNIX is prone to crashing
+or going for for repairs a lot it would make sense to start the \fIircd\fP
+server as part of your UNIX bootup procedure.  In some cases the \fIirc(1)\fP
+will automatically attempt to boot the \fIircd\fP server if the user is
+on the SAME UNIX that the \fIircd\fP is supposed to be running on.  If the
+\fIirc(1)\fP cannot connect to the \fIircd\fP server it will try to start
+the server on it's own and will then try to reconnect to the newly booted
+\fIircd\fP server.
+.SH EXAMPLE
+.RS
+.nf
+tolsun% \fBircd\fP
+.fi
+.RE
+.LP
+Places \fIircd\fP into UNIX Background and starts up the server for use.
+Note:  You do not have to add the "&" to this command, the program will
+automatically detach itself from tty.
+.SH COPYRIGHT
+(c) 1988,1989 University of Oulu, Computing Center, Finland,
+.LP
+(c) 1988,1989 Department of Information Processing Science,
+University of Oulu, Finland
+.LP
+(c) 1988,1989,1990,1991 Jarkko Oikarinen
+.LP
+For full COPYRIGHT see LICENSE file with IRC package.
+.LP
+.RE
+.SH FILES
+ /etc/utmp
+ "ircd.conf"
+.SH "SEE ALSO"
+irc(1)
+.SH BUGS
+See the file 'BUGS' included in the distribution.
+.SH AUTHOR
+The current authors of the undernet IRC daemon are coder-com@undernet.org,
+the original author was Jarkko Oikarinen.
\ No newline at end of file
diff --git a/doc/iso-time.html b/doc/iso-time.html
new file mode 100644 (file)
index 0000000..4bb48d9
--- /dev/null
@@ -0,0 +1,535 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">
+<!-- $Id: iso-time.html,v 1.1 2000-04-02 23:46:03 bleep Exp $ -->
+<HTML>
+<HEAD>
+<TITLE>International Standard Date and Time Notation</TITLE>
+<BASE HREF="http://www.cl.cam.ac.uk/~mgk25/iso-time.html">
+<META NAME="keywords" CONTENT="ISO 8601, date format, time format,
+standard notation, calendar, clock, time zones, daylight saving time,
+summer time, international standard, file format, protocol,
+data representation">
+<META NAME="description" CONTENT="International Standard ISO 8601
+specifies numeric representations of date and time. It helps to avoid
+confusion caused by the many different national notations.">
+</HEAD>
+<BODY BGCOLOR="#EFEFEF" TEXT="#000000">
+
+<H1>A Summary of the International Standard Date and Time Notation</H1>
+
+<P>by Markus Kuhn
+
+<P><A HREF="http://www.iso.ch/markete/8601.pdf">International Standard
+ISO 8601</A> specifies numeric representations of date and time. This
+standard notation helps to avoid confusion in international
+communication caused by the many different national notations and
+increases the portability of computer user interfaces. In addition,
+these formats have several important advantages for computer usage
+compared to other traditional date and time notations. The time
+notation described here is already the de-facto standard in almost all
+countries and the date notation is becoming increasingly popular.
+
+<P><STRONG>Especially authors of Web pages and software engineers who
+design user interfaces, file formats, and communication protocols
+should be familiar with ISO 8601.</STRONG>
+
+<P>Contents: <A HREF="#date">Date</A>, <A HREF="#time">Time of Day</A>,
+<A HREF="#zone">Time Zone</A>.
+
+<H2><A NAME="date">Date</A></H2>
+
+<P>The international standard date notation is
+
+<BLOCKQUOTE><P><STRONG>YYYY-MM-DD</STRONG></BLOCKQUOTE>
+
+<P>where YYYY is the year in the usual Gregorian calendar, MM is the
+month of the year between 01 (January) and 12 (December), and DD is
+the day of the month between 01 and 31.
+
+<P>For example, the fourth day of February in the year 1995 is written
+in the standard notation as
+
+<BLOCKQUOTE><P><STRONG>1995-02-04</STRONG></BLOCKQUOTE>
+
+<P>Other commonly used notations are e.g. 2/4/95, 4/2/95, 95/2/4,
+4.2.1995, 04-FEB-1995, 4-February-1995, and many more. Especially the
+first two examples are dangerous, because as both are used quite often
+in the U.S. and in Great Britain and both can not be distinguished, it
+is unclear whether 2/4/95 means 1995-04-02 or 1995-02-04. The date
+notation 2/4/5 has at least six reasonable interpretations (assuming
+that only the twentieth and twenty-first century are reasonable
+candidates in our life time).
+
+<P>Advantages of the ISO 8601 standard date notation compared to other
+commonly used variants:
+
+<UL>
+  <LI>easily readable and writeable by software (no 'JAN', 'FEB', ...
+      table necessary)
+  <LI>easily comparable and sortable with a trivial string comparison
+  <LI>language independent
+  <LI>can not be confused with other popular date notations
+  <LI>consistency with the common 24h time notation system, where
+      the larger units (hours) are also written in front of the smaller
+      ones (minutes and seconds)
+  <LI>strings containing a date followed by a time are also
+      easily comparable and sortable (e.g. write "1995-02-04 22:45:00")
+  <LI>the notation is short and has constant length, which makes both
+      keyboard data entry and table layout easier
+  <LI>identical to the Chinese date notation, so the largest cultural
+      group (>25%) on this planet is already familiar with it :-)
+  <LI>date notations with the order "year, month, day" are in addition
+      already widely used e.g. in Japan, Korea, Hungary, Sweden, Finland,
+      Denmark, and a few other countries and people in the U.S. are already
+      used to at least the "month, day" order
+  <LI>a 4-digit year representation avoids
+      <A HREF="http://www.year2000.com/cgi-bin/clock.cgi">overflow
+      problems after 1999-12-31</A>
+</UL>
+
+<P>As dates will look a little bit strange anyway starting with
+2000-01-01 (e.g. like 1/1/0), it has been suggested that the year 2000
+is an excellent opportunity to change to the standard date notation.
+
+<P>ISO 8601 is only specifying numeric notations and does not cover
+dates and times where words are used in the representation. It is not
+intended as a replacement for language-dependent worded date notations
+such as "24. Dezember 2001" (German) or "February 4, 1995" (US
+English). ISO 8601 should however be used to replace notations such as
+"2/4/95" and "9.30 p.m.".
+
+<P>Apart from the recommended primary standard notation
+<STRONG>YYYY-MM-DD</STRONG>, ISO 8601 also specifies a number of
+alternative formats for use in applications with special requirements.
+All of these alternatives can easily and automatically be
+distinguished from each other:
+
+<P>The hyphens can be omitted if compactness of the representation is
+more important than human readability, for example as in
+
+<BLOCKQUOTE><P><STRONG>19950204</STRONG></BLOCKQUOTE>
+
+<P>For situations where information about the century is really not
+required, a 2-digit year representation is available:
+
+<BLOCKQUOTE><P><STRONG>95-02-04</STRONG> or
+<STRONG>950204</STRONG></BLOCKQUOTE>
+
+<P>If only the month or even only the year is of interest:
+
+<BLOCKQUOTE><P><STRONG>1995-02</STRONG> or
+<STRONG>1995</STRONG></BLOCKQUOTE>
+
+<P>In commercial and industrial applications (delivery times,
+production plans, etc.), especially in Europe, it is often required to
+refer to a week of a year. Week 01 of a year is per definition the
+first week that has the Thursday in this year, which is equivalent to
+the week that contains the fourth day of January. In other words, the
+first week of a new year is the week that has the majority of its
+days in the new year. Week 01 might also contain days from the
+previous year and the week before week 01 of a year is the last week
+(52 or 53) of the previous year even if it contains days from the new
+year. A week starts with Monday (day 1) and ends with Sunday (day 7).
+For example, the first week of the year 1997 lasts from 1996-12-30 to
+1997-01-05 and can be written in standard notation as
+
+<BLOCKQUOTE><P><STRONG>1997-W01</STRONG> or
+<STRONG>1997W01</STRONG></BLOCKQUOTE>
+
+<P>The week notation can also be extended by a number indicating the
+day of the week. For example, the day 1996-12-31, which is the Tuesday
+(day 2) of the first week of 1997, can also be written as
+
+<BLOCKQUOTE><P><STRONG>1997-W01-2</STRONG> or
+<STRONG>1997W012</STRONG></BLOCKQUOTE>
+
+<P>for applications like industrial planning where many things like
+shift rotations are organized per week and knowing the week number and
+the day of the week is more handy than knowing the day of the month.
+
+<P>An abbreviated version of the year and week number like
+
+<BLOCKQUOTE><P><STRONG>95W05</STRONG></BLOCKQUOTE>
+
+<P>is sometimes useful as a compact code printed on a product that
+indicates when it has been manufactured.
+
+<P>The ISO standard avoids explicitly stating the possible range of
+week numbers, but this can easily be deduced from the definition:
+
+<BLOCKQUOTE>
+
+<P><STRONG>Theorem:</STRONG> Possible ISO week numbers are in the
+range 01 to 53. A year always has a week 52. (There is one historic
+exception: the year in which the Gregorian calendar was introduced had
+less than 365 days and less than 52 weeks.)
+
+<P><STRONG>Proof:</STRONG> Per definition, the first week of a year is
+W01 and consequently days before week W01 belong to the previous year
+and so there is no week with lower numbers. Considering the highest
+possible week number, the worst case is a leap year like 1976 that
+starts with a Thursday, because this keeps the highest possible number
+of days of W01 in the previous year, i.e. 3 days. In this case, the
+Sunday of W52 of the worst case year is day number 4+51*7=361 and
+361-366=5 days of W53 belong still to this year, which guarantees that
+in the worst case year day 4 (Thursday) of W53 is not yet in the next
+year, so a week number 53 is possible. For example, the 53 weeks of
+the worst case year 1976 started with 1975-12-29 = 1976-W01-1 and
+ended with 1977-01-02 = 1976-W53-7. On the other hand, considering the
+lowest number of the last week of a year, the worst case is a non-leap
+year like 1999 that starts with a Friday, which ensures that the first
+three days of the year belong to the last week of the previous year.
+In this case, the Sunday of week 52 would be day number 3+52*7=367,
+i.e. only the last 367-365=2 days of the W52 reach into the next year
+and consequently, even a worst case year like 1999 has a week W52
+including the days 1999-12-27 to 2000-01-02. q.e.d.
+
+</BLOCKQUOTE>
+
+<P>[Unfortunately, the current version of the C programming language
+standard provides in the <CODE>strftime()</CODE> function no means to
+generate the ISO 8601 week notation. A required extension would be
+four new formatting codes: for the year of the week to which the
+specified day belongs (both 2-digit and 4-digit), for the number of
+the week between 01 and 53, and for the day of the week between 1
+(Monday) and 7 (Sunday). Another trivial mistake in the description of
+<CODE>strftime()</CODE> in the C standard is that the range of seconds
+goes from 00 to 61, because at one time only one single leap second 60
+can be inserted into UTC and consequently there will never be a leap
+second 61. Contribution <A
+HREF="http://www.gold.net/users/cdwf/c/wg14n764.txt">N764</A> to the
+<A HREF="ftp://dkuug.dk/JTC1/SC22/wg14/index.html">ISO C committee</A>
+suggests to fix some of this in the next revision of the ISO C
+standard. The author of this text has also developed a proposal for a
+<A HREF="c-time/">modernised clock and calendar API</A> for C, which
+provides full proper treatment of leap seconds and timezones and fixes
+numerous other problems in the current C timing library functions. It
+also serves as an excellent model for those who want to design clock
+library functions for other programming languages.]
+
+<P>Both day and year are useful units of structuring time, because the
+position of the sun on the sky, which influences our lives, is
+described by them. However the 12 months of a year are of some obscure
+mystic origin and have no real purpose today except that people are
+used to having them (they do not even describe the current position of
+the moon). In some applications, a date notation is preferred that
+uses only the year and the day of the year between 001 and 365 (366 in
+leap years). The standard notation for this variant representing
+the day 1995-02-04 (that is day 035 of the year 1995) is
+
+<BLOCKQUOTE><P><STRONG>1995-035</STRONG> or
+<STRONG>1995035</STRONG></BLOCKQUOTE>
+
+<P>Leap years are years with an additional day YYYY-02-29, where the
+year number is a multiple of four with the following exception: If a
+year is a multiple of 100, then it is only a leap year if it is also a
+multiple of 400. For example, 1900 was not a leap year, but 2000 is one.
+
+<H2><A NAME="time">Time of Day</A></H2>
+
+<P>The international standard notation for the time of day is
+
+<BLOCKQUOTE><P><STRONG>hh:mm:ss</STRONG></BLOCKQUOTE>
+
+<P>where hh is the number of complete hours that have passed since
+midnight (00-24), mm is the number of complete minutes that have
+passed since the start of the hour (00-59), and ss is the number of
+complete seconds since the start of the minute (00-59).  If the hour
+value is 24, then the minute and second values must be zero. [Although
+ISO 8601 does not mention this, the value 60 for ss might sometimes be
+needed during an inserted <A
+HREF="http://tycho.usno.navy.mil/leap.html">leap second</A> in an
+atomic time scale like Coordinated Universal Time (UTC). A single leap
+second 23:59:60 is inserted into the UTC time scale every few years as
+announced by the <A HREF="http://hpiers.obspm.fr/">International Earth
+Rotation Service</A> in Paris to keep UTC from wandering away more
+than 0.9&nbsp;s from the less constant astronomical time scale UT1
+that is defined by the actual rotation of the earth.]
+
+
+<P>An example time is
+
+<BLOCKQUOTE><P><STRONG>23:59:59</STRONG></BLOCKQUOTE>
+
+<P>which represents the time one second before midnight.
+
+<P>As with the date notation, the separating colons can also be
+omitted as in
+
+<BLOCKQUOTE><P><STRONG>235959</STRONG></BLOCKQUOTE>
+
+<P>and the precision can be reduced by omitting the seconds or both
+the seconds and minutes as in
+
+<BLOCKQUOTE><P><STRONG>23:59</STRONG>, <STRONG>2359</STRONG>, or
+<STRONG>23</STRONG></BLOCKQUOTE>
+
+<P>It is also possible to add fractions of a second after a decimal
+dot or comma, for instance the time 5.8&nbsp;ms before midnight can be
+written as
+
+<BLOCKQUOTE><P><STRONG>23:59:59.9942</STRONG> or
+<STRONG>235959.9942</STRONG> </BLOCKQUOTE>
+
+<P>As every day both starts and ends with midnight, the two notations
+<STRONG>00:00</STRONG> and <STRONG>24:00</STRONG> are available to
+distinguish the two midnights that can be associated with one date.
+This means that the following two notations refer to exactly the same
+point in time:
+
+<BLOCKQUOTE><P><STRONG>1995-02-04 24:00</STRONG> =
+<STRONG>1995-02-05 00:00</STRONG></BLOCKQUOTE>
+
+<P>In case an unambiguous representation of time is required, 00:00 is
+usually the preferred notation for midnight and not 24:00. Digital
+clocks display 00:00 and not 24:00.
+
+<P>ISO 8601 does not specify, whether its notations specify a point in
+time or a time period. This means for example that ISO 8601 does not
+define whether 09:00 refers to the exact end of the ninth hour of the
+day or the period from 09:00 to 09:01 or anything else. The users of
+the standard must somehow agree on the exact interpretation of the
+time notation if this should be of any concern.
+
+<P>If a date and a time are displayed on the same line, then always
+write the date in front of the time. If a date and a time value are
+stored together in a single data field, then ISO 8601 suggests that
+they should be separated by a latin capital letter T, as in
+<STRONG>19951231T235959</STRONG>.
+
+<P>A remark for readers from the U.S.:
+
+<BLOCKQUOTE><P>The 24h time notation specified here has already been
+the de-facto standard all over the world in written language for
+decades. The only exception are some English speaking countries, where
+still notations with hours between 1 and 12 and additions like "a.m."
+and "p.m." are in wide use. The common 24h international standard
+notation starts to get widely used now even in England. Most other
+languages don't even have abbreviations like "a.m." and "p.m." and the
+12h notation is certainly hardly ever used on Continental Europe to
+write or display a time. Even in the U.S., the military and computer
+programmers have been using the 24h notation for a long time.
+
+<P>The old English 12h notation has many disadvantages like:
+
+<UL>
+  <LI> It is longer than the normal 24h notation.
+  <LI> It takes somewhat more time for humans to compare two times
+       in 12h notation.
+  <LI> It is not clear, how 00:00, 12:00 and 24:00 are represented.
+       Even encyclopedias and style manuals contain contradicting
+       descriptions and a common quick fix seems to be to avoid
+       "12:00 a.m./p.m." altogether and write "noon", "midnight", or
+       "12:01 a.m./p.m." instead, although the word "midnight" still
+       does not distinguish between 00:00 and 24:00.
+  <LI> It makes people often believe that the next day starts at the
+       overflow from "12:59 a.m." to "1:00 a.m.", which is a common
+       problem not only when people try to program the timer of VCRs
+       shortly after midnight.
+  <LI> It is not easily comparable with a string compare operation.
+  <LI> It is not immediately clear for the unaware, whether the
+       time between "12:00 a.m./p.m." and "1:00 a.m./p.m." starts
+       at 00:00 or at 12:00, i.e. the English 12h notation is more
+       difficult to understand.
+</UL>
+
+<P>Please consider the 12h time to be a relic from the dark ages when
+Roman numerals were used, the number zero had not yet been invented
+and analog clocks were the only known form of displaying a
+time. Please avoid using it today, especially in technical
+applications! Even in the U.S., the widely respected <CITE>Chicago
+Manual of Style</CITE> now recommends using the international
+standard time notation in publications.
+
+</BLOCKQUOTE>
+
+<P>A remark for readers from German speaking countries:
+
+<BLOCKQUOTE><P>In May 1996, the German standard DIN 5008, which
+specifies typographical rules for German texts written on typewriters,
+has been updated. The old German numeric date notations DD.MM.YYYY and
+DD.MM.YY have been replaced by the ISO date notations YYYY-MM-DD and
+YY-MM-DD. Similarly, the old German time notations hh.mm and hh.mm.ss
+have been replaced by the ISO notations hh:mm and hh:mm:ss.  Those new
+notations are now also mentioned in the latest edition of the
+<CITE>Duden</CITE>. The German alphanumeric date notation continues to
+be for example "3. August 1994" or "3. Aug. 1994". The corresponding
+Austrian standard has already used the ISO 8601 date and time
+notations before.
+
+<P>ISO 8601 has been adopted as European Standard EN 28601 and is
+therefore now a valid standard in all EU countries and all conflicting
+national standards have been changed accordingly.
+</BLOCKQUOTE>
+
+<H2><A NAME="zone">Time Zone</A></H2>
+
+<P>Without any further additions, a date and time as written above is
+assumed to be in some local time zone. In order to indicate that a
+time is measured in <A HREF="http://aa.usno.navy.mil/AA/faq/docs/UT.html"
+>Universal Time (UTC)</A>, you can append a capital
+letter <STRONG>Z</STRONG> to a time as in
+
+<BLOCKQUOTE><P><STRONG>23:59:59Z</STRONG> or <STRONG>2359Z</STRONG>
+</BLOCKQUOTE>
+
+<P>[The Z stands for the "zero meridian", which goes through Greenwich
+in London, and it is also commonly used in radio communication where
+it is pronounced "Zulu" (the word for Z in the international radio
+alphabet).  <A HREF=
+"http://www.apparent-wind.com/gmt-explained.html">Universal
+Time</A> (sometimes also called "Zulu Time") was called Greenwich Mean
+Time (GMT) before 1972, however this term should no longer be
+used. Since the introduction of an international atomic time scale,
+almost all existing civil time zones are now related to UTC, which is
+slightly different from the old and now unused GMT.]
+
+<P>The strings
+
+<BLOCKQUOTE><P><STRONG>+hh:mm</STRONG>, <STRONG>+hhmm</STRONG>, or
+<STRONG>+hh</STRONG></BLOCKQUOTE>
+
+<P>can be added to the time to indicate that the used local time zone
+is hh hours and mm minutes ahead of UTC. For time zones west of the
+zero meridian, which are behind UTC, the notation
+
+<BLOCKQUOTE><P><STRONG>-hh:mm</STRONG>, <STRONG>-hhmm</STRONG>, or
+<STRONG>-hh</STRONG></BLOCKQUOTE>
+
+<P>is used instead. For example, Central European Time (CET) is +0100
+and U.S./Canadian Eastern Standard Time (EST) is -0500. The following
+strings all indicate the same point of time:
+
+<BLOCKQUOTE><P><STRONG>12:00Z</STRONG> = <STRONG>13:00+01:00</STRONG>
+= <STRONG>0700-0500</STRONG></BLOCKQUOTE>
+
+<P>There exists no international standard that specifies
+abbreviations for civil time zones like CET, EST, etc. and sometimes
+the same abbreviation is even used for two very different time zones.
+In addition, politicians enjoy modifying the rules for civil time
+zones, especially for daylight saving times, every few years, so the
+only really reliable way of describing a local time zone is to specify
+numerically the difference of local time to UTC. Better use directly
+UTC as your only time zone where this is possible and then you do not
+have to worry about time zones and daylight saving time changes at
+all.
+
+<H2><A NAME="tz">More Information about Time Zones</A></H2>
+
+<P><A HREF="mailto:ado@elsie.nci.nih.gov">Arthur David Olson</A> and
+others maintain a <A HREF=
+"http://www.twinsun.com/tz/tz-link.htm">database of all current and
+many historic time zone changes and daylight saving time
+algorithms</A>. It is available via ftp from <A
+HREF="ftp://elsie.nci.nih.gov/pub/">elsie.nci.nih.gov</A> in the
+<SAMP>tzcode*</SAMP> and <SAMP>tzdata*</SAMP> files. Most Unix time
+zone handling implementations are based on this package. If you want
+to join the <SAMP>tz</SAMP> mailing list, which is dedicated to
+discussions about time zones and this software, please send a request
+for subscription to <A HREF="mailto:tz-request@elsie.nci.nih.gov"
+>tz-request@elsie.nci.nih.gov</A>. You can read previous discussion
+there in the <A HREF="ftp://elsie.nci.nih.gov/pub/tzarchive.gz">tz
+archive</A>.
+
+<H2><A NAME="other">Other Links about Date, Time, and Calendars</A></H2>
+
+<P>Some other interesting sources of information about date and time
+on the Internet are for example the <A
+HREF="http://www.boulder.nist.gov/timefreq/glossary.htm">Glossary of
+Frequency and Timing Terms</A> and the <A
+HREF="http://www.boulder.nist.gov/timefreq/faq/faq.htm">FAQ</A>
+provided by <A HREF="http://www.boulder.nist.gov/timefreq/">NIST</A>,
+the <A HREF=
+"http://www.yahoo.com/Science/Measurements_and_Units/Time/" >Yahoo
+Science:Measurements and Units:Time</A> link collection, the <A
+HREF="http://tycho.usno.navy.mil/">U.S. Naval Observatory Server</A>,
+the <A HREF="http://hpiers.obspm.fr/"> International Earth Rotation
+Service (IERS)</A> (for time gurus only!), the <A
+HREF="http://www.eecis.udel.edu/~ntp/">University of Delaware NTP Time
+Server</A>, the time and calendar section of the <A
+HREF="http://sciastro.astronomy.net/sci.astro.3.FAQ">USENET sci.astro
+FAQ</A>, and the <A HREF=
+"http://www.tondering.dk/claus/calendar.html">Calendar FAQ</A>.
+
+<P><HR>
+
+<P>This was a brief overview of the ISO 8601 standard, which covers
+only the most useful notations and includes some additional related
+information. The full standard defines in addition a number of more
+exotic notations including some for periods of time. The <A HREF=
+"http://www.iso.ch/cate/d15903.html">ISO 8601:1988 document</A> is
+fortunately now also <A
+HREF="http://www.iso.ch/markete/8601.pdf">available online</A>, or you
+can order a paper copy from
+
+<BLOCKQUOTE><P>
+<A HREF="http://www.iso.ch/">International Organization
+for Standardization</A><BR>
+Case postale 56<BR>
+1, rue de Varemb&eacute;<BR>
+CH-1211 Gen&egrave;ve 20<BR>
+Switzerland<BR>
+<BR>
+phone: +41 22 749 01 11<BR>
+fax: +41 22 733 34 30<BR>
+email: <A HREF="mailto:sales@isocs.iso.ch">sales@isocs.iso.ch</A>
+</BLOCKQUOTE>
+
+<P>A more detailed online summary of ISO 8601 than this one is the
+text <CITE>ISO 8601:1988 Date/Time Representations</CITE> available
+from <A HREF=
+"ftp://ftp.informatik.uni-erlangen.de/pub/doc/ISO/ISO8601.ps.Z">
+ftp.informatik.uni-erlangen.de/pub/doc/ISO/ISO8601.ps.Z</A>
+(PostScript, 16 kb, 5 pages) written by <A HREF=
+"mailto:Gary.Houston@actrix.gen.nz">Gary Houston</A>, now also
+available in <A HREF=
+"http://www.mcs.vuw.ac.nz/comp/Technical/SGML/doc/iso8601/ISO8601.html"
+>HTML</A>. Ian Galpin (G1SMD) proposes to use ISO 8601 as a <A
+HREF="http://www.kirsta.demon.co.uk/radio/iso_8601.htm">Common Date-Time
+Standard for Amateur Radio</A>. <A
+HREF="http://www.saqqara.demon.co.uk/">Steve Adams</A> has written <A
+HREF= "http://www.saqqara.demon.co.uk/datefmt.htm">another web
+page</A> about the ISO date format that is partially based on this
+text.
+
+<P>ISO TC 154 decided in 1996 to revise ISO 8601. <A
+HREF="mailto:Louis.Visser@nni.nl">Louis Visser</A> is coordinating
+this project. If you want to contribute to this work, you should
+contact your <A HREF=
+"http://www.iso.ch/addresse/address.html">national ISO member
+organization</A>. <!-- Have a look at the <A HREF="8601v04.pdf">1998-01
+draft of the forthcoming ISO 8601:1999</A>.-->
+
+<P><HR>
+
+<P>I wish to thank <A HREF="http://emr.cs.uiuc.edu/~reingold">Edward
+M. Reingold</A> for developing the fine GNU Emacs calendar functions,
+as well as <A HREF="http://yank.kitchener.on.ca/~richw">Rich Wales</A>,
+<A HREF="mailto:msb@sq.com">Mark Brader</A>, <A
+HREF="mailto:eggert%yata.UUCP@twinsun.com">Paul Eggert</A>, and others
+in the <A HREF="news:comp.std.internat">comp.std.internat</A>, <A
+HREF="news:comp.protocols.time.ntp">comp.protocols.time.ntp</A>, and
+<A HREF="news:sci.astro">sci.astro</A> USENET discussion groups for
+valuable comments about this text. Further comments and hyperlinks to
+this page are very welcome.
+
+<P>Some journalists recently got interested in the international date
+and time format and reported about it. Examples include:
+<UL>
+<LI>An article by <A HREF="mailto:Jon.Auerbach@news.wsj.com">Jon G.
+Auerbach</A> in the 1999-06-01 issue of the Wall Street Journal, page
+A1.
+</UL>
+<P>If you are a journalist and need information on this or related
+topics, please feel free to contact me.
+
+<P>You might also be interested in the <A
+HREF="http://www.cl.cam.ac.uk/~mgk25/iso-paper.html">International
+Standard Paper Sizes</A> Web page.
+
+<P><A HREF="http://www.cl.cam.ac.uk/~mgk25/">
+Markus Kuhn</A> <A HREF="mailto:Markus.Kuhn@cl.cam.ac.uk"
+>&lt;Markus.Kuhn@cl.cam.ac.uk></A>
+<BR><SMALL>created 1995 -- last modified 2000-01-24 --
+http://www.cl.cam.ac.uk/~mgk25/iso-time.html</SMALL>
+</BODY>
+</HTML>
diff --git a/doc/linux-poll.patch b/doc/linux-poll.patch
new file mode 100644 (file)
index 0000000..bdbba0b
--- /dev/null
@@ -0,0 +1,52 @@
+*** ./select.c.bak     Sun Apr 30 13:00:38 2000
+--- /usr/src/linux/fs/select.c Mon May  1 18:00:15 2000
+***************
+*** 11,16 ****
+--- 11,17 ----
+   */
+  
+  #include <linux/malloc.h>
++ #include <linux/vmalloc.h>
+  #include <linux/smp_lock.h>
+  #include <linux/poll.h>
+  #include <linux/file.h>
+***************
+*** 416,422 ****
+       }
+  
+       size = nfds * sizeof(struct pollfd);
+!      fds = (struct pollfd *) kmalloc(size, GFP_KERNEL);
+       if (!fds)
+               goto out;
+  
+--- 417,426 ----
+       }
+  
+       size = nfds * sizeof(struct pollfd);
+!      if (size > PAGE_SIZE) 
+!              fds = (struct pollfd *) vmalloc(size);
+!      else
+!              fds = (struct pollfd *) kmalloc(size, GFP_KERNEL);
+       if (!fds)
+               goto out;
+  
+***************
+*** 437,443 ****
+               err = -EINTR;
+  
+  out_fds:
+!      kfree(fds);
+  out:
+       if (wait)
+               free_wait(wait_table);
+--- 441,450 ----
+               err = -EINTR;
+  
+  out_fds:
+!      if (size > PAGE_SIZE) 
+!              vfree(fds);
+!      else
+!              kfree(fds);
+  out:
+       if (wait)
+               free_wait(wait_table);
diff --git a/doc/p10.html b/doc/p10.html
new file mode 100644 (file)
index 0000000..fbbc4fe
--- /dev/null
@@ -0,0 +1,1184 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<HTML>
+<HEAD>
+   <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1">
+   <META NAME="GENERATOR" CONTENT="Mozilla/4.07 [en] (X11; I; Linux 2.2.14 i586) [Netscape]">
+   <TITLE>Undernet P10 Protocol and Interface Specification</TITLE>
+</HEAD>
+<BODY>
+
+<H2>
+<A NAME="top"></A><FONT SIZE=+3>Undernet P10 Protocol and Interface Specification</FONT></H2>
+<I>(As of ircu 2.10.11)</I>
+<H2>
+Undernet Coder-com, <TT>coder-com@undernet.org</TT></H2>
+$Id: p10.html,v 1.6 2002-02-14 00:20:40 ghostwolf Exp $
+<P>
+<HR ALIGN=CENTER WIDTH=100% SIZE=2><I>This document aims to be a practical
+guide for implementing and maintaining the protocol, not just a reference
+manual.</I>
+<P>This document is "work in progress" and being continually updated :)
+<HR 
+  ALIGN=CENTER WIDTH=100% SIZE=2>
+<BR><FONT SIZE=+2>1. <B><A HREF="#chap1">Introduction</A></B></FONT>
+<P><FONT SIZE=+2>2. <B><A HREF="#chap2">General concepts and background</A></B></FONT>
+<BLOCKQUOTE><FONT SIZE=+0>2.1 <A HREF="#chap2.1">Concepts</A>.</FONT>
+<BR><FONT SIZE=+0>2.2 <A HREF="#chap2.2">Token Table</A>.</FONT></BLOCKQUOTE>
+
+<H2>
+3. <A HREF="#chap3">Registration and syncronisation</A></H2>
+
+<UL>
+<LI>
+<FONT SIZE=+0>3.1 <A HREF="#chap3.1">Server registration and authentication</A>.</FONT></LI>
+
+<LI>
+<FONT SIZE=+0>3.2 <A HREF="#chap3.2">Network database resyncronisation</A>.</FONT></LI>
+
+<LI>
+<FONT SIZE=+0>3.3 <A HREF="#chap3.3">Summary</A>.</FONT></LI>
+</UL>
+
+<H2>
+4. <A HREF="#chap4">Continous operation</A></H2>
+
+<UL>
+<LI>
+4.1 <A HREF="#chap4.1">Channel state operations.</A></LI>
+
+<LI>
+4.2 <A HREF="#chap4.2">Client state operations.</A></LI>
+
+<LI>
+4.3 <A HREF="#chap4.3">Channel/Client Messaging.</A></LI>
+
+<LI>
+4.4 Setting G-Lines.</LI>
+
+<LI>
+4.5 ...</LI>
+</UL>
+
+<H2>
+4. Programmers reference: Function headers</H2>
+
+<UL>
+<LI>
+<FONT SIZE=+0>4.1 ms_nick</FONT></LI>
+
+<LI>
+<FONT SIZE=+0>4.2 m_burst</FONT></LI>
+
+<LI>
+<FONT SIZE=+0>4.3 ..etc</FONT></LI>
+</UL>
+
+<H2>
+5. <A HREF="#chap5">Programmers reference: Client/Server Structures</A></H2>
+
+<H2>
+6. <A HREF="#chap7">FAQ</A></H2>
+
+<H2>
+7. Acknowledgements and disclaimer</H2>
+
+<H2>
+8. <A HREF="#chap8">Update History</A></H2>
+
+<BLOCKQUOTE>
+<LI>
+<A HREF="#chap8.1">TODO List</A></LI>
+</BLOCKQUOTE>
+
+<CENTER>
+<HR ALIGN=CENTER WIDTH=100% SIZE=2></CENTER>
+
+<P><A NAME="chap1"></A><B><FONT SIZE=+2>1. Introduction</FONT></B>
+<P><FONT FACE="Arial,Helvetica"><FONT SIZE=-1><B>[</B><A HREF="#top">Back</A><B>]</B></FONT></FONT>
+<BR>
+<HR ALIGN=LEFT WIDTH=100% SIZE=2>
+<P><A NAME="chap2"></A><B><FONT SIZE=+2>2. General concepts and background</FONT></B>
+<P><A NAME="chap2.1"></A><B><FONT SIZE=+1>2.1 Concepts</FONT></B>
+<P>The undernet P10 protocol uses a scheme of "Numerics" to uniquenly identify
+a client or server within the network. Each server has its own unique numeric
+(0 -> 4095) and each client has its own numeric within that server (0->262,143).
+<P>The numerics are encoded into a Base64 stream to maintain human readable
+data flow and reduce the size of the messages. The Base64 character set
+used in ircu is included below, this defines all valid characters allowed
+in a Base64 numeric with "A" representing 0 and "]" representing 63.
+<BLOCKQUOTE>
+<PRE><TT><FONT COLOR="#00007F">ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789[]</FONT></TT></PRE>
+</BLOCKQUOTE>
+Server numerics consist of 2 characters, with the minimum, 0, being represented
+by "AA", and the maximum, 4095, being represented by "]]". Client numerics
+are 3 characters long, with the minimum, 0, being represented by "AAA",
+and the maximum, 262,143, being represented by "]]]". The unique identifier
+of a client on the network consists of a combination of both the server
+and client numeric in the format SSCCC.
+<P>As an example, consider a server "irc.undernet.org" which has a numeric
+of 2, translating to "AC" in Base64. On this server exists a client, whom
+has been allocated the numeric 63 (which translates to "AA]" in Base64).
+Therefore, the unique identifier of this client on the network is "ACAA]".
+From this, we can determine which server the message came from, aswell
+as the client who sent it.
+<P>These numerics are used to prefix every message issued on the stream
+except for the initial "PASS" or "SERVER" message, which are not prefixed.
+Therefore, every message that can be recieved from a server will consist
+of the format:
+<BLOCKQUOTE>
+<PRE><FONT COLOR="#00007F">[NUMERIC PREFIX] [TOKEN] [DATA]</FONT></PRE>
+</BLOCKQUOTE>
+For Example:
+<BLOCKQUOTE>
+<PRE><FONT COLOR="#00007F">A[A5j P ABAAA :Foo.</FONT></PRE>
+</BLOCKQUOTE>
+<A NAME="chap2.2"></A><B><FONT SIZE=+1>2.2 Token Table</FONT></B>
+<P>The following table lists all the acceptable messages, along with their
+relevant "Token", which is used in the server&lt;>server protocol. The
+aim of tokenisation is to reduce the bandwidth used during network communication
+by reducing the length of common message identifiers.
+<BR>&nbsp;
+<CENTER><TABLE BORDER COLS=2 WIDTH="40%" >
+<TR>
+<TD><B>Message</B></TD>
+
+<TD><B>Token</B></TD>
+</TR>
+
+<TR>
+<TD><FONT SIZE=-1>PRIVMSG</FONT></TD>
+
+<TD><FONT SIZE=-1>P</FONT></TD>
+</TR>
+
+<TR>
+<TD><FONT SIZE=-1>WHO</FONT></TD>
+
+<TD><FONT SIZE=-1>H</FONT></TD>
+</TR>
+
+<TR>
+<TD><FONT SIZE=-1>WHOIS</FONT></TD>
+
+<TD><FONT SIZE=-1>W</FONT></TD>
+</TR>
+
+<TR>
+<TD><FONT SIZE=-1>WHOWAS</FONT></TD>
+
+<TD><FONT SIZE=-1>X</FONT></TD>
+</TR>
+
+<TR>
+<TD><FONT SIZE=-1>USER</FONT></TD>
+
+<TD><FONT SIZE=-1>USER</FONT></TD>
+</TR>
+
+<TR>
+<TD><FONT SIZE=-1>NICK</FONT></TD>
+
+<TD><FONT SIZE=-1>N</FONT></TD>
+</TR>
+
+<TR>
+<TD><FONT SIZE=-1>SERVER</FONT></TD>
+
+<TD><FONT SIZE=-1>S</FONT></TD>
+</TR>
+
+<TR>
+<TD><FONT SIZE=-1>LIST</FONT></TD>
+
+<TD><FONT SIZE=-1>LIST</FONT></TD>
+</TR>
+
+<TR>
+<TD><FONT SIZE=-1>TOPIC</FONT></TD>
+
+<TD><FONT SIZE=-1>T</FONT></TD>
+</TR>
+
+<TR>
+<TD><FONT SIZE=-1>INVITE</FONT></TD>
+
+<TD><FONT SIZE=-1>I</FONT></TD>
+</TR>
+
+<TR>
+<TD><FONT SIZE=-1>VERSION</FONT></TD>
+
+<TD><FONT SIZE=-1>V</FONT></TD>
+</TR>
+
+<TR>
+<TD><FONT SIZE=-1>QUIT</FONT></TD>
+
+<TD><FONT SIZE=-1>Q</FONT></TD>
+</TR>
+
+<TR>
+<TD><FONT SIZE=-1>SQUIT</FONT></TD>
+
+<TD><FONT SIZE=-1>SQ</FONT></TD>
+</TR>
+
+<TR>
+<TD><FONT SIZE=-1>KILL</FONT></TD>
+
+<TD><FONT SIZE=-1>D</FONT></TD>
+</TR>
+
+<TR>
+<TD><FONT SIZE=-1>INFO</FONT></TD>
+
+<TD><FONT SIZE=-1>F</FONT></TD>
+</TR>
+
+<TR>
+<TD><FONT SIZE=-1>LINKS</FONT></TD>
+
+<TD><FONT SIZE=-1>LI</FONT></TD>
+</TR>
+
+<TR>
+<TD><FONT SIZE=-1>STATS</FONT></TD>
+
+<TD><FONT SIZE=-1>R</FONT></TD>
+</TR>
+
+<TR>
+<TD><FONT SIZE=-1>HELP</FONT></TD>
+
+<TD><FONT SIZE=-1>HELP</FONT></TD>
+</TR>
+
+<TR>
+<TD><FONT SIZE=-1>ERROR</FONT></TD>
+
+<TD><FONT SIZE=-1>Y</FONT></TD>
+</TR>
+
+<TR>
+<TD><FONT SIZE=-1>AWAY</FONT></TD>
+
+<TD><FONT SIZE=-1>A</FONT></TD>
+</TR>
+
+<TR>
+<TD><FONT SIZE=-1>CONNECT</FONT></TD>
+
+<TD><FONT SIZE=-1>CO</FONT></TD>
+</TR>
+
+<TR>
+<TD><FONT SIZE=-1>MAP</FONT></TD>
+
+<TD><FONT SIZE=-1>MAP</FONT></TD>
+</TR>
+
+<TR>
+<TD><FONT SIZE=-1>PING</FONT></TD>
+
+<TD><FONT SIZE=-1>G</FONT></TD>
+</TR>
+
+<TR>
+<TD><FONT SIZE=-1>PONG</FONT></TD>
+
+<TD><FONT SIZE=-1>Z</FONT></TD>
+</TR>
+
+<TR>
+<TD><FONT SIZE=-1>OPER</FONT></TD>
+
+<TD><FONT SIZE=-1>OPER</FONT></TD>
+</TR>
+
+<TR>
+<TD><FONT SIZE=-1>PASS</FONT></TD>
+
+<TD><FONT SIZE=-1>PA</FONT></TD>
+</TR>
+
+<TR>
+<TD><FONT SIZE=-1>WALLOPS</FONT></TD>
+
+<TD><FONT SIZE=-1>WA</FONT></TD>
+</TR>
+
+<TR>
+<TD><FONT SIZE=-1>DESYNCH</FONT></TD>
+
+<TD><FONT SIZE=-1>DS</FONT></TD>
+</TR>
+
+<TR>
+<TD><FONT SIZE=-1>TIME</FONT></TD>
+
+<TD><FONT SIZE=-1>TI</FONT></TD>
+</TR>
+
+<TR>
+<TD><FONT SIZE=-1>SETTIME</FONT></TD>
+
+<TD><FONT SIZE=-1>SE</FONT></TD>
+</TR>
+
+<TR>
+<TD><FONT SIZE=-1>RPING</FONT></TD>
+
+<TD><FONT SIZE=-1>RI</FONT></TD>
+</TR>
+
+<TR>
+<TD><FONT SIZE=-1>RPONG</FONT></TD>
+
+<TD><FONT SIZE=-1>RO</FONT></TD>
+</TR>
+
+<TR>
+<TD><FONT SIZE=-1>NAMES</FONT></TD>
+
+<TD><FONT SIZE=-1>E</FONT></TD>
+</TR>
+
+<TR>
+<TD><FONT SIZE=-1>ADMIN</FONT></TD>
+
+<TD><FONT SIZE=-1>AD</FONT></TD>
+</TR>
+
+<TR>
+<TD><FONT SIZE=-1>TRACE</FONT></TD>
+
+<TD><FONT SIZE=-1>TR</FONT></TD>
+</TR>
+
+<TR>
+<TD><FONT SIZE=-1>NOTICE</FONT></TD>
+
+<TD><FONT SIZE=-1>O</FONT></TD>
+</TR>
+
+<TR>
+<TD><FONT SIZE=-1>WALLCHOPS</FONT></TD>
+
+<TD><FONT SIZE=-1>WC</FONT></TD>
+</TR>
+
+<TR>
+<TD><FONT SIZE=-1>CPRIVMSG</FONT></TD>
+
+<TD><FONT SIZE=-1>CP</FONT></TD>
+</TR>
+
+<TR>
+<TD><FONT SIZE=-1>CNOTICE</FONT></TD>
+
+<TD><FONT SIZE=-1>CN</FONT></TD>
+</TR>
+
+<TR>
+<TD><FONT SIZE=-1>JOIN</FONT></TD>
+
+<TD><FONT SIZE=-1>J</FONT></TD>
+</TR>
+
+<TR>
+<TD><FONT SIZE=-1>PART</FONT></TD>
+
+<TD><FONT SIZE=-1>L</FONT></TD>
+</TR>
+
+<TR>
+<TD><FONT SIZE=-1>LUSERS</FONT></TD>
+
+<TD><FONT SIZE=-1>LU</FONT></TD>
+</TR>
+
+<TR>
+<TD><FONT SIZE=-1>MOTD</FONT></TD>
+
+<TD><FONT SIZE=-1>MO</FONT></TD>
+</TR>
+
+<TR>
+<TD><FONT SIZE=-1>MODE</FONT></TD>
+
+<TD><FONT SIZE=-1>M</FONT></TD>
+</TR>
+
+<TR>
+<TD><FONT SIZE=-1>KICK</FONT></TD>
+
+<TD><FONT SIZE=-1>K</FONT></TD>
+</TR>
+
+<TR>
+<TD><FONT SIZE=-1>USERHOST</FONT></TD>
+
+<TD><FONT SIZE=-1>USERHOST</FONT></TD>
+</TR>
+
+<TR>
+<TD><FONT SIZE=-1>USERIP</FONT></TD>
+
+<TD><FONT SIZE=-1>USERIP</FONT></TD>
+</TR>
+
+<TR>
+<TD><FONT SIZE=-1>ISON</FONT></TD>
+
+<TD><FONT SIZE=-1>ISON</FONT></TD>
+</TR>
+
+<TR>
+<TD><I><FONT SIZE=-1>SQUERY</FONT></I></TD>
+
+<TD><I><FONT SIZE=-1>SQUERY</FONT></I></TD>
+</TR>
+
+<TR>
+<TD><I><FONT SIZE=-1>SERVLIST</FONT></I></TD>
+
+<TD><I><FONT SIZE=-1>SERVLIST</FONT></I></TD>
+</TR>
+
+<TR>
+<TD><I><FONT SIZE=-1>SERVSET</FONT></I></TD>
+
+<TD><I><FONT SIZE=-1>SERVSET</FONT></I></TD>
+</TR>
+
+<TR>
+<TD><FONT SIZE=-1>REHASH</FONT></TD>
+
+<TD><FONT SIZE=-1>REHASH</FONT></TD>
+</TR>
+
+<TR>
+<TD><FONT SIZE=-1>RESTART</FONT></TD>
+
+<TD><FONT SIZE=-1>RESTART</FONT></TD>
+</TR>
+
+<TR>
+<TD><FONT SIZE=-1>CLOSE</FONT></TD>
+
+<TD><FONT SIZE=-1>CLOSE</FONT></TD>
+</TR>
+
+<TR>
+<TD><FONT SIZE=-1>DIE</FONT></TD>
+
+<TD><FONT SIZE=-1>DIE</FONT></TD>
+</TR>
+
+<TR>
+<TD><FONT SIZE=-1>HASH</FONT></TD>
+
+<TD><FONT SIZE=-1>HASH</FONT></TD>
+</TR>
+
+<TR>
+<TD><FONT SIZE=-1>DNS</FONT></TD>
+
+<TD><FONT SIZE=-1>DNS</FONT></TD>
+</TR>
+
+<TR>
+<TD><FONT SIZE=-1>SILENCE</FONT></TD>
+
+<TD><FONT SIZE=-1>U</FONT></TD>
+</TR>
+
+<TR>
+<TD><FONT SIZE=-1>GLINE</FONT></TD>
+
+<TD><FONT SIZE=-1>GL</FONT></TD>
+</TR>
+
+<TR>
+<TD><FONT SIZE=-1>BURST</FONT></TD>
+
+<TD><FONT SIZE=-1>B</FONT></TD>
+</TR>
+
+<TR>
+<TD><FONT SIZE=-1>CREATE</FONT></TD>
+
+<TD><FONT SIZE=-1>C</FONT></TD>
+</TR>
+
+<TR>
+<TD><FONT SIZE=-1>DESTRUCT</FONT></TD>
+
+<TD><FONT SIZE=-1>DE</FONT></TD>
+</TR>
+
+<TR>
+<TD><FONT SIZE=-1>END_OF_BURST</FONT></TD>
+
+<TD><FONT SIZE=-1>EB</FONT></TD>
+</TR>
+
+<TR>
+<TD><FONT SIZE=-1>END_OF_BURST_ACK</FONT></TD>
+
+<TD><FONT SIZE=-1>EA</FONT></TD>
+</TR>
+
+<TR>
+<TD><FONT SIZE=-1>PROTO</FONT></TD>
+
+<TD><FONT SIZE=-1>PROTO</FONT></TD>
+</TR>
+
+<TR>
+<TD><FONT SIZE=-1>JUPE</FONT></TD>
+
+<TD><FONT SIZE=-1>JU</FONT></TD>
+</TR>
+
+<TR>
+<TD><FONT SIZE=-1>OPMODE</FONT></TD>
+
+<TD><FONT SIZE=-1>OM</FONT></TD>
+</TR>
+
+<TR>
+<TD><FONT SIZE=-1>CLEARMODE</FONT></TD>
+
+<TD><FONT SIZE=-1>CM</FONT></TD>
+</TR>
+
+<TR>
+<TD><FONT SIZE=-1>ACCOUNT</FONT></TD>
+
+<TD><FONT SIZE=-1>AC</FONT></TD>
+</TR>
+</TABLE></CENTER>
+<FONT FACE="Arial,Helvetica"><FONT SIZE=-1><B>[</B><A HREF="#top">Back</A><B>]</B></FONT></FONT>
+<BR>
+<HR ALIGN=LEFT WIDTH=100% SIZE=2>
+<P><A NAME="chap3"></A><B><FONT SIZE=+2>3. Registration and syncronisation</FONT></B>
+<P><A NAME="chap3.1"></A><B><FONT SIZE=+1>3.1 Server registration and authentication</FONT></B>
+<P>After a TCP connection has been established, the server initally introduces
+itself via a "PASS" message as follows:
+<BLOCKQUOTE>
+<PRE><FONT COLOR="#00007F">PASS :[PASSWORD]</FONT></PRE>
+</BLOCKQUOTE>
+"PASSWORD" is simply compared with the password present in the destination
+servers config file, and is used to confirm credentials after the "SERVER"
+message has been recieved, as follows:
+<BLOCKQUOTE>
+<PRE><TT><FONT COLOR="#00007F">SERVER [SERVERNAME] [HOPCOUNT] [START TIME] [LINK TIME] [PROTOCOL] [NUMERIC/MAXCONN] :[DESCRIPTION]</FONT></TT></PRE>
+</BLOCKQUOTE>
+For Example:
+<BLOCKQUOTE>
+<PRE><B>1&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 3 4&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 5&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 6&nbsp;&nbsp; 7&nbsp;&nbsp;&nbsp;&nbsp; 8&nbsp;
+</B>SERVER irc.undernet.org 1 933022556 947908144 J10 AA]]] :[127.0.0.1] A Undernet Server.</PRE>
+</BLOCKQUOTE>
+<I>Notes:</I>
+<OL>
+<LI>
+The SERVER message, indicating this connection wishes to introduce a new
+server to the network.</LI>
+
+<LI>
+&nbsp;The name of the server you are introducing, a valid server name consists
+of [..defn..].</LI>
+
+<LI>
+&nbsp;The hop count of the server you are introducing, this is always 1
+when you are introducing yourself.</LI>
+
+<LI>
+&nbsp;The epoch timestamp specifying when the ircd was started.</LI>
+
+<LI>
+&nbsp;The epoch timestamp specifying the time the server initiated the
+link to the network.</LI>
+
+<LI>
+&nbsp;The Protocol identifier of this server.</LI>
+
+<OL>
+<LI>
+This token informs the network which protocol it is compliant with, eg:
+If it is a P10 compliant server, then the token will be "P10".</LI>
+
+<LI>
+&nbsp;If the server being introduced has not yet successfully synced its
+database with the network (Completed its net.burst - see 3.2), then the
+Protocol token should be prefixed with a J, instead of a P (Eg: J10) to
+indicate it is currently still <B>j</B>oining the network.</LI>
+
+<LI>
+&nbsp;The protocol token should always be JXX when the server is introducing
+<B>itself</B>.</LI>
+</OL>
+
+<LI>
+The numeric, and maximum connections identifier for this server.</LI>
+
+<OL>
+<LI>
+This token is formatted exactly the same as a client numeric is formatted.
+The first 2 characters identify the server's numeric, whilst in this situation,
+the final 3 characters define the maximum number of clients that this server
+can hold (and more importantly, the maximum number of numerics it will
+generate). This is always one less than a power of two, because the server
+uses this as a bitmask.  A server can give out a higher numeric than this,
+however it will be "anded" with this number to find it's entry slot.  The
+reason for this is so a server which is near the maximum number of clients
+can give out more numerics than it's using to prevent a new client getting a
+numeric that was used only seconds ago and maybe get messages destined to
+the old user.</LI>
+
+<LI>
+&nbsp;The example "AA]]]" shows that this is a server with numeric 0, which
+will generate client numerics up to 262,143.</LI>
+</OL>
+
+<LI>
+This final parameter simply consists of a textual description of the server
+prefixed by a colon. This is displayed in a clients WHOIS line, aswell
+as in the LINKS reply.  By convention, if this is a leaf server it contains
+the servers IP in square brackets at the beginning of the string,</LI>
+</OL>
+<A NAME="chap3.2"></A><B><FONT SIZE=+1>3.2 Network Database resyncronisation</FONT></B>
+<P>After the connection has been established and verified, the next step
+is to syncronise the database of client/server/channel information between
+the two servers.
+<BLOCKQUOTE><B>3.2.1 - SERVER Messages</B></BLOCKQUOTE>
+
+<BLOCKQUOTE>Server details are transmitted via "SERVER" messages similar
+to the initial introduction message, with the following format:</BLOCKQUOTE>
+
+<BLOCKQUOTE>
+<BLOCKQUOTE><TT><FONT COLOR="#00007F">[OWNING SERVER PREFIX] S [SERVERNAME]
+[HOPCOUNT] [START TIME] [LINK TIME] [PROTOCOL] [NUMERIC/MAXCONN] 0 :[DESCRIPTION]</FONT></TT></BLOCKQUOTE>
+<FONT COLOR="#000000">The syntax of this message is almost identical to
+the originally recieved server message, with the only exception being that
+the message is numeric prefixed, to indicate which server sent this message
+(and also therefore, which hub this new server is linked too). There is
+also a fixed "0" present before the Description field, this is a placeholder
+for future use and currently unused. [Isomer: Question, what IS this
+reserved for?] </FONT>
+<P><B>3.2.2 - NICK Messages</B></BLOCKQUOTE>
+
+<BLOCKQUOTE>Client information is transmitted via "NICK" messages, of the
+following format:</BLOCKQUOTE>
+
+<BLOCKQUOTE>
+<BLOCKQUOTE>
+<PRE><TT><FONT COLOR="#00007F">[NUMERIC PREFIX] N [NICK] [HOPCOUNT] [TIMESTAMP] [USERNAME] [HOST] &lt;+modes> [BASE64 IP] [NUMERIC] :[USERINFO]</FONT></TT></PRE>
+</BLOCKQUOTE>
+<FONT COLOR="#00007F">For Example:</FONT>
+<BLOCKQUOTE><TT><FONT COLOR="#000000">1&nbsp; 2 3&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+4 5&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 6&nbsp;&nbsp;&nbsp;&nbsp;
+7&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 8&nbsp;&nbsp;&nbsp;&nbsp;
+9&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 10&nbsp;&nbsp;&nbsp; 11</FONT></TT>
+<BR><TT><FONT COLOR="#000000">AF N Client1 1 947957573 User userhost.net
++oiwg DAqAoB AFAAA :Generic Client.</FONT></TT></BLOCKQUOTE>
+<I>Notes:</I>
+<OL>
+<LI>
+The numeric of the server sending this message. (And hence, owning this
+client).</LI>
+
+<LI>
+The "NICK" token.</LI>
+
+<LI>
+The nickname of this client, currently max 9 chars.</LI>
+
+<LI>
+The "Hopcount" of this client, Ie: how many servers away it is on.</LI>
+
+<LI>
+The epoch timestamp indicating when the user was created.</LI>
+
+<LI>
+The "User" part of the user@host mask.</LI>
+
+<LI>
+the "Host" part of the user@host mask.</LI>
+
+<LI>
+[<B>Optional</B>]: User modes. If present, this is always +&lt;user modes
+for this client>.  Note that the special +r usermode is followed by the
+client's account name; see the documentation for ACCOUNT.</LI>
+
+<LI>
+The real IP address of this client, a Base64 encoded 32bit int.</LI>
+
+<LI>
+This client's numeric, in SSCCC format.</LI>
+
+<LI>
+Free format user info line.</LI>
+
+<BR>&nbsp;</OL>
+</BLOCKQUOTE>
+
+<BLOCKQUOTE><B>3.2.3 - BURST Messages</B></BLOCKQUOTE>
+
+<BLOCKQUOTE>Channel details and membership information is synchronised
+in one (or more) BURST messages for each channel that exists, formatted
+as follows:</BLOCKQUOTE>
+
+<BLOCKQUOTE>
+<BLOCKQUOTE>
+<PRE><TT><FONT COLOR="#00007F">[NUMERIC PREFIX] B [CHANNEL] [CREATION TIMESTAMP] &lt;+MODES> &lt;ARG1> &lt;ARG2> [MEMBER LIST] &lt;:%BANS></FONT></TT></PRE>
+</BLOCKQUOTE>
+</BLOCKQUOTE>
+
+<BLOCKQUOTE>For Example:</BLOCKQUOTE>
+
+<BLOCKQUOTE>
+<BLOCKQUOTE>
+<PRE>1&nbsp; 2 3&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 4&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 5&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 6&nbsp;&nbsp; 7&nbsp; 8&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 9
+AZ B #coder-com 949217470 +tinkl key 56 AAAAA,AAAAB,AAAAC,ABAAA,ABAAB,ABAAC,ACAAA :%*!*@*.net</PRE>
+</BLOCKQUOTE>
+</BLOCKQUOTE>
+
+<BLOCKQUOTE><I>Notes:</I></BLOCKQUOTE>
+
+<OL>
+<LI>
+The numeric of the server sending this message.</LI>
+
+<LI>
+The "BURST" token.</LI>
+
+<LI>
+The name of the channel to which this data belongs. Currently #Channel
+and +Channel names can be sent in a BURST message, &amp;Channels are not
+because by definition they are local to the server.</LI>
+
+<LI>
+The epoch timestamp indicating when the channel was created.</LI>
+
+<LI>
+[<B>Optional</B>]: Channel Modes.</LI>
+
+<OL>
+<LI>
+The channel may have a number of modes set, aswell as relevant mode arguments
+in the following 2 parameters.</LI>
+</OL>
+
+<LI>
+[<B>Optional</B>]: Channel Key, this parameter is present if the channel
+modes contain a "k" mode.</LI>
+
+<LI>
+[<B>Optional</B>]: Channel Limit, this parameter is present if the channel
+modes contain a "l" mode.</LI>
+
+<LI>
+&nbsp;A <I>comma</I> seperated list of client numerics, with the following
+specific formatting rules to indicate +o, +v and +ov channel members.</LI>
+
+<OL>
+<LI>
+Numerics can have the following symbols appended on them; "<B>:ov</B>",
+"<B>:v</B>" or "<B>:o</B>". These indicate that this numeric is either
+Opped (<B>:o</B>), Voiced (<B>:v</B>) or both (<B>:ov</B>). This state
+applies to the numeric it is attached too, and all subsequent numerics
+until another state is encountered. <I>For Example:</I></LI>
+
+<LI>
+AAABA:ov, AAABB:o,AAABC,AAABD,AAABE:v,AAABZ</LI>
+
+<BR>Here, AAABA is both opped, and voiced, AAABB, AAABC and AAABD are opped
+leaving AAABE and AAABZ voiced.
+<LI>
+&nbsp;The first numeric of the member list will always contain a state
+symbol.</LI>
+</OL>
+
+<LI>
+A <I>space</I> seperated list of bans present in the channel. The start
+of the ban stream is indicated by a ":%", everything following the ":%"
+is the ban list.</LI>
+
+<BR><I>For Example:</I>
+<BR>:%*!*@*.foobar.net another!ban@*.com *!*fred@a.host.co.uk
+<BR>Would add the following bans to the channel:
+<P>*!*@*.foobar.net
+<BR>another!ban@*.com
+<BR>*!*fred@a.host.co.uk</OL>
+
+<BLOCKQUOTE>If the length of a BURST message exceeds the maximum lenght
+of a line (512 characters) then the remaining channel members/bans are
+sent in subsequent BURST lines. The subsequent burst lines are <B>only</B>
+used to add additional members to the channel, and if neccessary, channel
+bans. There will be no "Mode" parameters present. A sample additional burst
+line would be:</BLOCKQUOTE>
+
+<BLOCKQUOTE>
+<BLOCKQUOTE>
+<PRE>AZ BURST #coder-com 949217470 ACAAB:o,ACAAD :%*!*another@*.ban.com</PRE>
+</BLOCKQUOTE>
+</BLOCKQUOTE>
+
+<BLOCKQUOTE>Which adds two more opped members and a ban to the channel.</BLOCKQUOTE>
+
+<BLOCKQUOTE><B>3.2.4 - JUPE Messages</B></BLOCKQUOTE>
+
+<BLOCKQUOTE>Any currently unexpired JUPEs are transmitted via "JUPE" messages
+with the following format:</BLOCKQUOTE>
+
+<BLOCKQUOTE>
+<BLOCKQUOTE><TT><FONT COLOR="#00007F">[NUMERIC PREFIX] JU * (+|-)[SERVER
+NAME] [LIFETIME] [LAST MOD] :[REASON]</FONT></TT></BLOCKQUOTE>
+For example:</BLOCKQUOTE>
+
+<BLOCKQUOTE>
+<BLOCKQUOTE><TT>1&nbsp; 2&nbsp; 3 4&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+5&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 6&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+7</TT>
+<BR><TT><FONT COLOR="#000000">AZ JU * +juped.undernet.org 000003593 955419707
+:Juped Server</FONT></TT></BLOCKQUOTE>
+<I>Notes:</I></BLOCKQUOTE>
+
+<OL>
+<LI>
+The numeric of the server sending this message.</LI>
+
+<LI>
+The "JUPE" token.</LI>
+
+<LI>
+The target that should apply this JUPE (always "*" during bursts).</LI>
+
+<LI>
+The name of the server to JUPE, prefixed with a "+" if the JUPE is active,
+or with a "-" if it is not.</LI>
+
+<LI>
+The remaining absolute lifetime of the JUPE, expressed in seconds.</LI>
+
+<LI>
+The last time the JUPE was modified.</LI>
+
+<LI>
+The reason the JUPE was applied.</LI>
+</OL>
+<A NAME="chap3.3"></A><B><FONT SIZE=+1>3.3 Summary</FONT></B>
+<P>The following table summarises the sequence of events that occur when
+a server connects to another server. S1 is our server, and S2 is a HUB
+on the target network.
+<P>S1: Sends Password.
+<BR>S1: Sends initial SERVER message.
+<P><I>S2 Confirms S1 has the correct credentials, and if so, proceeds.
+If not, S1 is squit with a relevant reason.</I>
+<P>S2: Sends Password.
+<BR>S2: Sends initial SERVER message.
+<P><I>S1 Confirms S2 has the correct credentials, and if so, proceeds.
+If not, S2 is squit with a relevant reason.</I>
+<P><B><I>The follow occur asynchronously, however they have been shown
+seperately below for simplicity.</I></B>
+<P>S1: Sends all the servers it is aware of as a stream of SERVER messages.
+<BR>S1: Sends all the clients it is aware of as a stream of NICK messages.
+<BR>S1: Sends the database of channel states on the network, as a stream
+of BURST messages.
+<BR>S1: Sends all the jupes it is aware of as a stream of JUPE messages.
+<BR>S1: Sends a END_OF_BURST token (EB) to indicate it has finished sending.
+<P>S2: Sends all the servers it is aware of as a stream of SERVER messages.
+<BR>S2: Sends all the clients it is aware of as a stream of NICK messages.
+<BR>S2: Sends the database of channel states on the network, as a stream
+of BURST messages.
+<BR>S2: Sends all the jupes it is aware of as a stream of JUPE messages.
+<BR>S2: Sends a END_OF_BURST token (EB) to indicate it has finished sending.
+<P>S2: Sends an EOB_ACK token (EA) to indicate it has succesfully recieved
+the END_OF_BURST from S1
+<BR>S1: Sends an EOB_ACK token (EA) to indicate it has succesfully recieved
+the END_OF_BURST from S2
+<P><I>Example Session:</I>
+<PRE><FONT COLOR="#00007F">[WRITE]: PASS :54321
+[WRITE]: SERVER irc.undernet.org 1 947957852 947957852 J10 AB]]] :Undernet Client Server.
+[WRITE]: AB N MrFoo 1 947957852 ~me myhost.foobar.net +diksw DAqAoB ABAAA :Mr Foo (foo@bar.com).
+[WRITE]: AB B #mychannel 946101324 ABAAA:o
+[WRITE]: AB EB
+[ READ]: PASS :54321
+[ READ]: SERVER server1.undernet.org 1 947901540 947958150 J10 AFAD] :A Generic Server.
+[ READ]: AF S server2.undernet.org 2 0 947957585 P10 AZAD] 0 :[192.168.10.3] A Generic Server.
+[ READ]: AZ S server3.undernet.org 3 0 947957607 P10 AIAD] 0 :[192.168.10.5] A Generic Server.
+[ READ]: AF N Client1 1 947957573 Ident userhost.net +oiwg DAqAoB AFAAA :Generic Client.
+[ READ]: AZ N Client2 2 947957719 Ident userhost.net +iwg DAqAoB AZAAA :Generic Client.
+[ READ]: AI N Client3 3 947957742 Ident userhost.net +iwg DAqAoB AIAAA :Generic Client.
+[ READ]: AI N Client4 3 947958121 Ident userhost.net +iwg DAqAoB AIAAB :Generic Client.
+[ READ]: AF B #foobar 947957734 +tink akey AIAAB,AIAAA:v,AZAAA:o :%*!*another@*.ban.com *!*foo@bar.net
+[ READ]: AF B #coder-com 947957727 AIAAB,AZAAA:o
+[ READ]: AF B #another 946101321 AFAAA
+[ READ]: AF JU * +juped.undernet.org 3600 947958100 :Broken, please fix
+[ READ]: AF EB
+[WRITE]: AB EA
+[ READ]: AF EA</FONT></PRE>
+<FONT FACE="Arial,Helvetica"><FONT SIZE=-1><B>[</B><A HREF="#top">Back</A><B>]</B></FONT></FONT>
+<BR>
+<HR WIDTH="100%">
+<BR><A NAME="chap4"></A><B><FONT SIZE=+2>4. Continuous Operation</FONT></B>
+<P>This chapter provides details of the messages that can be sent after
+successfully linking to a network, and synchronising the channel/user database.
+<P><A NAME="chap4.1"></A><B><FONT SIZE=+1>4.1 Channel state operations</FONT></B>
+<P>There are a number of messages that can modify the state of a channel,
+these are:
+<OL><B>4.1.1 - MODE</B>
+<P>The MODE message can modify channel modes and bans, and also give or
+take operator/voice status from channel members.
+<OL>&nbsp;
+<BR><TT><FONT COLOR="#00007F">[NUMERIC PREFIX] M [CHANNEL] (+|-)[MODESTRING]
+&lt;MODESTRING PARAMETERS></FONT></TT></OL>
+
+<P><BR>For Example:
+<OL>&nbsp;
+<BR><TT>1&nbsp;&nbsp;&nbsp;&nbsp; 2 3&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+4&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 5</TT>
+<BR><TT>AZAAA M #coder-com +stinlko 500 TestKey BAC</TT></OL>
+<I></I>
+<P><BR><I>Notes:</I>
+<BR>&nbsp;
+<OL>
+<LI>
+The numeric of the user issuing this MODE command. It can be assumed this
+user is opped on the target channel.</LI>
+
+<LI>
+The "MODE" token.</LI>
+
+<LI>
+The target channel.</LI>
+
+<LI>
+The "Mode string".</LI>
+
+<OL>
+<LI>
+This consists of up to 6 '+' or '-' (add or remove) prefixed channel modes.
+(If no '+' or '-' are specified, a '+' is assumed unless a '-' has been
+encountered previously in the mode string). For example, '+s+t+n-l-io'
+is a valid mode string, as is '+stnmov'.</LI>
+
+<BR>&nbsp;
+<LI>
+Valid Mode modes are:</LI>
+</OL>
+</OL>
+
+<OL>
+<OL>&nbsp;
+<TABLE BORDER COLS=3 WIDTH="85%" NOSAVE >
+<TR NOSAVE>
+<TD NOSAVE><B>Token</B></TD>
+
+<TD><B>Function</B></TD>
+
+<TD><B>Parameters</B></TD>
+</TR>
+
+<TR NOSAVE>
+<TD NOSAVE>p</TD>
+
+<TD>Sets/Unsets 'Private' Flag.</TD>
+
+<TD>None.</TD>
+</TR>
+
+<TR>
+<TD>s</TD>
+
+<TD>Sets/Unsets 'Secret' Flag.</TD>
+
+<TD>None.</TD>
+</TR>
+
+<TR>
+<TD>m</TD>
+
+<TD>Sets/Unsets 'Moderated' Flag.</TD>
+
+<TD>None.</TD>
+</TR>
+
+<TR>
+<TD>n</TD>
+
+<TD>Sets/Unsets 'External Messages' Flag.</TD>
+
+<TD>None.</TD>
+</TR>
+
+<TR>
+<TD>t</TD>
+
+<TD>Sets/Unsets 'Topic Limit' Flag.</TD>
+
+<TD>None.</TD>
+</TR>
+
+<TR>
+<TD>i</TD>
+
+<TD>Sets/Unsets 'Invite only' Flag.</TD>
+
+<TD>None.</TD>
+</TR>
+
+<TR>
+<TD>l</TD>
+
+<TD>Sets/Unsets 'Channel Limit' Flag.</TD>
+
+<TD>The channel limit.</TD>
+</TR>
+
+<TR>
+<TD>k</TD>
+
+<TD>Sets/Unsets 'Channel Key' Flag.</TD>
+
+<TD>The channel keyword (Password).</TD>
+</TR>
+
+<TR>
+<TD>o</TD>
+
+<TD>Ops and Deops users.</TD>
+
+<TD>Numeric of user to be opped.</TD>
+</TR>
+
+<TR>
+<TD>v</TD>
+
+<TD>Voice</TD>
+
+<TD>Numeric of user to be voiced.</TD>
+</TR>
+
+<TR>
+<TD>b</TD>
+
+<TD>Ban</TD>
+
+<TD>Ban string.</TD>
+</TR>
+</TABLE>
+</OL>
+</OL>
+
+<OL>
+<LI>
+The "Mode string Parameters".</LI>
+
+<OL>
+<LI>
+This is a matching list of parameters to the modes supplied in the "Modestring".</LI>
+
+<BR><I>For Example:</I>
+<BR>If the Modestring is "+stnlo", a typical parameter string would be
+"500 AZAA". The first 3 modes, 's', 't' and 'n' do not require parameters,
+so non are present. The following two, 'l' and 'o' both require parameters,
+so they are 500 and AZAAA respectively (This sets the channel limit to
+500 users, and ops the numeric AZAAA).</OL>
+</OL>
+
+<P><BR>N.B: The "MODE" message is also used to modify a client's user modes,
+not just channel modes. See <A HREF="#chap4.2">section 4.2</A> for details.</OL>
+
+<OL><B>4.1.2 - OPMODE</B>
+<P>The OPMODE message is identical in syntax to the MODE message, however
+it will only ever have an operator as the source. It is likely that the
+source of this mode will not have ops in the target channel, but it should
+succeed never the less.
+<P><B>4.1.3 - JOIN</B>
+<P><B>4.1.4 - PART</B>
+<P><B>4.1.5 - KICK</B>
+<P><B>4.1.6 - TOPIC</B>
+<P><B>4.1.7 - CLEARMODE</B>
+<BR>&nbsp;
+<OL><TT>AZAAA CM #coder-com ovpsmikbl</TT></OL>
+</OL>
+<A NAME="chap4.2"></A><B><FONT SIZE=+1>4.2 Client state operations</FONT></B>
+<BLOCKQUOTE><B>4.2.1 - NICK</B>
+<BLOCKQUOTE><TT>AZAAA N Nick2 955423230</TT></BLOCKQUOTE>
+<B>4.2.2 - MODE</B>
+<BLOCKQUOTE><TT>AZAAA M Nick2 :+odi</TT></BLOCKQUOTE>
+<B>4.2.3 - ACCOUNT</B>
+<BLOCKQUOTE><TT>AX AC AZAAA oper</TT></BLOCKQUOTE>
+<P>The ACCOUNT message provides a way for servers, such as the channel service
+server, to set the account name information that is associated with a client.
+Once set, it cannot be unset or changed, and will be propagated in NICK during
+net bursts using the special user mode +r followed by the account name.
+</BLOCKQUOTE>
+<A NAME="chap4.3"></A><B><FONT SIZE=+1>4.3 Channel/Client Messaging.</FONT></B>
+<BLOCKQUOTE><B>4.3.1 - PRIVMSG</B>
+<P><B>4.3.2 - NOTICE</B>
+<P><B>4.3.3 - CNOTICE</B>
+<P><B>4.3.4 - CPRIVMSG</B>
+<BR>&nbsp;</BLOCKQUOTE>
+<FONT FACE="Arial,Helvetica"><FONT SIZE=-1><B>[</B><A HREF="#top">Back</A><B>]</B></FONT></FONT>
+<BR>
+<HR ALIGN=LEFT WIDTH=100% SIZE=2>
+<P><A NAME="chap5"></A><B><FONT SIZE=+2>5. Programmers reference: Client/Server
+Structures</FONT></B>
+<P>This section provides information on the standard Client/Server structures,
+for easy reference during development.
+<P><I>[..Link to autogenerated struct.html..]</I>
+<P><FONT FACE="Arial,Helvetica"><FONT SIZE=-1><B>[</B><A HREF="#top">Back</A><B>]</B></FONT></FONT>
+<BR>
+<HR ALIGN=LEFT WIDTH=100% SIZE=2>
+<BR><A NAME="chap7"></A><B><FONT SIZE=+2>7. FAQ</FONT></B>
+<P>Frequently asked questions.
+<UL>
+<LI>
+Q. How..</LI>
+
+<LI>
+A. ...</LI>
+</UL>
+<FONT FACE="Arial,Helvetica"><FONT SIZE=-1><B>[</B><A HREF="#top">Back</A><B>]</B></FONT></FONT>
+<BR>
+<HR WIDTH="100%">
+<P><A NAME="chap8"></A><B><FONT SIZE=+2>8. Update History</FONT></B>
+<P>[2000-01-20]: Initial draft, structure, background info.
+<BR>[2000-02-13]: Added initial BURST documentation.
+<BR>[2000-02-14]: Continued BURST documentation / Begin NICK and SERVER
+documentation.
+<BR>[2000-02-26]: Continued chapter 5, few example fixes, added token table
+from msg.h. -Gte.
+<BR>[2000-03-02]: Added NICK spec. -Gte.
+<BR>[2000-03-18]: Added JUPE spec. -Kev
+<BR>[2000-04-10]: Added information about OPMODE and CLEARMODE tokens.
+-Kev
+<BR>[2000-04-11]: Started work on chapter 4. -Gte
+<BR>[2000-06-01]: Changed some info about the max number of clients -Isomer
+<BR>[2002-01-11]: Wrote a specification for ACCOUNT and noted that a usermode
+in a NICK message may have an argument. -Kev
+<P><A NAME="chap8.1"></A><B><FONT SIZE=+1>8.1 TODO</FONT></B>
+<UL>
+<LI>
+Finish Chapter 5.</LI>
+
+<LI>
+Go through examples, and ensure they are all correct.</LI>
+
+<LI>
+Add common function headers, with argv listings.</LI>
+
+<LI>
+Add description of further server to server messages, with special cases
+and outcomes.</LI>
+
+<LI>
+Add FAQ Section.</LI>
+</UL>
+<FONT FACE="Arial,Helvetica"><FONT SIZE=-1><B>[</B><A HREF="#top">Back</A><B>]</B></FONT></FONT>
+</BODY>
+</HTML>
diff --git a/doc/readme.asll b/doc/readme.asll
new file mode 100644 (file)
index 0000000..a48470b
--- /dev/null
@@ -0,0 +1,25 @@
+AsLL preliminary documentation, last updated 13 Jun 2002
+
+Server-to-server ping format:
+
+<prefix> G !<local-ts> <target> <local-ts>
+
+prefix = origin server numeric
+local-ts = local timestamp, as "seconds.miliseconds"
+target = target server numeric
+
+The local-ts is also sent instead of the origin field,
+so RTT information can be collected from non-AsLL servers,
+while preserving backward compatibility.
+
+
+Server-to-server pong format:
+
+<prefix> Z <origin> <target> <remote-ts> <diff> <local-ts>
+
+prefix = origin server numeric
+origin = origin server numeric
+target = target server numeric
+remote-ts = remote timestamp as received from an AsLL PING
+diff = difference between local-ts and remote-ts in miliseconds (integer)
+local-ts = local timestamp, as "seconds.miliseconds"
diff --git a/doc/readme.chroot b/doc/readme.chroot
new file mode 100644 (file)
index 0000000..2c42cac
--- /dev/null
@@ -0,0 +1,91 @@
+Using Chroot With IRCD
+
+Introduction
+
+Many system administrators like to run certain daemons within a
+"jail," a secure area of the file system that the daemon supposedly
+cannot break out of.  That way, if the daemon is compromised somehow,
+the attacker cannot get out and affect the rest of the system in any
+way.  There are problems with this--the standard UNIX way of doing
+this is with the chroot() call, which has been deprecated by the
+UNIX98 standard.  Moreover, if an attacker has root within the jail,
+it is trivial to get *out* of the jail in most circumstances.
+Nevertheless, it is still often a good idea, and some systems can use
+more secure jails than other systems.
+
+Older versions of ircd supported chroot() operation within the server
+itself, but these were fraught with problems--chroot() can only be
+called by a process running as root, so ircd had to be started as
+root, typically by making it setuid, and would then have to drop those
+privileges after calling chroot().  Moreover, the design of the server
+would require that the server binary be in DPATH, or the /RESTART
+command would not work.  In fact, /RESTART still wouldn't work,
+because the server would then attempt to change directories to a DPATH
+relative to the current root directory--and of course, the root
+directory often would not contain the shared libraries necessary for
+the ircd to even start.
+
+Configuring the Server For Use With Chroot
+
+In the versions of ircd starting with u2.10.11, all the setuid and
+chroot() code has been removed from the server.  It is still possible
+to cause the daemon to run in a chroot() jail, however, through the
+use of a wrapper script.  This requires making all paths compiled in
+to the server be relative to the new root directory; fortunately, this
+can be done by giving the configure script the --with-chroot=<dir>
+option.  The <dir> argument specifies to configure where the root
+directory will be, and the server restart path, data path,
+configuration file, and debug log files will all be modified to be
+relative to this root directory.  If the data path or configuration
+files cannot be made relative to the specified root directory,
+configure will issue an error message and exit; if the server restart
+path is not relative to the specified root directory, configure will
+issue a warning.
+
+The various paths are made relative to the root directory through the
+use of simple edits to their string representation.  As an example,
+assume that we will be using the root directory "/home/ircd"; if the
+data path is "/home/ircd/lib," the data path that will be compiled
+into the server will be simply "/lib"; if, on the other hand, the
+specified data path were "/usr/local/lib/ircd," configure would issue
+an error, since there is no way to make the data path relative to the
+specified root directory.
+
+Preparing the Root Directory
+
+Most modern operating systems use shared libraries.  When using
+chroot(), these libraries are searched for relative to the new root
+directory, and they must be present in order for a program to
+execute.  The root directory must be prepared, therefore, by coping
+these libraries into the correct place.  A script for this purpose has
+been provided in tools/mkchroot.  This script relies on the command
+"ldd," which is used to report which shared libraries are used by a
+particular program; it also relies on ldd printing out the full path
+to those libraries.  If either of these conditions is not met, it will
+be necessary to track down the libraries by hand and place them into
+the appropriate locations.  The tools/mkchroot script takes as its
+first argument the path to the directory to be prepared as a root
+directory; following this argument should be a list of programs that
+will be running with that directory as the root directory.
+
+Using the Wrapper
+
+Also provided in the tools subdirectory are the sources for a simple
+wrapper program that can be used to start ircd.  The program can be
+compiled by executing "cc -o wrapper tools/wrapper.c"; it must be run
+as root, but do not install it as root, since that would be a major
+security risk.  This tool can be used to set the hard limit on file
+descriptors, as well as a root directory, and so may be useful to the
+administrator even if chroot() operation is not desired.  A summary of
+the command line options for the wrapper tool can be obtained with the
+"-h" option.  To set the file descriptor limit, use the "-l" option
+followed by the desired number of file descriptors; to select an
+alternative root directory, use "-c" followed by the desired root
+directory.  You must use the "-u" option to specify a user name (or
+user ID) that the command should be run as; otherwise, the command
+will be run as root, which is not what you want (and why you should
+never install this program setuid root).  Follow the command line
+arguments with "--" and the full path to the command that you wish to
+run, along with arguments to that command.  The "--" tells the wrapper
+program to stop interpreting options, and is very important if you
+must give the command any options.
diff --git a/doc/readme.crules b/doc/readme.crules
new file mode 100644 (file)
index 0000000..803f06f
--- /dev/null
@@ -0,0 +1,126 @@
+SmartRoute
+Rule based connects
+Draft 4 - Aug 19, 1994
+by Tony Vencill
+
+Rule based connects allow an admin to specify under what conditions
+a connect should not be allowed.  If no rules are specified for a
+given C and/or N line it will be allowed under any condition.
+
+A rule may consist of any legal combination of the following functions
+and operators.
+
+Functions
+---------
+connected(targetmask)     - true if a server other than that processing
+                            the rule is connected that matches the
+                            target mask
+directcon(targetmask)     - true if a server other than that processing
+                            the rule is directly connected that matches
+                            the target mask
+via(viamask, targetmask)  - true if a server other than that processing
+                            the rule matches the target mask and is
+                            connected via a directly connected server
+                            that matches the via mask
+directop()                - true if an oper is directly connected
+
+Unary operators
+---------------
+!    eg: !argument        - true if the argument is false
+
+Binary operartors
+-----------------
+&&   eg: arg1&&arg2       - true if arg1 and arg2 are both true
+||   eg: arg1||arg2       - true if arg1, arg2, or both are true
+
+Parenthesis () are allowed for grouping arguments, but if no parenthesis
+are included, && will take precedence over ||, ! will take precedence
+over both && and ||, and the function will be evaluated from left to
+right.  White space in a rule is ignored.  Invalid characters in a rule
+will lead to the rule being ignored.
+
+Examples
+--------
+
+A simple example of a connect rule might be:
+
+connected(*eu.under*)
+
+This might be used in a US undernet server for a Europe CN pair to
+insure that a second Europe link is not allowed if one US-EU link
+already exists.  Note that on the undernet, US server names are
+city.state.us.undernet.org and Europe server names are
+city.country.eu.undernet.org.
+
+A more interesting example might be:
+
+connected(*eu.under*) && 
+  ( !direct(*eu.under*) || via(manhat*, *eu.under*) )
+
+Imagine the Boston undernet server uses this rule on its Europe CN
+pairs.  This says that if a Europe server is already connected, a
+Boston-Europe connect will not be allowed.  It also says that if a
+Europe server does already exist and Boston is not directly connected
+to one or more Europe servers or Manhattan is, the Boston-Europe
+connect will not be allowed.  This has the effect of allowing multiple
+US-EU links but attempting to limit these links to one server (ie:
+Boston will not initiate its first Europe link if another server is
+already linking Europe).  This rule will also prefer to let Manhattan
+handle the US-EU link by disallowing Boston-Europe links if a Europe
+server is already linked to Manhattan.
+
+A example of the remaining function, directop(), is:
+
+connected(*eu.under*) || directop()
+
+If this line is used on Boston for the Paderborn CN pair, it will allow
+connects to Paderborn only if another Europe server is not already
+connected and there is not an oper on Boston.  If this rule is
+overrideable (ie: is applied only to autoconnects as described below),
+then it will disallow Boston autoconnects to Paderborn while a Boston
+oper is online, but allow oper-initiated connects to Paderborn under any
+circumstance.  This directop() function could be used to invoke less
+prefered routes only when an oper is not present to handle routing, or
+conversly to allow use of less preferable routes only when an oper is
+present to monitor their performance.
+
+ircd.conf entries
+-----------------
+
+A rule is listed in the ircd.conf file using a D or d line (which can
+be thought of as a "disallow" line).  D lines will apply to all oper
+and server originated connects, while d lines will apply only to
+autoconnects (ie: they are overrideable by opers).  The formats are:
+
+D:targetmask::rule
+d:targetmask::rule
+
+Remember that newlines are not allowed in conf lines.  Two examples
+(from above) are:
+
+D:*eu.under*::connected(*eu.under*)
+d:*eu.under*::connected(*eu.under*) || directop()
+
+Connects originating from other servers will be checked against and
+matching D lines, while matching d lines will be ignored as it will not
+be clear whether or not the connection attempt is oper initiated.
+
+Checking and viewing rules
+--------------------------
+
+The chkconf program that comes with the servers has been modified to
+also check your connect rules.  If running in debug mode, parsing errors
+will show up at debug level 8.  To view rules online, "/stats d" can be
+used to see all rules and "/stats D" can be used to view those rules
+which affect oper initiated connects and accepts.
+
+Processing and storage
+----------------------
+
+The rules are parsed when the conf file is read and transformed into a
+more efficiently computed form, then all applicable rules are
+evaluated each time a connect command is given or an autoconnect is
+due.  If more than one applicable rule is given, only one need
+evaluate to true for the connect to be allowed (ie: the rules are ored
+together).  Note that conditions that exist when the connect is
+initiated might differ from conditions when the link is established.
diff --git a/doc/readme.cvs b/doc/readme.cvs
new file mode 100644 (file)
index 0000000..ddc14d5
--- /dev/null
@@ -0,0 +1,42 @@
+Notes on checking out from the Undernet CVS archive.
+
+The main trunk of the tree (HEAD) will be used for development only.
+When the maintainers believe the code is stable enough to prepare for
+a release, they will make a branch for that release series.
+
+Each branch will have a base name, which is the name of the release
+series where dots are replaced with underscores.  The branch name will
+be the base name with the suffix "_branch".  Once an official release
+is made, each release branch will have one or more fixed tags and one
+moving tag.  The fixed tags will indicate specific patchlevels, and
+have the base name with a suffix giving the zero-based patchlevel.
+The moving tag's name will be the base name, and will always point to
+the same state as some fixed tag on the branch.
+
+This allows developers to easily track the most recent version of any
+branch (by checking out using the branch's name), and allows server
+admins to easily track the most recent release on the branch (by
+checking out using the branch's base name).
+
+For example, for the ircu2.10.12 release series, the branch's base
+name is u2_10_12.  The branch's name is u2_10_12_branch.  The first
+release (ircu2.10.12) would be permanently tagged as u2_10_12_0, and
+until an update is released, it would also have the tag u2_10_12.
+When the first update is released, it would be permanently tagged as
+u2_10_12_01, and the tag u2_10_12 would be changed to point to it.
+
+If the current stable series is 2.10.12, server admins should check
+out the code using the command:
+  cvs -d :pserver:anonymous@cvs.undernet.org:/cvsroot/undernet-ircu co -r u2_10_12 -P ircu2.10
+Admins may only run unreleased code on Undernet with coder-com
+approval.  The command above will retrieve the most recent release.
+
+Developers should check out the release branch using the command:
+  cvs -d :pserver:anonymous@cvs.undernet.org:/cvsroot/undernet-ircu co -r u2_10_12_branch -P ircu2.10
+
+http://sourceforge.net/cvs/?group_id=63470 gives more information on
+using CVS to access the ircu code; http://www.nongnu.org/cvs/ gives
+more information on using CVS in general.
+
+NOTE: Release before ircu2.10.12 used a different branching scheme.
+Older revisions of this readme.cvs explain that system.
diff --git a/doc/readme.features b/doc/readme.features
new file mode 100644 (file)
index 0000000..045eec5
--- /dev/null
@@ -0,0 +1,936 @@
+Many of the old compile-time options are now configured through the
+server configuration file, ircd.conf.  This file is intended to
+document each of these features.  Logging, although also configured
+through the use of Feature entries, is documented in doc/readme.log.  NOTE
+THAT THESE NAMES ARE CASE SENSITIVE!  Values are not case sensitive
+unless stated otherwise in the documentation for that feature.
+
+DOMAINNAME
+ * Type: string
+ * Default: picked by ./configure from /etc/resolv.conf
+
+This option allows you to specify what you consider to be "local."  It
+is only used for statistics.  When you issue the IRC command /STATS w,
+the server will respond with statistics of how many clients have been
+connecting to your server in the last minute, hour and day.  It will
+give these statistics for all connections (including the servers), all
+clients (from anywhere) and also for clients whose hostname ends on
+the domain you specify here.  So if you are an ISP and you want to
+know what the client load from your own domain is, specify that domain
+here.  If you are unsure what to do, then it isn't really important
+what you give here, just don't give an empty string.  A good guess is
+the last two parts of your own hostname (i.e., if your hostname is
+foo.bar.nowhere.org, specify "nowhere.org").  Note that the string you
+give should NOT start with a "." and you should not use quotes.
+
+RELIABLE_CLOCK
+ * Type: boolean
+ * Default: FALSE
+
+You should really ONLY specify "TRUE" here when your system clock is
+stable and accurate at all times (within a few seconds).  If you are
+running ntpdate on a regular basis, or an equivalent like xntpd, to
+keep your system clock synchronized over the network, then you might
+have an accurate clock.  However, this is not guaranteed; for example,
+it is known that xntpd gives unstable results on Linux in some cases.
+Note that an unstable clock is worse then an clock that has a constant
+offset, because the servers attempt to correct for a constant offset,
+but do not correct jumps of your system clock!  In general you SHOULD
+be running ntpdate or equivalent AND make sure it works when you run a
+production server on Undernet.  Otherwise leave your clock alone and
+specify "FALSE" here.  If unsure specify "FALSE"!
+
+BUFFERPOOL
+ * Type: integer
+ * Default: 27000000
+
+This specifies the maximum amount of RAM that your server will
+allocate for buffering sendQs.  Small leafs can use a value as little
+as 1000000, while large HUBs need to specify a value as high as
+20000000.  If you run out of memory, clients and/or servers are
+dropped with the error "Buffer allocation error"; then you will have
+to increase this number (and install more RAM if appropriate).  If you
+want a more educated guess for this value then realize that any value
+is good if you _really_ would rather drop servers and clients than
+allocate more memory; this will be the case when there is the danger
+you may run out of memory for other allocations.  Even if you run the
+daemon on a dedicated machine, specifying all of the RAM you have is a
+bad thing, because running out of memory is a lot worse than dropping
+clients in a controlled way; if possible you should have memory left
+for all the internal structures (channels, clients, ban lists, receive
+buffers) at all times.  On average, clients seem to use 150 bytes of
+sendQ, but at peak moments this can easily increase to 2032 bytes per
+client (sendQs are allocated in chunks of 2032 bytes).  The maximum
+possible amount that can be allocated for sendQs is the number of
+connected clients times whatever you specified as the maximum sendQ in
+your Class blocks in the ircd.conf file.  That value will likely be larger
+then the amount of RAM you have.  The educated guess I talked about
+earlier would be "number of clients" times * 2048 bytes + "size of
+net.burst" * n, where "n" is 1 for leafs and up to 5 for HUBs.  The
+"size of net.burst" is about 125 bytes per online client (on the whole
+network).  For large HUBs with 4000 clients on a network with 30,000
+users, this results in 27 Mb.  Leafs could use 12 Mb.  Of course you
+can use less when you have less than 4000 local clients.  This value
+is in bytes.
+
+HAS_FERGUSON_FLUSHER
+ * Type: boolean
+ * Default: FALSE
+
+If you have a server with a lot of resources available, this option
+will cause the server to attempt to flush its internal buffers before
+dropping clients during a net break.  Don't define this if you don't
+know for certain; if you're not careful this can end up rebooting
+FreeBSD boxes.  For more information, refer to freebsd.txt, also in
+this directory.
+
+CLIENT_FLOOD
+ * Type: integer
+ * Default: 1024
+
+Currently, everything that a client sends to a server is read by the
+server and stored in a buffer (the clients receive queue).  The server
+will process messages from this queue one by one (running over all
+clients each time).  When a client sends new messages faster they get
+processed, and the size of its receive buffer reaches this value, the
+client is dropped with the error "Excess flood."  A reasonable value
+is 1024 bytes.  The maximum size is 8000 bytes.
+
+SERVER_PORT
+ * Type: integer
+ * Default: 4400
+
+When an IRC operator attempts a connect to another server, he or she
+may not know which port the connect should go to.  In this server
+version, that operator may use the special port 0, in which case the
+server will take the port from the Connect block.  If no port is
+specified in the Connect block, however, the port specified by this
+option will be used instead.
+
+NODEFAULTMOTD
+ * Type: boolean
+ * Default: TRUE
+
+Every time a client connects to your server, the full Message of the
+Day (as specified by the Motd blocks or by the file specified by the MPATH
+option) is sent to the client.  The server sends the Message of the
+Day even though many clients permit the user to ignore it.  Many users
+never read the message of the day anyway, making it a huge waste of
+bandwidth.  If you specify "TRUE" here, then the server won't send the
+MOTD to the client by default; instead, it will only tell the client
+when the MOTD was last changed, and give instructions on how to obtain
+it by typing /MOTD.
+
+MOTD_BANNER
+ * Type: string
+ * Default: NULL
+
+If you enable NODEFAULTMOTD, this specifies a one-line banner to be sent
+to the client in addition to the instructions mentioned above.
+
+PROVIDER
+ * Type: string
+ * Default: NULL
+
+This string as added to the 001 numeric prefixed with "via" before the nick.
+It's used for providing promotional space to providers as per CFV-202
+
+KILL_IPMISMATCH
+ * Type: boolean
+ * Default: FALSE
+
+When a client connects to your server, the IP address of the client is
+reverse-resolved to obtain a hostname.  Then that hostname is resolved
+to an IP address and compared with the IP address of the client.  If
+they don't match, the client will appear with the IP address instead
+of the hostname, unless KILL_IPMISMATCH is "TRUE," in which case the
+client is simply disconnected.
+
+IDLE_FROM_MSG
+ * Type: boolean
+ * Default: TRUE
+
+The IRC command WHOIS gives an idle time for clients.  If you want
+this idle time to be set to zero only when the client sends a PRIVMSG,
+then you should specify "TRUE" here.  If you specify "FALSE," then the
+idle time will be nullified on all messages except the server
+PING/PONG.
+
+HUB
+ * Type: boolean
+ * Default: FALSE
+
+All servers of an IRC "network" are connected in a "tree" (no loops).
+Servers that are only connected to one other server (called the
+"uplink") are called "leafs"; servers that are connected to more than
+one other server are called HUBs.  If you specify "FALSE" here then
+your server will prevent itself from accidentally connecting to two
+servers at once, thus keeping servers in poor network locations from
+routing traffic.  Note that on Undernet, all newly linked servers are
+linked as leafs during their test phase, and should specify "FALSE"
+here.
+
+WALLOPS_OPER_ONLY
+ * Type: boolean
+ * Default: FALSE
+
+Setting this option removes the ability for clients that are not IRC
+operators to see wallops messages.
+
+NODNS
+ * Type: boolean
+ * Default: FALSE
+
+If you are playing with the server off-line, and no DNS is available,
+then long delays occur before the server starts up because it tries to
+resolve the name given in the General block (which usually isn't given
+in /etc/hosts) and for each connecting client.  If you specify "TRUE"
+here, then a DNS lookup will be done only for the real hostname, and
+the server will not try to resolve clients that connect to
+"localhost."  Note that other DNS lookups are still done for outbound
+connections.
+
+RANDOM_SEED
+ * Type: string
+ * Default: none
+
+When a client connects, the server sends the client a "cookie,"
+consisting of a random number.  The client must return the cookie to
+the server verbatim.  This is done to prevent IP spoofing.  The cookie
+is generated by a pseudorandom number generator included in ircd.
+This generator must be seeded with a phrase that is kept secret, to
+ensure that the numbers it generates are not easily guessed.  The
+value given to RANDOM_SEED may be a string of any length.  It should
+not contain any characters that are considered special by the
+configuration file system, such as ":" or "#"; the string should be at
+least 8 characters long, but longer strings are better.  The
+RANDOM_SEED may not be retrieved online.
+
+DEFAULT_LIST_PARAM
+ * Type: string
+ * Default: none
+
+The LIST command takes a single optional argument.  If given, that
+argument is either a channel or a filter.  If that argument is not
+given, then by default, /LIST will list all channels on the network.
+Needless to say, this can generate a large amount of data on large
+networks with many channels, as well as chewing up a lot of CPU time.
+Server administrators can therefore set a default filter to be applied
+to the channel list if the optional argument to LIST is omitted.
+
+NICKNAMEHISTORYLENGTH
+ * Type: integer
+ * Default: 800
+
+This value specifies the length of the nick name history list, which
+is used for /WHOWAS and some nickname chasing in /KILL and /KICK.  It
+uses about 300 to 400 bytes per entry.  Note that at a net break, so
+many client disappear that the whole "whowas" list is refreshed a few
+times (unless you make it rather large).  A reasonable value is "total
+number of clients" / 25.
+
+HOST_HIDING
+ * Type: boolean
+ * Default: TRUE
+
+This selects whether local users can set umode +x, thus allowing them
+to hide their hostname if they have also registered with a channel
+service (i.e. they have the ACCOUNT flag set).
+
+HIDDEN_HOST
+ * Type: string
+ * Default: users.undernet.org
+
+This selects the suffix for the hidden hostmask (see HOST_HIDING).
+
+HIDDEN_IP
+ * Type: string
+ * Default: 127.0.0.1
+
+This selects a fake IP to be shown on /USERIP and /WHO %i when the
+target has a hidden host (see HOST_HIDING).
+
+CONNEXIT_NOTICES
+ * Type: boolean
+ * Default: FALSE
+
+This feature controls the generation of server notices when a user
+connects to or disconnects from the server.  Enabling this feature may
+have a performance impact.
+
+KILLCHASETIMELIMIT
+ * Type: integer
+ * Default: 30
+
+If a user changes his or her nickname just before an operator issues a
+/KILL, the /KILL will be changed to follow the user the operator
+intended to get.  This option specifies the time limit, in seconds,
+for this nickname change; if the user changed his or her nickname more
+than this many seconds ago, the /KILL will not be changed.  Don't
+change this unless you really need to.
+
+MAXCHANNELSPERUSER
+ * Type: integer
+ * Default: 10
+
+This is the maximum number of channels a user can be in at a time.
+The "mandatory" value on Undernet is currently 10.  Since it only
+influences the local server when you decrease it, its up to you to
+decide if you want to use a smaller value.  Do not use a larger value
+however, because it DOES cost more memory and bandwidth on all other
+servers when you allow users to join more channels simultaneously.
+One of the most important reasons to choose a smaller value is the
+fact that the "GUI" clients tend to stay on every channel they join
+(they aren't bothered by flooding in other channels).  It DOES take
+your bandwidth however to send all those messages for 10 different
+channels to all your users.
+
+AVBANLEN
+ * Type: integer
+ * Default: 40
+
+This is the expected average ban mask length.  Leave it at 40.
+
+MAXBANS
+ * Type: integer
+ * Default: 45
+
+This is the maximum number of bans a user may set on a given channel.
+
+MAXSILES
+ * Type: integer
+ * Default: 15
+
+This is the maximum number of masks a user can silence at a time.  The
+silence command allows users to filter messages directed at them from
+certain users or domains, at the source server.  Increasing this
+number allows users to use up more memory with inefficient use of the
+command.  If you're not sure, don't change this.
+
+HANGONGOODLINK
+ * Type: integer
+ * Default: 300
+
+Often the net breaks for a short time and it is useful to try to
+reestablish the same connection faster than CONNECTFREQUENCY would
+allow, but to keep from trying again on a bad connection, we require
+that the connection be open for a certain minimum time. The
+recommended value is 300 seconds.
+
+HANGONRETRYDELAY
+ * Type: integer
+ * Default: 10
+
+When attempting to quickly reestablish a connection to a good link, we
+give the net a few seconds to calm down. This time must be long enough
+for the other end to also notice that the connection is broken. The
+recommended value is 10 seconds.
+
+CONNECTTIMEOUT
+ * Type: integer
+ * Default: 90
+
+Number of seconds to wait for a connect(2) call to complete.  NOTE:
+this must be at *LEAST* 10.  When a client connects, it has
+CONNECTTIMEOUT - 10 seconds for its host to respond to an ident lookup
+query and for a DNS lookup to complete. It is recommended that you not
+change this value, but if you do, consider the fact that users whose
+clients do not support NOSPOOF will have to type /QUOTE PING <big
+number> before registration.
+
+MAXIMUM_LINKS
+ * Type: integer
+ * Default: 1
+
+This is the maximum number of links for the built-in client class 0.
+Leave this value at 1.
+
+PINGFREQUENCY
+ * Type: integer
+ * Default: 120
+
+If the daemon doesn't receive anything from any of its links within
+PINGFREQUENCY seconds, then the it will attempt to check for an active
+link with a PING message.  If no reply is received within
+(PINGFREQUENCY * 2) seconds, then the connection will be closed.  This
+value may be overridden by a Class block in "ircd.conf" if the
+connection's Client or Connect block in "ircd.conf" assigns a specific
+class to the connection (recommended).
+
+CONNECTFREQUENCY
+ * Type: integer
+ * Default: 600
+
+This is the default frequency that the server attempts to reconnect
+with its uplink server if it is set to auto connect to it. Note that
+this value is overridden by a Class block in ircd.conf if the Connect
+entries in ircd.conf assign a specific class to the connection.
+
+DEFAULTMAXSENDQLENGTH
+ * Type: integer
+ * Default: 40000
+
+This is the default value of the maximum sendQ length of connection
+classes (see doc/example.conf for details on Class blocks).  You will
+generally override this value in your "ircd.conf" with a Class block.
+
+GLINEMAXUSERCOUNT
+ * Type: integer
+ * Default: 20
+
+G-lines that affect too many users have to be set with a special
+command, to prevent accidental G-lines of large blocks of users.  This
+feature sets that particular threshold.
+
+MPATH
+ * Type: string
+ * Default: "ircd.motd"
+
+MPATH is the filename (relative to DPATH) or the full path of the
+"Message of the Day" file.  The contents of this file will be sent to
+every client that connects to the server, after registration.
+
+RPATH
+ * Type: string
+ * Default: "remote.motd"
+
+RPATH is the filename (relative to DPATH) or the full path of the
+"Remote Message of the Day" file.  The contents of this file will be
+sent to every remote client that issues a /MOTD <your server name>.
+Only the first three lines are sent, so you might want to keep that in
+mind while writing the file.
+
+PPATH
+ * Type: string
+ * Default: "ircd.pid"
+
+PPATH is the filename (relative to DPATH) or the full path of the
+"PID" file.  It is used for storing the server's process ID so that a
+ps(1) isn't necessary.
+
+TOS_SERVER
+ * Type: integer
+ * Default: 0x08
+
+This option is used to specify the type of service that will be
+requested for connections to other servers.  The value may be given as
+a hexadecimal integer.
+
+TOS_CLIENT
+ * Type: integer
+ * Default: 0x08
+
+This option is used to specify the type of service that will be
+requested for connections to users.  The value may be given as a
+hexadecimal integer.
+
+POLLS_PER_LOOP
+ * Type: integer
+ * Default: 200
+
+Some of the engines used by the event interface get a number of events
+from the kernel at once.  Since the number retrieved can impact
+performance, it can be tuned by modifying this value.  The engines
+enforce a lower limit of 20.
+
+CONFIG_OPERCMDS
+ * Type: boolean
+ * Default: FALSE
+
+Since u2.10.11, several new oper-only features have been added that
+involve changes to the server<->server protocol.  This configuration
+option provides a single switch to prevent the use of these features
+until the entire network has been upgraded.  It is not required that
+all servers set this to "TRUE" in order for the features to be used,
+as long as all servers are running u2.10.11 or above.
+
+HIS_MAP
+ * Type: boolean
+ * Default: TRUE
+
+As per UnderNet CFV-165, this removes /MAP from users.
+
+HIS_SNOTICES
+ * Type: boolean
+ * Default: TRUE
+
+As per UnderNet CFV-165, this removes server notices from users.
+
+HIS_SNOTICES_OPER_ONLY
+ * Type: boolean
+ * Default: TRUE
+
+As per UnderNet CFV-165, this removes server notices from users.
+
+HIS_DEBUG_OPER_ONLY
+ * Type: boolean
+ * Default: TRUE
+
+As per UnderNet CFV-165, this removes server wallops from users.
+
+HIS_WALLOPS
+ * Type: boolean
+ * Default: TRUE
+
+As per UnderNet CFV-165, this removes operator wallops from users.
+
+HIS_LINKS
+ * Type: boolean
+ * Default: TRUE
+
+As per UnderNet CFV-165, this removes /LINKS from users.
+
+HIS_TRACE
+ * Type: boolean
+ * Default: TRUE
+
+As per UnderNet CFV-165, this removes /TRACE from users.
+
+HIS_STATS_a
+ * Type: boolean
+ * Default: TRUE
+
+As per UnderNet CFV-165, this removes /STATS a from users.
+
+HIS_STATS_c
+ * Type: boolean
+ * Default: TRUE
+
+As per UnderNet CFV-165, this removes /STATS c from users.
+
+HIS_STATS_d
+ * Type: boolean
+ * Default: TRUE
+
+As per UnderNet CFV-165, this removes /STATS d from users.
+
+HIS_STATS_e
+ * Type: boolean
+ * Default: TRUE
+
+As per UnderNet CFV-165, this removes /STATS e from users.
+
+HIS_STATS_f
+ * Type: boolean
+ * Default: TRUE
+
+As per UnderNet CFV-165, this removes /STATS f from users.
+
+HIS_STATS_g
+ * Type: boolean
+ * Default: TRUE
+
+As per UnderNet CFV-165, this removes /STATS g from users.
+
+HIS_STATS_i
+ * Type: boolean
+ * Default: TRUE
+
+As per UnderNet CFV-165, this removes /STATS i from users.
+
+HIS_STATS_j
+ * Type: boolean
+ * Default: TRUE
+
+As per UnderNet CFV-165, this removes /STATS j from users.
+
+HIS_STATS_J
+ * Type: boolean
+ * Default: TRUE
+
+As per UnderNet CFV-165, this removes /STATS J from users.
+
+HIS_STATS_k
+ * Type: boolean
+ * Default: TRUE
+
+As per UnderNet CFV-165, this removes /STATS k from users.
+
+HIS_STATS_l
+ * Type: boolean
+ * Default: TRUE
+
+As per UnderNet CFV-165, this removes /STATS l from users.
+
+HIS_STATS_L
+ * Type: boolean
+ * Default: TRUE
+
+As per UnderNet CFV-165, this removes /STATS L from users.
+
+HIS_STATS_M
+ * Type: boolean
+ * Default: TRUE
+
+As per UnderNet CFV-165, this removes /STATS M from users.
+
+HIS_STATS_m
+ * Type: boolean
+ * Default: TRUE
+
+As per UnderNet CFV-165, this removes /STATS m from users.
+
+HIS_STATS_o
+ * Type: boolean
+ * Default: TRUE
+
+As per UnderNet CFV-165, this removes /STATS o from users.
+
+HIS_STATS_p
+ * Type: boolean
+ * Default: TRUE
+
+As per UnderNet CFV-165, this removes /STATS p from users.
+
+HIS_STATS_q
+ * Type: boolean
+ * Default: TRUE
+
+As per UnderNet CFV-165, this removes /STATS q from users.
+
+HIS_STATS_r
+ * Type: boolean
+ * Default: TRUE
+
+As per UnderNet CFV-165, this removes /STATS r from users.
+
+HIS_STATS_R
+ * Type: boolean
+ * Default: TRUE
+
+As per UnderNet CFV-165, this removes /STATS R from users.
+
+HIS_STATS_t
+ * Type: boolean
+ * Default: TRUE
+
+As per UnderNet CFV-165, this removes /STATS t from users.
+
+HIS_STATS_T
+ * Type: boolean
+ * Default: TRUE
+
+As per UnderNet CFV-165, this removes /STATS T from users.
+
+HIS_STATS_u
+ * Type: boolean
+ * Default: FALSE
+
+As per UnderNet CFV-165, this allows users to perform /STATS u.
+
+HIS_STATS_U
+ * Type: boolean
+ * Default: TRUE
+
+As per UnderNet CFV-165, this removes /STATS U from users.
+
+HIS_STATS_v
+ * Type: boolean
+ * Default: TRUE
+
+As per UnderNet CFV-165, this removes /STATS v from users.
+
+HIS_STATS_w
+ * Type: boolean
+ * Default: FALSE
+
+As per UnderNet CFV-165, this allows users to perform /STATS w.
+
+HIS_STATS_x
+ * Type: boolean
+ * Default: TRUE
+
+As per UnderNet CFV-165, this removes /STATS x from users.
+
+HIS_STATS_y
+ * Type: boolean
+ * Default: TRUE
+
+As per UnderNet CFV-165, this removes /STATS y from users.
+
+HIS_STATS_z
+ * Type: boolean
+ * Default: TRUE
+
+As per UnderNet CFV-165, this removes /STATS z from users.
+
+HIS_STATS_IAUTH
+ * Type: boolean
+ * Default: TRUE
+
+As per UnderNet CFV-165, this disables /STATS IAUTH and
+/STATS IAUTHCONF from users.
+
+HIS_WHOIS_SERVERNAME
+ * Type: boolean
+ * Default: TRUE
+
+As per UnderNet CFV-165, this removes server names in replies to /WHOIS.
+
+HIS_WHOIS_IDLETIME
+ * Type: boolean
+ * Default: TRUE
+
+As per UnderNet CFV-165, this removes idle time in replies to /WHOIS.
+
+HIS_WHO_SERVERNAME
+ * Type: boolean
+ * Default: TRUE
+
+As per UnderNet CFV-165, this removes server names in replies to /WHO.
+
+HIS_WHO_HOPCOUNT
+ * Type: boolean
+ * Default: TRUE
+
+As per UnderNet CFV-165, this replaces hopcount to a static 3 in
+replies to /WHO.
+
+HIS_MODEWHO
+ * Type: boolean
+ * Default: TRUE
+
+As per UnderNet CFV-165, this doesn't show which server performed a channel
+mode change.
+
+HIS_BANWHO
+ * Type: boolean
+ * Default: TRUE
+
+As per UnderNet CFV-165, this doesn't show which server set a ban.
+
+HIS_KILLWHO
+ * Type: boolean
+ * Default: TRUE
+
+As per UnderNet CFV-165, this doesn't show which server or oper performed a
+kill.
+
+HIS_REWRITE
+ * Type: boolean
+ * Default: TRUE
+
+As per UnderNet CFV-165, this remaps remote numerics to come from the local
+server.
+
+HIS_REMOTE
+ * Type: integer
+ * Default: 1
+
+As per UnderNet CFV-165, this disallows remote queries. (*sob!*)
+
+HIS_NETSPLIT
+ * Type: boolean
+ * Default: TRUE
+
+As per UnderNet CFV-165, this removes server names in net break sign-offs.
+
+HIS_WHOIS_LOCALCHAN
+ * Type: boolean
+ * Default: TRUE
+
+As per UnderNet CFV-165, this removes local channels in replies to /WHOIS.
+
+HIS_SERVERNAME
+ * Type: string
+ * Default: "*.undernet.org"
+
+As per UnderNet CFV-165, this is the "name" of the server shown to users on a
+/WHOIS of another user.
+
+HIS_SERVERINFO
+ * Type: string
+ * Default: "The Undernet Underworld"
+
+As per UnderNet CFV-165, this is the "info" of the server shown to users on a
+/WHOIS of another user.
+
+HIS_URLSERVERS
+ * Type: string
+ * Default: "http://www.undernet.org/servers.php"
+
+As per UnderNet CFV-165, this is the URL shown to users when they do a /MAP or
+/LINKS.
+
+NETWORK
+ * Type: string
+ * Default: "UnderNet"
+
+This defines the network name as reported in the 005 "supported features"
+numeric, and as used by the "Failed to deliver" message.
+
+URL_CLIENTS
+ * Type: string
+ * Default: "ftp://ftp.undernet.org/pub/irc/clients"
+
+This defines a URL that users may visit to find compatible IRC clients.
+
+URLREG
+ * Type: string
+ * Default: "http://cservice.undernet.org/live/"
+
+This defines a URL that is used in server response 477 (ERR_NEEDREGGEDNICK) to
+let users know which website they must visit to obtain a proper account for
+authentication.
+
+NICKLEN
+ * Type: integer
+ * Default: 12
+
+This is the allowed length of the nickname length.  It may not be
+larger than the NICKLEN #define, and should usually be the same
+length.  The real purpose of this feature is to permit easy increases
+in nickname length for a network.
+
+IRCD_RES_RETRIES
+ * Type: integer
+ * Default: 2
+
+This is the number of attempts the irc daemon's resolver will have at
+trying to solicit a response from the DNS server.
+
+IRCD_RES_TIMEOUT
+ * Type: integer
+ * Default: 4
+
+When a DNS query is sent, the irc daemon's resolver will wait this many
+seconds for a reply.  After this timeout has expired, it will retry again,
+for as many retries as IRCD_RES_RETRIES allows.  This can be cut short by
+AUTH_TIMEOUT expiring.
+NOTE: Has no effect when using the adns resolver.
+
+AUTH_TIMEOUT
+ * Type: integer
+ * Default: 9
+
+This is the maximum number of seconds to wait for the ident lookup and
+the DNS query to succeed.  On older (pre 2.10.11.06) servers this was
+hard coded to 60 seconds.
+
+IPCHECK_CLONE_LIMIT
+ * Type: integer
+ * Default: 4
+
+The number of times you are allowed to connect within IPCHECK_CLONE_PERIOD
+seconds before you are considered abusing the server and throttled.
+
+IPCHECK_CLONE_PERIOD
+ * Type: integer
+ * Default: 40
+
+The number of seconds you are allowed to connect IPCHECK_CLONE_LIMIT times
+within before you are considered abusing the server and throttled.
+For instance if you set IPCHECK_CLONE_LIMIT to 1, and IPCHECK_CLONE_PERIOD
+to 10, then a user is only allowed to connect once in 10s, if they connect
+again within 10s, then they are considered to be connecting too fast and
+they are throttled.
+
+IPCHECK_CLONE_DELAY
+ * Type: integer
+ * Default: 600
+
+The number of seconds grace after restarting the server before the throttle
+code kicks in.  Even if a user connects repetitively during this period,
+they will never get throttled.  This is so after a restart users on a
+multiuser box can all connect to a server simultaniously without being
+considered an attack.
+
+SOCKSENDBUF
+ * Type: integer
+ * Default: 61440
+
+The send window size used for connections to other servers.
+
+SOCKRECVBUF
+ * Type: integer
+ * Default: 61440
+
+The receive window size used for connections to other servers.
+
+ANNOUNCE_INVITES
+ * Type: boolean
+ * Default: FALSE
+
+If set, send RPL_ISSUEDINVITE (345) to a channel's operators to
+announce when someone is invited to the channel.
+
+LOCAL_CHANNELS
+ * Type: boolean
+ * Default: TRUE
+
+If set, allow users to create local channels.
+
+TOPIC_BURST
+ * Type: boolean
+ * Default: FALSE
+
+If set, send the current topic value and timestamp for channels during
+burst.  This generally only makes sense for hubs to use, and it causes
+a large increase in net.burst size.
+
+AWAY_BURST
+ * Type: boolean
+ * Default: FALSE
+
+If set, send the current away message of a user during burst. This causes
+a large increase in net.burst size.
+
+CHANNELLEN
+ * Type: integer
+ * Default: 200
+
+This is the allowed length of locally created channels.  It may not be
+larger than the CHANNELLEN #define.  Like the NICKLEN feature, this is
+intended to ease changes in channel name length across a network.
+
+OPLEVELS
+ * Type: boolean
+ * Default: TRUE
+
+This allows local users to set the +A and +U modes (admin and user
+passwords, respectively) on channels where they are marked as channel
+managers.  This feature must be disabled until all servers on the
+network are able to interpret and handle these modes correctly.
+
+ZANNELS
+ * Type: boolean
+ * Default: TRUE
+
+This preserves empty channels with no admin password so that it is
+impractical to become the channel manager by clearing out the channel.
+It must be set to FALSE if there are both 2.10.11.x servers and
+2.10.12.y servers on the network where y < 4.  It should be set to
+TRUE whenever the OPLEVELS features is TRUE.
+
+LOC_ENABLE
+ * Type: boolean
+ * Default: FALSE
+
+Enable Login-On-Connect.
+
+LOC_TARGET
+ * Type: string
+ * Default: NULL
+
+If LOC_ENABLE is on, this is the target nick where to send the requests
+to. If the nick is not online or has not umode +S or is not on a
+services server, the LOC request is discarded.
+
+EXCEPT_ENABLE
+ * Type: boolean
+ * Default: TRUE
+
+If enabled, then channel ops are allowed to set/unset ban exceptions (cmode +e).
+If disabled, then only servers can set this mode.
+
+NOAMSG_TIME
+ * Type: integer
+ * Default: 0
+
+The time span in which the multi target message block may drop messages. 0 will disable the extended multi target message block.
+
+NOAMSG_NUM
+ * Type: integer
+ * Default: 1
+
+The number the same message must occur to be blocked in channels that block multi target messages.
diff --git a/doc/readme.gline b/doc/readme.gline
new file mode 100644 (file)
index 0000000..bbc00b4
--- /dev/null
@@ -0,0 +1,124 @@
+GLINE documentation, last updated on 17 Mar 2007
+
+For an ordinary user, the syntax is:
+
+  GLINE [<mask>]
+
+If <mask> is given, and if a G-line for that server exists, all the
+information about that G-line is displayed.  If <mask> is not given,
+an error is returned.
+
+For an operator, the syntax is:
+
+  GLINE [[!][+|-|>|<]<mask> [<target>] [<expiration> [:<reason>]]]
+
+There are a total of 10 basic forms of the GLINE command.  If no
+arguments are given, all existing G-lines will be listed; if only
+<mask> is given, the behavior is the same as for an ordinary user.
+The remaining forms allow G-lines to be set, manipulated, or possibly
+destroyed.
+
+* Local G-lines.
+
+Opers may set or remove G-lines that only apply to a specific server.
+When the <target> parameter is not given, the specific server will be
+the local server; otherwise, it will be taken to be a remote server,
+and the G-line operations will take place there, if the oper has the
+GLINE privilege.  When <mask> is preceded with the '+' character, the
+G-line will be added, and <expiration> and <reason> are required; when
+<mask> is preceded with the '-' character, the G-line will be removed,
+and <expiration> and <reason> are not required.  The '<' and '>'
+character prefixes are not valid for local G-lines.
+
+* Local modifications to global G-lines.
+
+Opers may locally activate or deactivate global G-lines.  In this
+mode, <mask> is interpreted as referencing an existing G-line, and
+will be preceded by either '<' (to locally deactivate the G-line) or
+'>' (to locally activate the G-line).  This local state overrides the
+global state of the G-line, and persists until there is a global state
+change to the G-line, or until the G-line expires.  The <expiration>
+and <reason> arguments are not required, but <target> may be given if
+the oper desires to make the appropriate change on a remote
+server--note that the oper will need the GLINE privilege for this.
+
+* Global G-lines.
+
+Opers may, if they have the GLINE privilege, set and manipulate global
+G-lines on the network.  To create a new G-line, the oper must prefix
+the <mask> with either '+' (for globally activated G-lines) or '-'
+(for globally deactivated G-lines).  Additionally, <target> must be
+given as "*", and the <expiration> and <reason> parameters are
+required.  If the G-line already exists, it will be modified to match
+the new global status, <expiration>, and <reason>.
+
+When the G-line already exists, an oper may activate or deactivate it
+simply by setting <target> to "*" and prefixing the <mask> with either
+"+" (to activate the G-line) or "-" (to deactivate it).  If it is
+desired to simply modify the expiration time or reason, without
+changing the activation status, specify <mask> without any prefix, set
+<target> to "*", and provide the updated <expire> and optionally an
+updated <reason>.
+
+* Privilege notes.
+
+Note that, for all locally-restricted G-line changes, such as locally
+activating a G-line or creating a local G-line, the oper must have the
+LOCAL_GLINE privilege.  For any other G-line change, including
+locally-restricted changes on remote servers, the server's
+CONFIG_OPERCMDS privilege must be enabled and the oper must have the
+GLINE privilege.  There are also restrictions to prevent an oper from
+setting a G-line that is too wide; in some cases, those restrictions
+may be overridden by prefixing the <mask> parameter with the "!"
+character, IF the operator has the WIDE_GLINE privilege.
+
+For a server, the syntax is:
+
+  <prefix> GL <target> [!][+|-|>|<]<mask> [<expiration>] [<lastmod>]
+       [<lifetime>] [:<reason>]
+
+There are a total of 8 basic forms of the GL command.  The primary
+innovation is the addition of the <lifetime> parameter, which
+specifies a lifetime for the G-line record which may be longer than
+the expiration time.  <lifetime> will be monotonically increasing,
+enabling <expiration> to be modified in any way desirable.
+
+* Local G-lines.
+
+Remote servers, or opers on them, may remotely set local G-lines on
+the local server.  To create a local G-line, <target> will be set to
+the numeric of the local server, and <mask> must be preceded by '+'
+(optionally preceded by '!' if the origin desires to override some
+safety settings).  The <expiration> and <reason> parameters are
+required.  The <lastmod> and <lifetime> parameters will be ignored if
+present, allowing backwards compatibility with ircu2.10.12.10 and
+prior versions.  Removing local G-lines is similar--<mask> must be
+preceded by '-', and all other parameters are ignored to allow
+backwards compatibility.
+
+* Local modifications to global G-lines.
+
+Remote servers, or opers on them, may also locally activate or
+deactivate a global G-line on the local server.  The <target> must be
+set to the numeric of the local server, and <mask> must be preceded by
+either '<' (to locally deactivate the G-line) or '>' (to locally
+activate the G-line).  This local state overrides the global state of
+the G-line, and persists until there is a global state change to the
+G-line, or until the G-line expires.  No other parameters are
+necessary in this mode, and will be ignored if present.
+
+* Global G-lines.
+
+For creation and manipulation of global G-lines, the <target>
+parameter must be set to "*".  If the G-line does not exist, and if
+<expiration> is given, the G-line will be created with the specified
+expiration and <reason> (the latter defaulting to "No reason" if not
+present).  Otherwise, the G-line will be updated according to the
+available parameters.  The rules are similar to those for oper-issued
+global G-lines, with the addition of a <lastmod> parameter, which is a
+monotonically increasing serial number for the G-line, and an optional
+<lifetime> parameter that specifies a monotonically increasing
+lifetime for the G-line record.  Note that, for existing G-lines where
+only state changes (global activation or deactivation) are necessary,
+only <lastmod> is required; <expiration> must be specified for all
+other forms of the GL command.
diff --git a/doc/readme.iauth b/doc/readme.iauth
new file mode 100644 (file)
index 0000000..0d406d9
--- /dev/null
@@ -0,0 +1,456 @@
+OVERVIEW
+========
+
+The iauth protocol used here is based on the one in irc2.11.1, with
+minor changes to support challenge-response protocols and
+login-on-connect.  Reference to that version's iauth-internals.txt and
+source code may be useful.  For clarity, this document uses "server"
+to refer to any IRC server implementing this protocol, "ircu" to refer
+to Undernet ircd, and "ircd" to refer to IRCnet ircd.
+
+Certain messages are relayed to interested operators.  ircu implements
+this by using the 131072 (SNO_AUTH) server notice mask.  ircd
+implements this by using the &AUTH local channel.
+
+STARTING IAUTH
+==============
+
+The path to the iauth program is specified in the server configuration
+file.  The server spawns that program when reading the configuration
+file or when the previous iauth instance terminates.  To protect
+against a series of crashes, the server will refuse to restart an
+iauth instance that it spawned in the last five seconds.  A rehash
+operation will clear this behavior.  The server and iauth instance
+communicate over the iauth instance's stdin and stdout.
+
+Every message from the server to the iauth instance is a single line.
+The line starts with an integer client identifier.  This may be -1 to
+indicate no particular client or a non-negative number to indicate a
+client connected to the server.
+
+When the server starts the iauth instance, it sends a line formatted
+like "-1 M irc.example.org 20000" to indicate its name and an
+exclusive upper bound on valid client identifiers.  In that example,
+possible client identifiers would be from 0 through 19999 inclusive.
+This upper bound is called MAXCONNECTIONS in the server code.
+
+When the iauth instance starts, it sends a V message to indicate its
+version.
+
+The server should provide /stats subcommands that report the iauth
+instance's version, configuration and statistics.
+
+Line formats in both direction are IRC-like in format: space
+characters separate arguments and a colon at the start of an argument
+indicates that the remainder of the line is one argument.  To avoid
+problems, IPv6 address arguments with a leading colon may have to be
+prefixed with a 0 -- for example, ::1 sent as 0::1.
+
+When the iauth instance sends messages that relate to a particular
+client, that client is identified by three parameters from the
+server's Client Introduction message (<id>, <remoteip> and
+<remoteport>).  If any of these disagree with the server's current
+user tables, it is an error.
+
+CLIENT STATES
+=============
+
+Each client is conceptually in one of four states: GONE, REGISTER,
+HURRY or NORMAL.  Each client starts in the GONE state.  Certain
+messages from the server signal a client's transition from one state
+to another, and certain messages from the iauth instance cause a state
+transition.
+
+To be pedantic, the REGISTER state is a collection of sub-states since
+certain commands must occur at most and/or at least one time during
+the REGISTER state.  The distinctions between these sub-states are
+distracting and not important, so they are described as one state and
+the repetition limitations are described for each command.
+
+The rationale for the HURRY state is to give explicit input to the
+iauth instance as to when the server believes it has sent the complete
+set of data for the client.  Rather than defining the complete set of
+information in this protocol document, that is left to the server.
+ircd does not indicate this state.
+
+POLICIES AND USE CASES
+======================
+
+The historical application of iauth has been to block users that
+appear to be drones early, before they have a chance to disrupt the
+network, and without affecting other users on the same host (which
+K-lines do).  This protocol extends that application by adding the n
+server message and by allowing challenge-response exchanges with the
+client.
+
+Eventually it would be nice to move the DNS and ident lookups into
+iauth, and remove that code from the IRC server.  ircd already does
+this; since ircu does not, it adds the u server message.
+
+For trusted proxies, this protocol gives the capability for clients
+connecting through those proxies to be displayed with their actual
+username, IP address and hostname.  The same functions allow other
+clients to use iauth-assigned spoofs, for example to hide the IP
+addresses used by operators.
+
+This protocol allows login-on-connect, for example by clients that
+send their account name and password in PASS, through the R iauth
+message.
+
+This protocol allows iauth to assign a client to a particular class by
+specifying a class name in the D or R iauth message.
+
+SERVER MESSAGES
+===============
+
+X - Example Message Description
+Syntax: <id> X <several> <arguments>
+Example: 5 X arguments vary
+States: REGISTER(1), HURRY, NORMAL
+Next State: -
+Comments: This is an example message description.  Each message is a
+  single character.  The States field indicates which states the
+  message may occur in and any restrictions on how many times the
+  message may be sent during those states (restrictions only make
+  sense when Next State is -).  The Next State field indicates which
+  new state is implied by the message; a hyphen indicates no state
+  change is implied.  The X (Example) message is not a real message
+  type.
+Compatibility: If we believe ircu behavior is different than ircd's,
+  this describes ircd's behavior or expectations.
+
+C - Client Introduction
+Syntax: <id> C <remoteip> <remoteport> <localip> <localport>
+Example: 5 C 192.168.1.10 23367 192.168.0.1 6667
+States: GONE
+Next State: REGISTER
+Comments: Indicates that <localport> on <localip> accepted a client
+  connection from <remoteport> on <remoteip>.
+
+D - Client Disconnect
+Syntax: <id> D
+Example: 5 D
+States: REGISTER, HURRY, NORMAL
+Next State: GONE
+Comments: Indicates that a client is disconnecting from the server.
+
+N - Hostname Received
+Syntax: <id> N <hostname>
+Example: 5 N host-1-10.example.org
+States: REGISTER(1)
+Next State: -
+Comments: Indicates that the server received hostname information for
+  a client.  Only one of 'N' and 'd' is sent.
+
+d - Hostname Timeout
+Syntax: <id> d
+Example: 5 d
+States: REGISTER(1)
+Next State: -
+Comments: Indicates that the server did not receive hostname
+  information for a client in a timely fashion.  Only one of 'N' and
+  'd' is sent.
+
+P - Client Password
+Syntax: <id> P :<password ...>
+Example: 5 P :buddha n1rvan4
+States: REGISTER
+Next State: -
+Comments: Indicates the client's password information.  This may be a
+  traditional client password, an account and pass phrase pair, or the
+  response to a challenge (see the iauth C message).  This message is
+  enabled by requesting the A policy.
+
+U - Client Username
+Syntax: <id> U <username> <hostname> <servername> :<userinfo ...>
+Example: 5 U buddha bodhisattva.example.com irc.undernet.org :Gautama Siddhartha
+States: REGISTER(1+)
+Next State: -
+Comments: Indicates the client's claimed username and "GECOS"
+  information, along with client hostname and server name.  This
+  information is not reliable.  This message is enabled by requesting
+  the A policy.
+Compatibility: ircd only sends the <username> parameter.
+
+u - Client Username
+Syntax: <id> u <username>
+Example: 5 u notbuddha
+States: REGISTER(1)
+Next State: -
+Comments: Indicates a more reliable username for the client.
+Compatibility: This is an Undernet extension and ircd does not send
+  it.  It is enabled by the iauth instance requesting the U policy.
+
+n - Client Nickname
+Syntax: <id> n <nickname>
+Example: 5 n Buddha
+States: REGISTER(1+), HURRY
+Next State: -
+Comments: Indicates the client's requested nickname.
+Compatibility: This is an Undernet extension and ircd does not send
+  it.  It is enabled by the iauth instance requesting the U policy.
+
+L - Login On Connect
+Syntax: <id> L <account>[:<accountstamp>][ <fakehost>]
+Example: 5 L Buddha Buddha.TestNet.com
+States: REGISTER(1)
+Next State: -
+Comments: Indicates a successfull LOC query. If the LOC query failed,
+  no message is sent but the iauthd must assume that the query failed
+  or was not done when it goes into the HURRY state.
+  The user gets automatically set "+xr <account>". If <fakehost> is
+  set, it also gets "+f <fakehost>". The iauthd cannot overwrite
+  these settings. If the iauthd believes them to be wrong, it must
+  reject the client.
+Compatibility: This is an extension of the IRCu-Patchset.
+
+H - Hurry Up
+Syntax: <id> H <class>
+Example: 5 H Others
+States: REGISTER
+Next State: HURRY
+Comments: Indicates that the server is ready to register the client
+  except for needing a response from the iauth server.  <class> is
+  a tentative connection class for the user, which will be used unless
+  iauth overrides it in a D or R message.
+Compatibility: This is an Undernet extension and ircd does not send
+  it.  It is enabled by the iauth instance requesting the U policy.
+
+T - Client Registered
+Syntax: <id> T
+Example: 5 T
+States: HURRY
+Next State: NORMAL
+Comments: Indicates the server got tired of waiting for iauth to
+  finish and the client is being accepted.  This message should
+  never be sent when the R policy is in effect.
+Compatibility: ircd allows this message for clients in the REGISTER
+  state.
+
+E - Error
+Syntax: <id> E <type> :<additional text>
+Example: 5 E Gone
+States: N/A
+Next State: -
+Comments: Indicates that a message received from the iauth instance
+  could not be rationally interpreted.  This may be because the client
+  could not be found, the client was in an inappropriate state for the
+  message, or for other reasons.  The <type> argument specifies the
+  general type of error and <additional text> provides details.  <id>
+  may be -1.
+
+M - Server Name and Capacity
+Syntax: <id> M <servername> <capacity>
+Example: -1 M irc.example.org 20000
+States: GONE(1)
+Next State: -
+Comments: Indicates the server's name and upper bound on client
+  identifiers.
+Compatibility: ircd does not include the <capacity> information.
+  The <id> should be ignored: ircd sends 0 and ircu sends -1.
+
+IAUTH MESSAGES
+==============
+
+X - Example Message Description
+Syntax: X <arguments>
+Example: X something
+Notify: yes
+States: N/A
+Next State: N/A
+Comments: This is an example message description.  Each message is a
+  single character.  If the Notify field is present and says yes,
+  interested operators (with SNO_AUTH set) should be notified of the
+  message.  The States field, where present, indicate which states
+  accept this message.  Clients in other states should ignore the
+  message or treat it as an error.  The Next State field, where
+  present, indicates what the next state should be for the client.
+Compatibility: If we believe ircu behavior is different than ircd's,
+  this describes ircd's behavior or expectations.
+
+> - Operator Notification
+Syntax: > :<message text>
+Example: > :Hello Operators!
+Notify: yes
+Comments: Contains a message that the iauth instance wants to send to
+  interested operators.
+
+G - Set Debug Level
+Syntax: G <level>
+Example: G 1
+Notify: yes
+Comments: Sets a debug level for the server's end of the iauth
+  conversation.  When enabled, debug messages should be sent to the
+  same channel (group, mask, etc) as other iauth notifications.
+  Debug level 0 suppresses iauth-related debug output, and positive
+  integers enable iauth debugging messages.
+
+O - Set Policy Options
+Syntax: O <options>
+Example: O RTAWU
+Notify: yes
+Comments: Sets policy options for the iauth conversation.  Old policy
+  options should be forgotten.  Valid policy options are:
+   A - Send username and password information.
+       This causes the server to send the U and P messages.
+   R - Require clients to be approved before registering them.
+       When this policy is in effect, it affects the behavior
+       of a registration timeout; for details, see the documentation
+       for the T server message.
+   T - When the R policy is in effect and the iauth service does not
+       respond for a client, this causes the server to count the number
+       of clients refused, to send a warning message to interested
+       operators periodically, and to send the count of rejected users
+       to interested operators when the iauth instance responds again.
+   U - Send nickname, confirmed username and hurry information.
+       This causes the server to send the n, u and H messages.
+   W - Allow extra time for iauth to respond based on hostname.
+       When this policy is in effect and a DNS message (N or d) is
+       sent for a client, that client's registration timeout is
+       extended or reset.
+Compatibility: The U policy is an Undernet extension and is not
+  recognized by ircd.
+
+V - iauth Program Version
+Syntax: V :<version string>
+Example: V :Undernet-iauthu v1.0
+Notify: yes
+Comments: Indicates the iauth program version.  This should only be
+  used in diagnostic messages, and must not change protocol behavior.
+
+a - Start of new configuration
+Syntax: a
+Example: a
+Notify: yes
+Comments: Indicates that a new configuration is being loaded by the
+  iauth instance.  Any cached configuration records should be cleared.
+
+A - Configuration Information
+Syntax: A <hosts?> <module> :<options>
+Example: A * rfc931
+Notify: yes
+Comments: Indicates new configuration information.
+
+s - Start of new statistics
+Syntax: s
+Example: s
+Notify: yes
+Comments: Indicates a new set of statistics will be sent.  Any cached
+  statistics records should be cleared.
+
+S - Statistics Information
+Syntax: S <module> :<module information>
+Example: S rfc931 connected 0 unix 0 other 0 bad 0 out of 0
+Notify: yes
+Comments: Indicates new or additional statistics information.
+
+o - Forced Username
+Syntax: o <id> <remoteip> <remoteport> <username>
+Example: o 5 192.168.1.10 23367 bubba
+States: REGISTER, HURRY
+Next State: -
+Comments: Indicates that the username should be used for the specified
+  client even if the normal sanity-checking would prohibit the
+  username.
+
+U - Trusted Username
+Syntax: U <id> <remoteip> <remoteport> <username>
+Example: U 5 192.168.1.10 23367 buddha
+States: REGISTER, HURRY
+Next State: -
+Comments: Indicates that the iauth instance believes <username> is
+  accurate for the specified client.
+
+u - Untrusted Username
+Syntax: u <id> <remoteip> <remoteport> <username>
+Example: u 5 192.168.1.10 23367 enlightened_one
+States: REGISTER, HURRY
+Next State: -
+Comments: Indicates that the iauth instance does not strongly trust
+  <username> to be accurate, but has no more trusted username.
+
+N - Client Hostname
+Syntax: N <id> <remoteip> <remoteport> <hostname>
+Example: N 5 192.168.1.10 23367 buddha.example.org
+States: REGISTER, HURRY
+Next State: -
+Comments: Indicates that the iauth instance believes the specified
+  client should use the hostname given.
+Compatibility: This is an Undernet extension and ircd does not support
+  this message.
+
+I - Client IP Address
+Syntax: I <id> <currentip> <remoteport> <newip>
+Example: I 5 192.168.1.10 23367 127.128.129.130
+States: REGISTER, HURRY
+Next State: -
+Comments: Indicates that the iauth instance wants the server to
+  present and treat the client as using <newip>.  This means that
+  future iauth messages relating to the client must use <newip>
+  as the <remoteip> parameter.
+Compatibility: This is an Undernet extension and ircd does not support
+  this message.
+
+M - Adjust User Mode
+Syntax: M <id> <remoteip> <remoteport> +<mode changes>
+Example: M 5 192.168.1.10 23367 +iwg
+States: REGISTER, HURRY
+Next State: -
+Comments: Indicates a set of user mode changes to be applied to the
+  client.
+Compatibility: This is an Undernet extension and ircd does not support
+  this message.
+
+C - Challenge User
+Syntax: C <id> <remoteip> <remoteport> :<challenge string>
+Example: C 5 192.168.1.10 23367 :In which year did Columbus sail the ocean blue?
+States: REGISTER, HURRY
+Next State: -
+Comments: Indicates that the challenge string should be sent to the
+  specified user, for example via NOTICE AUTH :*** <challenge string>.
+  The client responds by sending PASS :<response>, which should be
+  relayed via the P server message.  This requires that the A policy
+  be in effect.
+Compatibility: This is an Undernet extension and ircd does not support
+  this message.
+
+k - Quietly Kill Client
+Syntax: k <id> <remoteip> <remoteport> :<reason>
+Example: k 5 192.168.1.10 23367 :Open proxy found.
+States: REGISTER, HURRY, NORMAL
+Next State: GONE
+Comments: Indicates that the specified client should be disconnected
+  for the reason given without notifying operators.
+Compatibility: ircu does not use the same notification mechanism as
+  ircd, so operators are notified using SNO_CONNEXIT anyway.
+
+K - Kill Client
+Syntax: K <id> <remoteip> <remoteport> :<reason>
+Example: K 5 192.168.1.10 23367 :We don't like you.
+States: REGISTER, HURRY, NORMAL
+Next State: GONE
+Comments: Indicates that the specified client should be disconnected
+  for the reason given.  Operators should be notified.
+
+D - Done Checking
+Syntax: D <id> <remoteip> <remoteport> [class]
+Example: D 5 192.168.1.10 23367
+States: REGISTER, HURRY
+Next State: NORMAL
+Comments: Indicates that the iauth instance believes the specified
+  client should be allowed onto the network.  If a class parameter is
+  given, the client should be assigned to that class.
+Compatibility: Specifying the class is an Undernet extension and ircd
+  does not support that parameter.
+
+R - Registered User
+Syntax: R <id> <remoteip> <remoteport> <account> [class]
+Example: R 5 192.168.1.10 23367 Buddha
+States: REGISTER, HURRY
+Next State: NORMAL
+Comments: Indicates that the iauth instance believes the specified
+  client should be allowed onto the network, pre-authenticated to
+  the account listed.  If a class parameter is given, the client
+  should be assigned to that class.
+Compatibility: This is an Undernet extension and ircd does not support
+  this message.
diff --git a/doc/readme.indent b/doc/readme.indent
new file mode 100644 (file)
index 0000000..6e02bc0
--- /dev/null
@@ -0,0 +1,9 @@
+If you want to indent this source file, in order to convert
+the source tree to the used programming style, you should use
+`make indent' in the base directory.
+
+For this to work you need to have `indent' version 2.1.0 or higher
+in your PATH.  GNU indent 2.1.0 is available from all GNU sites,
+its main ftp site is ftp://ftp.gnu.org/indent/.  Or you can download
+it directly from the webpage of its maintainer at
+http://www.xs4all.nl/~carlo17/indent/
diff --git a/doc/readme.jupe b/doc/readme.jupe
new file mode 100644 (file)
index 0000000..e34dfe7
--- /dev/null
@@ -0,0 +1,57 @@
+JUPE documentation, last updated on 18 Mar 2000
+
+For an ordinary user, the syntax is:
+
+  JUPE [<server>]
+
+If <server> is given, and if a jupe for that server exists, all the
+information about that jupe is displayed.  If <server> is not given,
+all un-expired jupes are displayed.
+
+For an operator, the syntax is:
+
+  JUPE [[+|-]<server> [[<target>] <expiration> :<reason>]]
+
+If <server> is not given, or if it is not prefixed by "+" or "-", the
+operation is exactly the same as if it were issued by an ordinary
+user.  If the "+" or "-" prefixes are used, the arguments <target>,
+<expiration>, and <reason> must be given, even if the jupe already
+exists.  If <target> is "*" and the currently existing jupe is a local
+jupe, the local jupe will be erased and recreated with the parameters
+given, as described below.  Otherwise, if the jupe currently exists, a
+prefix of "+" will cause an inactive jupe to be activated, whereas a
+prefix of "-" will cause an active jupe to be deactivated.
+
+If the jupe does not already exist, it is created. The <target>
+parameter is used to select whether the jupe is only to apply to a
+single server (which need not be the local server) or to the whole
+network; if <target> is not given, it is assumed to be the local
+server.  This could be useful if a single particular link is having
+problems, for instance.  The <expiration> parameter is a number of
+seconds, not to exceed 7 days, for the jupe to exist.  The <reason>
+argument is mandatory and should describe why this particular jupe was
+placed.
+
+For a server, the syntax is:
+
+  <prefix> JU <target> (+|-)<server> <expiration> <lastmod> :<reason>
+
+The <target> may be a server numeric or the character "*", for a
+globally scoped jupe.  The <server> argument is a server name, and
+must be prefixed by one of "+" (to indicate an active jupe) or "-" (to
+indicate an inactive jupe).  The parameter <expiration> is a total
+number of seconds the jupe is to live for, and <lastmod> is used for
+versioning.  Since JUPEs are propagated during netbursts, there must
+be some way of resolving conflicting states, which is the reason for
+this argument, and is also the reason jupes cannot be deleted, only
+deactivated.  The <reason> parameter indicates the reason the jupe was
+placed.
+
+If a JUPE is received with a <target> of "*", any jupes with local
+scope are deleted, in preference for the globally scoped version.  If
+the jupe already exists, the values of <lastmod> are compared; if the
+received <lastmod> is less than the stored <lastmod>, the existing
+jupe is resent to the server from which the JUPE message was received;
+otherwise, the jupe is activated or deactivated, depending on the
+<server> prefix.  If the jupe does not currently exist, it is created
+with the parameters given.
diff --git a/doc/readme.log b/doc/readme.log
new file mode 100644 (file)
index 0000000..1e635ca
--- /dev/null
@@ -0,0 +1,194 @@
+Older versions of ircd had no consistent way of logging various
+actions.  Some things, such as G-lines, were written out to log files
+with names compiled into the server.  Others could only be logged
+through syslog.  Some required that their log files exist beforehand.
+Starting with u2.10.11, this situation has changed dramatically.
+
+All logging in the server is now unified through a single logging
+subsystem.  Unfortunately, the server still does not generate all the
+logs that it could, and some more tuning is in store for the next
+major release of ircd.  Nevertheless, the logs that are generated are
+far more consistent, and those log messages may be sent to a given
+file, to syslog, or even to online operators--or any combination of
+these three methods.  This file is intended to describe configuration
+of the logging subsystem.
+
+All logs are classified by a "subsystem" and a "level."  The subsystem
+is a major classification; each subsystem may be configured
+individually.  The level classification is used to indicate how
+important the message is; subsystems may be configured to omit log
+messages with less than a certain importance--not unlike syslog.
+
+Levels
+
+Levels are used to classify the importance of various log messages.
+The most important level is the "CRIT" level; the least important is
+the "DEBUG" level.  Each of the levels is also mapped to a
+corresponding syslog level, and some may even force generation of
+certain types of server notices.  Each importance level is described
+below.
+
+ * CRIT - Used for very critical notifications, such as server
+   termination.  This is mapped to the corresponding "CRIT" syslog
+   priority.  This will also generate server notices to the "OLDSNO"
+   server notice mask.
+
+ * ERROR - Used to report important error conditions.  This is mapped
+   to the corresponding "ERR" syslog priority.
+
+ * WARNING - Used to warn about certain conditions.  This is mapped to
+   the corresponding "WARNING" syslog priority.
+
+ * NOTICE - Used for reporting important information.  This is mapped
+   to the corresponding "NOTICE" syslog priority.
+
+ * TRACE - Used to tracing operation of the server.  This is mapped to
+   the corresponding "INFO" syslog priority.
+
+ * INFO - Used for reporting unimportant but potentially useful
+   information.  This is mapped to the corresponding "INFO" syslog
+   priority.
+
+ * DEBUG - Used for reporting debugging information.  This is mapped
+   to the corresponding "DEBUG" syslog priority.  This will also
+   generate server notices to the "DEBUG" server notice mask.
+
+Subsystems
+
+All of the subsystems are described below, along with their default
+logging configuration.  There are no default log files to log to, and
+the default logging level is INFO (unless the server is compiled with
+debugging enabled)--this means that only notices of importance INFO or
+higher will be logged.
+
+ * SYSTEM - Used to report information that affects the server as a
+   whole.  By default, log messages to this subsystem go nowhere.
+
+ * CONFIG - Used to report information concerning the configuration
+   file.  By default, log messages to this subsystem go to the default
+   syslog facility, which defaults to "USER," and to the "OLDSNO"
+   server notice mask.
+
+ * OPERMODE - Used to report usage of /OPMODE and /CLEARMODE.  By
+   default, log messages to this subsystem go to the "HACK4" server
+   notice mask.
+
+ * GLINE - Used to report usage of /GLINE, particularly BADCHANs.  By
+   default, log messages to this subsystem go to the "GLINE" server
+   notice mask.
+
+ * JUPE - Used to report usage of /JUPE.  By default, log messages to
+   this subsystem go to the "NETWORK" server notice mask.
+
+ * WHO - Used to report usage of the extended features of /WHO
+   (/WHOX).  By default, log messages to this subsystem go nowhere.
+
+ * NETWORK - Used to report net junctions and net breaks.  By default,
+   log messages to this subsystem go to the "NETWORK" server notice
+   mask.
+
+ * OPERKILL - Used to report usage of /KILL by IRC operators.  By
+   default, log messages to this subsystem go nowhere.
+
+ * SERVKILL - Used to report usage of /KILL by other servers.  By
+   default, log messages to this subsystem go nowhere.
+
+ * USER - Used to report user sign-ons and sign-offs.  By default, log
+   messages to this subsystem go nowhere.
+
+ * OPER - Used to report usage of /OPER, either successfully or
+   unsuccessfully.  By default, log messages to this subsystem go to
+   the "OLDREALOP" server notice mask.
+
+ * RESOLVER - Used to report error messages or other conditions from
+   the resolver and authentication system.  By default, log messages
+   to this subsystem go nowhere.
+
+ * SOCKET - Used to report problems with sockets.  By default, log
+   messages to this subsystem go nowhere.
+
+ * IAUTH - Used to report connects, disconnects and errors for the
+   IAuth authorization mechanism.  By default, log messages to this
+   subsystem go to the "NETWORK" server notice mask.
+
+ * DEBUG - Used only when debugging is enabled.  All log messages to
+   this subsystem go either to the console or to the debug log file
+   compiled into the server, as well as to the "DEBUG" server notice
+   mask.  This is the only subsystem with a default log file.
+
+Configuration
+
+The true power of the logging subsystem comes from its extremely
+flexible configuration.  The default server facility can be
+configured, as can the facility for each individual subsystem
+described above.  Moreover, administrators can configure the server to
+log to specific files, send selected log messages to operators
+subscribed to any server notice mask, and even change the default log
+level for each subsystem.
+
+The logging subsystem has a set of tables mapping names to the
+numerical values used internally.  Subsystems, levels, syslog
+facilities, and server notice masks are all configured using strings.
+These tables even include special strings, such as "DEFAULT" and
+"NONE."  Each possible configuration piece is described below.
+
+Default Syslog Facility
+
+The IRC server has a default facility that it uses when sending log
+messages to syslog.  The default facility may be overridden for each
+individual subsystem, but the default itself can be changed with an
+appropriate Feature entry in the configuration file.  The facility
+normally defaults to "USER," but may be configured to be any of AUTH,
+CRON, DAEMON, LOCAL0, LOCAL1, LOCAL2, LOCAL3, LOCAL4, LOCAL5, LOCAL6,
+LOCAL7, LPR, MAIL, NEWS, USER, or UUCP.  Some systems also have the
+AUTHPRIV facility.  To configure this default, add a Feature line to
+the configuration file that looks like "LOG" = "<facility>";
+<facility> should be replaced with the string for the desired default
+syslog facility.
+
+Log Files
+
+Each subsystem may be configured to send its log messages to any
+single log file with a Feature entry like "LOG" = "<subsys>" "FILE"
+"<file>"; <subsys> should be replaced with one of the subsystem names
+described above, and <file> should be a file name for the log file.
+The file name may be relative to the server's data directory
+("DPATH"), or it may be an absolute path name.  Note that if you're
+using chroot, these absolute path names will be relative to the
+server's root directory.
+
+Logging to Syslog
+
+By default, except for the CONFIG subsystem, no logs are sent to
+syslog.  This can be overridden using an Feature entry like "LOG" =
+"<subsys>" "FACILITY" "<facility>"; <subsys>, as above, should be
+replaced with one of the subsystem names described above, and
+<facility> must be one of the facility strings mentioned under
+"Default Syslog Facility."  The facility string may also be "NONE," to
+turn off syslog for that subsystem, and "DEFAULT," to use the server's
+default facility.  Please don't confuse a DEFAULT facility with the
+default for a particular subsystem; only the CONFIG subsystem defaults
+to DEFAULT, whereas all the rest default to NONE.
+
+Logging via Server Notices
+
+Log messages can be sent to online IRC operators.  Many subsystems
+actually default to this behavior, in fact.  For security, log
+messages containing IP addresses or other extremely sensitive data
+will never be sent via server notices, but all others can be sent to a
+specific server notice mask.  (For more information about server
+notice masks, please see doc/snomask.html.)  The available mask names
+are OLDSNO, SERVKILL, OPERKILL, HACK2, HACK3, UNAUTH, TCPCOMMON,
+TOOMANY, HACK4, GLINE, NETWORK, IPMISMATCH, THROTTLE, OLDREALOP,
+CONNEXIT, and DEBUG.  The special mask name "NONE" inhibits sending of
+server notices for a particular subsystem.  The Feature entry for this
+configuration looks like "LOG" = "<subsys>" "SNOMASK" "<mask>"; again,
+<subsys> is one of the subsystems described above, and <mask> is one
+of the mask names.
+
+Setting Minimum Logging Level
+
+The minimum log level for a particular subsystem may be set with an
+Feature entry like "LOG" = "<subsys>" "LEVEL" "<level>"; here,
+<subsys> is yet again one of the subsystems described above, and
+<level> is one of the level names, also described above.
diff --git a/doc/readme.who b/doc/readme.who
new file mode 100644 (file)
index 0000000..4a1649e
--- /dev/null
@@ -0,0 +1,288 @@
+WHO documentation, updated on 02 Jan 1999.
+
+Since ircu2.10.02 the WHO command had been changed from what described in
+RFC1459, while still keeping backward compatibility, actually it has been
+changed again in u2.10.05 so that since this release the format of the who
+query is now:
+
+[:source] WHO <mask1> [<options> [<mask2>]]
+
+<mask2> is optional, if mask2 is present it's used for matching and mask1 is
+ignored, otherwise mask1 is used for matching, since mask2 is the last
+parameter it *can* contain a space and this can help when trying to match a
+"realname".
+
+When matching IP numbers the <mask> can be in 3 forms:
+
+- The old and well known IRC masks using * and ? as wanted
+- The IPmask form a.b.c.d/e.f.g.h as used in most firewalls and
+  system configurations, where what is before the / are the bits we expect
+  in the IP number and what is after the / is the "filter mask" telling wich
+  bits whould be considered and wich should be ignored.
+- The IPmask form a.b.c.d/bitcount where bitcount is an integer between 0
+  and 31 (inclusive), the matching will be for the IPs whose first
+  "bitcount" bits are equal to those in a.b.c.d
+
+Note that:
+. The bitcount must be between 0 and 31, 32 is NOT good (and
+  makes no sense to use it... just match against the static IP a.b.c.d)
+. The missing pieces of both the bitmask and the ipnumber in the forms
+  ipnumber/bitmask and ipnumber/bitcount default to zero from right to left,
+  this is NOT what inet_aton and most tools do but makes more sense here
+  IMO, in example /who 194.243/16 is taken as /who 194.243.0.0/255.255.0.0
+  (inet_aton whould take 194.243 as 194.0.0.243).
+. For the above reason and specified validity limits 1.2.3.4/31 becomes
+  1.2.3.4/255.255.255.254 while 1.2.3.4/32 becomes 1.2.3.4/32.0.0.0 :)
+
+For all the other fields th match happens as has always been, i.e. it's only
+considered the IRC mask with * and ? (that is: don't expect to catch an user
+with "realname" = "1.2.3.4" when doing "/who 1.2/16 h" :)
+
+For both the masks and the options (and thus for all flags) case is NOT
+significative (so "/who <any> o" is exactly the same as "/who <ANY> O".
+
+The "options" part can be as follows:
+
+ [<flags>][%[<fields>[,<querytype>]]]
+
+in which:
+
+ <flags>: can be a sequence of field matching flags, use mode matching flags
+          and special purpose flags
+
+   Field matching flags, when one of these is specified the field in
+   question is matched against the mask, otherwise it's not matched.
+
+   n   Nick (in nick!user@host)
+   u   Username (in nick!user@host)
+   h   Hostname (in nick!user@host)
+   i   Numeric IP (the unresolved host)
+   s   Servername (the canonic name of the server the guy is on)
+   r   Info text (formerly "Realname")
+   a   Account name
+
+   If no field-matching flags are specified they default to what old servers
+   used to do: nuhsr (= everything except the numeric IP)
+
+   User mode matching flags (specifying one of these means that only clients
+   with that umode are considered, what is not specified is always matched):
+
+   d   Join-delayed channel members
+   o   Irc operator
+       [In the future more flags will be supported, basically all
+        usermodes plus the +/- specificators to revert the filtering]
+
+   Special purpose flags:
+
+   x   If this is specified the extended visibility of information for opers
+       is applied, what this means depends on the fact that you are local or
+       global operator and on how the admin configured the server (global
+       and eventually local irc opers might be allowed with this flag to see
+       +i local users, to see all +i users, to see users into +p and/or +s
+       channels, and so on). Using the 'x' flag while not being an irc
+       operator is meaningless (it will be ignored), using it while oper'd
+       means that the query is almost certainly logged and the admin might
+       (rightfully) ask you an explanation on why you did.
+
+   The rest, what follows the %, that is [%[fields[,<querytype>]]], is as it
+   has always been since the first who.patch, the <fields> part specifies
+   wich fields to include in the output as:
+
+   c : Include (first) channel name
+   d : Include "distance" in hops (hopcount)
+   f : Include flags (all of them)
+   h : Include hostname
+   i : Include IP
+   l : Include idle time (0 for remote users) [2.10.11+]
+   n : Include nick
+   r : Include real name
+   s : Include server name
+   t : Include the querytype in the reply
+   u : Include userID with eventual ~
+   a : Include account name
+   o : Include oplevel (shows 999 to users without ops in the channel)
+
+And the ,<querytype> final option can be used to specify what you want the
+server to say in the querytype field of the output, useful to filter the
+output in scripts that do a kind of "on 354 ..."
+
+If no %fields are specified the reply is _exactly_ the same as has always
+been, numeric 352, same fields, same order.
+
+If one or more %fields are specified the reply uses a new numeric, since an
+out-of-standard 352 crashes EPIC and confuses several other clients. I used
+354.
+
+:"source" 354 "target" ["querytype"] ["channel"] ["user"] 
+                       ["IP"] ["host"] ["server"] ["nick"] 
+                       ["flags"] ["hops"] ["idle"] ["account"]
+                       [:"realname"]
+
+Where only the fields specified in the %fields options are present.
+
+"querytype" is the same value passed in the /who command, it is provided to
+simplify scripting, in example one could pass a certain value in the query
+and have that value "signal" back what is to be done with those replies.
+
+The number of lines in the reply is still limited to avoid self-flooding and
+sooner or later another limitation will be added: you will be forced to do
+no more than one /who query every 'n' seconds where 'n' depends on the
+number of fields you actually match (the field-match flags specified before
+% in the option, defaulting to 6 if you don't specify an option at all),
+infact matching against many fields as the default query does severely
+affects the CPU usage of the server and is *much* better to specify with the
+field-matching flags what you are looking for, in example when you are
+looking for all french users a "/who *.fr h" is A LOT better than just "/who
+*.fr" (and actually you want users that have the
+_hostname_ matching *.fr, you wouldn't want to match a japanese user
+that has the realname "ku fung-kay aj.fr" in example...)
+
+Note that:
+
+- An user doing a "/who whatever" or a "/who whatever o"
+  will not see any change (except for the anti-flood limit and sooner or
+  later the CPU usage limit)
+
+- An user doing a "/who #wasteland %n" will get just a list of nicks (lame,
+  very lame way of doing it :-)
+
+- An user doing a "/who 0 o%nuhs" will get a list of the opers with Nick,
+  userID, server and hostname like:
+  
+:Amst* 354 Nemesi #wasteland nbakker pc73.a.sn.no Oslo*.org Niels
+
+- An user doing a "/who 0 o%tnuhs,166" will get a list of the opers
+  with Nick, userID, server and hostname like the above but with a
+  request type field of 166 like:
+
+  :Amst* 354 Nemesi 166 #wasteland nbakker pc73.a.sn.no 
+         Oslo-R.NO.EU.Undernet.org Niels
+  
+  So that he can have in example a script that does 
+  on ^354 "% 166" display "There is an oper ..."
+
+- The client will have to sort/format the fields by itself,
+  the _order_ in which flags are passed is not significant, the fields in the
+  reply will always have the same order.
+
+- The maximum number of _lines_ reported as reply for a query
+  is 2048/(n+4) where 'n' is the number of flags "enabled" that is the
+  number of fields included in each reply.
+
+  Actually:   1 field  returned = maximum 409 replies
+              2 fields returned = maximum 341 replies
+              3 fields returned = maximum 292 replies
+              4 fields returned = maximum 256 replies
+              5 fields returned = maximum 227 replies
+              6 fields returned = maximum 204 replies
+              7 fields returned = maximum 186 replies (default query)
+              8 fields returned = maximum 170 replies
+              9 fields returned = maximum 157 replies
+             10 fields returned = maximum 146 replies
+
+  If the limit is reached before completing the query the reply is truncated
+  and a new numeric error is issued after the "End of WHO", anyway the "end
+  of" numeric is _always_ sent (otherwise some scripts and clients go
+  crazy).
+
+The actual "mask" to match can have one of the two following forms:
+
+- A comma-separated list of elements: in this case each element
+  is treated as a flat channel or nick name and is not matched to the other
+  elements. Nicks do count in the limit of output lines (they should not be
+  that many anyway), channels count if who asks the query is not on the
+  channel. (That is: a /who #channel gives unlimited output if you are in
+  there).
+
+- A _single_ mask: in this case (no commas, only one element) the mask is
+  first checked to be a full channel or nickname, then it is matched against
+  all relevant fiels as already known.  These happens in different steps
+  with replicates-removal so that if one has (?) something like "#wasteland"
+  as "real name" or is on a channel named "#***MyChan***" it all works
+  nicely.
+
+Miscellaneous bug fixes / "undocumented feature" changes:
+
+- /who NickName did not show the user with nick = NickName  when it was
+  invisible, even if the nick was given completely (without wildchars) now
+  it does, since one could always see him as /whois NickName.  It does not
+  report him twice if he also has in example the userID == NickName and is
+  -i.
+
+- ":source WHO :The Black Hacker" did not report an user having "The Black
+  Hacker" as real name, now it does. Since this can only be done without the
+  flags/format specificator because that would become the "last parameter"
+  an escape has been provided: if you pass to m_who _3_ parameters the first
+  one will be ignored and the last one used for matching, like in example
+  ":source WHO foo %nuh :*Black Hacker*" where "foo" will not be used and
+  the match will happen on "*Black Hacker*".  (It was passed through
+  clean_channelname() that prevented the mask from containing spaces and
+  such...)
+
+- When one user was umode -i he was shown or not depending on the 
+  fact he was on a +p or +s channel... since we are doing a lookup on the
+  _user_ this makes no sense to me, example: 
+  Neme1 : umode -i, on no channels, was SEEN with a /who 0
+  Neme2 : umode -i, on channel #p with chmode +p, was NOT SEEN by /who 0
+  Neme3 : umode -i, on channel #s with chmode +s, was NOT SEEN by /who 0
+
+  Now all users "-i" are matched with a "/who mask", the +i users instead
+  must be on a _common_ channel to be seen.
+
+  Basically being on "one" +s|p channel "forced" a +i status while one might
+  want to be on #secret (mode +s) and have nobody know that he is in there
+  but on the other side stay -i so others can find him.  Of course a +s|p
+  channel is never shown in the reply unless who asks the query is in there,
+  if no "visible" channels are available for a -i user he is shown on
+  "channel *".
+
+- When one user is +i is shown _only_ if there is a common channel,
+  the first common channel found is shown in the reply.
+
+- As requested by many persons an escape has been provided for opers,
+  when #defined SHOW_ALL_CHANNELS opers can /who #channel from outside
+  and see users in there even if the channel is +s|+p
+  Each admin decides locally if this feature is enabled to his opers.
+
+- As requested by many admins an escape from the query-size limit
+  has been provided for opers, by #defining UNLIMIT_OPER_QUERY opers
+  can do unlimited sized /who-s (until they get disconnected by max
+  SendQ exceeded ;)
+  Again admins will decide if enable or not this feature.
+
+- A /who a,c,b,d,e,f used to return as many ** END OF WHO as there 
+  were elements in the list, since now the command is supposed to be
+  _efficient_ for /who nick1,nick2,nick3 .. I return a _single_ end
+  of query message.
+
+- /who did not work for a channel named in example #**StarWars**  
+  now it does handle it properly (the mask was passed through
+  collapse() and then.. did not find that channel, fixed).
+
+- "/who #John" did not report an user having '#John' as "Real name",
+  now it does (and does NOT report him twice if he is ALSO on a
+  channel named #John, strange but true: this can happen).
+
+- "/who a,b,c,d" where a b c and d are channelnames/nicks now uses an hash
+  lookup and therefore is extremely efficient, if _only_ one field is
+  specified it is looked in all the fields; who really wants _only_ users on
+  a specific channel or a single nick (without looking for a match in the
+  other fields) can force the server to consider the parameter as a list
+  adding a comma somewhere, like:
+
+  "/who #Italia," or "/who ,Nemesi"
+
+  Or even better to avoid misbehaviour with other servers:
+  "/who #Italia %... #Italia,"   or "/who Nemesi %... Nemesi,"
+
+  This will make old servers act properly and new ones and should be the
+  recomended way for GUI based clients to get a channel's userlist and all
+  the infos they want about users on the channel.
+
+- If you use the new numeric, flags will contain all the information about
+  a user on a channel.  @ for op'd, + for voiced, and ! for zombie. eg:
+  Isomer #coder-com H@+, where the old behavor of just displaying one of
+  them has been preserved for the old numeric.  [2.10.11+]
+
+Regards, Andrea aka Nemesi
+
diff --git a/doc/readme.www b/doc/readme.www
new file mode 100644 (file)
index 0000000..3991536
--- /dev/null
@@ -0,0 +1,23 @@
+More, and up to date, information can be retrieved from the following
+world wide web pages:
+
+* Undernet Documents Project:
+               http://www.user-com.undernet.org/documents/
+
+* Release Notes & Patch Repository:
+               http://coder-com.undernet.org/
+
+* ircII scripts to support the undernet extentions:
+               http://coder-com.undernet.org/ircii/
+
+* Undernet Use Policy:
+               http://www.user-com.undernet.org/documents/aup.html
+
+* Operator Etiquette:
+               http://www.user-com.undernet.org/documents/operman.html
+
+* New server links & Routing info:
+               http://routing-com.undernet.org/
+
+* Information about large number of file descriptors per process:
+  linux:       http://www.linux.org.za/oskar/patches/kernel/filehandle/
diff --git a/doc/rfc1413.txt b/doc/rfc1413.txt
new file mode 100644 (file)
index 0000000..0522c7b
--- /dev/null
@@ -0,0 +1,451 @@
+
+
+
+
+
+
+Network Working Group                                       M. St. Johns
+Request for Comments: 1413                      US Department of Defense
+Obsoletes: 931                                             February 1993
+
+
+                        Identification Protocol
+
+Status of this Memo
+
+   This RFC specifies an IAB standards track protocol for the Internet
+   community, and requests discussion and suggestions for improvements.
+   Please refer to the current edition of the "IAB Official Protocol
+   Standards" for the standardization state and status of this protocol.
+   Distribution of this memo is unlimited.
+
+1.  INTRODUCTION
+
+   The Identification Protocol (a.k.a., "ident", a.k.a., "the Ident
+   Protocol") provides a means to determine the identity of a user of a
+   particular TCP connection.  Given a TCP port number pair, it returns
+   a character string which identifies the owner of that connection on
+   the server's system.
+
+   The Identification Protocol was formerly called the Authentication
+   Server Protocol.  It has been renamed to better reflect its function.
+   This document is a product of the TCP Client Identity Protocol
+   Working Group of the Internet Engineering Task Force (IETF).
+
+2.  OVERVIEW
+
+   This is a connection based application on TCP.  A server listens for
+   TCP connections on TCP port 113 (decimal).  Once a connection is
+   established, the server reads a line of data which specifies the
+   connection of interest.  If it exists, the system dependent user
+   identifier of the connection of interest is sent as the reply.  The
+   server may then either shut the connection down or it may continue to
+   read/respond to multiple queries.
+
+   The server should close the connection down after a configurable
+   amount of time with no queries - a 60-180 second idle timeout is
+   recommended.  The client may close the connection down at any time;
+   however to allow for network delays the client should wait at least
+   30 seconds (or longer) after a query before abandoning the query and
+   closing the connection.
+
+
+
+
+
+
+
+St. Johns                                                       [Page 1]
+\f
+RFC 1413                Identification Protocol            February 1993
+
+
+3.  RESTRICTIONS
+
+   Queries are permitted only for fully specified connections.  The
+   query contains the local/foreign port pair -- the local/foreign
+   address pair used to fully specify the connection is taken from the
+   local and foreign address of query connection.  This means a user on
+   address A may only query the server on address B about connections
+   between A and B.
+
+4.  QUERY/RESPONSE FORMAT
+
+   The server accepts simple text query requests of the form:
+
+            <port-on-server> , <port-on-client>
+
+   where <port-on-server> is the TCP port (decimal) on the target (where
+   the "ident" server is running) system, and <port-on-client> is the
+   TCP port (decimal) on the source (client) system.
+
+   N.B - If a client on host A wants to ask a server on host B about a
+   connection specified locally (on the client's machine) as 23, 6191
+   (an inbound TELNET connection), the client must actually ask about
+   6191, 23 - which is how the connection would be specified on host B.
+
+      For example:
+
+                 6191, 23
+
+   The response is of the form
+
+   <port-on-server> , <port-on-client> : <resp-type> : <add-info>
+
+   where <port-on-server>,<port-on-client> are the same pair as the
+   query, <resp-type> is a keyword identifying the type of response, and
+   <add-info> is context dependent.
+
+   The information returned is that associated with the fully specified
+   TCP connection identified by <server-address>, <client-address>,
+   <port-on-server>, <port-on-client>, where <server-address> and
+   <client-address> are the local and foreign IP addresses of the
+   querying connection -- i.e., the TCP connection to the Identification
+   Protocol Server.  (<port-on-server> and <port-on-client> are taken
+   from the query.)
+
+      For example:
+
+         6193, 23 : USERID : UNIX : stjohns
+         6195, 23 : ERROR : NO-USER
+
+
+
+St. Johns                                                       [Page 2]
+\f
+RFC 1413                Identification Protocol            February 1993
+
+
+5.  RESPONSE TYPES
+
+A response can be one of two types:
+
+USERID
+
+     In this case, <add-info> is a string consisting of an
+     operating system name (with an optional character set
+     identifier), followed by ":", followed by an
+     identification string.
+
+     The character set (if present) is separated from the
+     operating system name by ",".  The character set
+     identifier is used to indicate the character set of the
+     identification string.  The character set identifier,
+     if omitted, defaults to "US-ASCII" (see below).
+
+     Permitted operating system names and character set
+     names are specified in RFC 1340, "Assigned Numbers" or
+     its successors.
+
+     In addition to those operating system and character set
+     names specified in "Assigned Numbers" there is one
+     special case operating system identifier - "OTHER".
+
+     Unless "OTHER" is specified as the operating system
+     type, the server is expected to return the "normal"
+     user identification of the owner of this connection.
+     "Normal" in this context may be taken to mean a string
+     of characters which uniquely identifies the connection
+     owner such as a user identifier assigned by the system
+     administrator and used by such user as a mail
+     identifier, or as the "user" part of a user/password
+     pair used to gain access to system resources.  When an
+     operating system is specified (e.g., anything but
+     "OTHER"), the user identifier is expected to be in a
+     more or less immediately useful form - e.g., something
+     that could be used as an argument to "finger" or as a
+     mail address.
+
+     "OTHER" indicates the identifier is an unformatted
+     character string consisting of printable characters in
+     the specified character set.  "OTHER" should be
+     specified if the user identifier does not meet the
+     constraints of the previous paragraph.  Sending an
+     encrypted audit token, or returning other non-userid
+     information about a user (such as the real name and
+     phone number of a user from a UNIX passwd file) are
+
+
+
+St. Johns                                                       [Page 3]
+\f
+RFC 1413                Identification Protocol            February 1993
+
+
+     both examples of when "OTHER" should be used.
+
+     Returned user identifiers are expected to be printable
+     in the character set indicated.
+
+     The identifier is an unformatted octet string - - all
+     octets are permissible EXCEPT octal 000 (NUL), 012 (LF)
+     and 015 (CR).  N.B. - space characters (040) following the
+     colon separator ARE part of the identifier string and
+     may not be ignored. A response string is still
+     terminated normally by a CR/LF.  N.B. A string may be
+     printable, but is not *necessarily* printable.
+
+ERROR
+
+   For some reason the port owner could not be determined, <add-info>
+   tells why.  The following are the permitted values of <add-info> and
+   their meanings:
+
+          INVALID-PORT
+
+          Either the local or foreign port was improperly
+          specified.  This should be returned if either or
+          both of the port ids were out of range (TCP port
+          numbers are from 1-65535), negative integers, reals or
+          in any fashion not recognized as a non-negative
+          integer.
+
+          NO-USER
+
+          The connection specified by the port pair is not
+          currently in use or currently not owned by an
+          identifiable entity.
+
+          HIDDEN-USER
+
+          The server was able to identify the user of this
+          port, but the information was not returned at the
+          request of the user.
+
+          UNKNOWN-ERROR
+
+          Can't determine connection owner; reason unknown.
+          Any error not covered above should return this
+          error code value.  Optionally, this code MAY be
+          returned in lieu of any other specific error code
+          if, for example, the server desires to hide
+          information implied by the return of that error
+
+
+
+St. Johns                                                       [Page 4]
+\f
+RFC 1413                Identification Protocol            February 1993
+
+
+          code, or for any other reason.  If a server
+          implements such a feature, it MUST be configurable
+          and it MUST default to returning the proper error
+          message.
+
+   Other values may eventually be specified and defined in future
+   revisions to this document.  If an implementer has a need to specify
+   a non-standard error code, that code must begin with "X".
+
+   In addition, the server is allowed to drop the query connection
+   without responding.  Any premature close (i.e., one where the client
+   does not receive the EOL, whether graceful or an abort should be
+   considered to have the same meaning as "ERROR : UNKNOWN-ERROR".
+
+FORMAL SYNTAX
+
+   <request> ::= <port-pair> <EOL>
+
+   <port-pair> ::= <integer> "," <integer>
+
+   <reply> ::= <reply-text> <EOL>
+
+   <EOL> ::= "015 012"  ; CR-LF End of Line Indicator
+
+   <reply-text> ::= <error-reply> | <ident-reply>
+
+   <error-reply> ::= <port-pair> ":" "ERROR" ":" <error-type>
+
+   <ident-reply> ::= <port-pair> ":" "USERID" ":" <opsys-field>
+                     ":" <user-id>
+
+   <error-type> ::= "INVALID-PORT" | "NO-USER" | "UNKNOWN-ERROR"
+                    | "HIDDEN-USER" |  <error-token>
+
+   <opsys-field> ::= <opsys> [ "," <charset>]
+
+   <opsys> ::= "OTHER" | "UNIX" | <token> ...etc.
+               ;  (See "Assigned Numbers")
+
+   <charset> ::= "US-ASCII" | ...etc.
+                 ;  (See "Assigned Numbers")
+
+   <user-id> ::= <octet-string>
+
+   <token> ::= 1*64<token-characters> ; 1-64 characters
+
+   <error-token> ::= "X"1*63<token-characters>
+                     ; 2-64 chars beginning w/X
+
+
+
+St. Johns                                                       [Page 5]
+\f
+RFC 1413                Identification Protocol            February 1993
+
+
+   <integer> ::= 1*5<digit> ; 1-5 digits.
+
+   <digit> ::= "0" | "1" ... "8" | "9" ; 0-9
+
+   <token-characters> ::=
+                  <Any of these ASCII characters: a-z, A-Z,
+                   - (dash), .!@#$%^&*()_=+.,<>/?"'~`{}[]; >
+                               ; upper and lowercase a-z plus
+                               ; printables minus the colon ":"
+                               ; character.
+
+   <octet-string> ::= 1*512<octet-characters>
+
+   <octet-characters> ::=
+                  <any octet from  00 to 377 (octal) except for
+                   ASCII NUL (000), CR (015) and LF (012)>
+
+Notes on Syntax:
+
+   1)   To promote interoperability among variant
+        implementations, with respect to white space the above
+        syntax is understood to embody the "be conservative in
+        what you send and be liberal in what you accept"
+        philosophy.  Clients and servers should not generate
+        unnecessary white space (space and tab characters) but
+        should accept white space anywhere except within a
+        token.  In parsing responses, white space may occur
+        anywhere, except within a token.  Specifically, any
+        amount of white space is permitted at the beginning or
+        end of a line both for queries and responses.  This
+        does not apply for responses that contain a user ID
+        because everything after the colon after the operating
+        system type until the terminating CR/LF is taken as
+        part of the user ID.  The terminating CR/LF is NOT
+        considered part of the user ID.
+
+   2)   The above notwithstanding, servers should restrict the
+        amount of inter-token white space they send to the
+        smallest amount reasonable or useful.  Clients should
+        feel free to abort a connection if they receive 1000
+        characters without receiving an <EOL>.
+
+   3)   The 512 character limit on user IDs and the 64
+        character limit on tokens should be understood to mean
+        as follows: a) No new token (i.e., OPSYS or ERROR-TYPE)
+        token will be defined that has a length greater than 64
+        and b) a server SHOULD NOT send more than 512 octets of
+        user ID and a client MUST accept at least 512 octets of
+
+
+
+St. Johns                                                       [Page 6]
+\f
+RFC 1413                Identification Protocol            February 1993
+
+
+        user ID.  Because of this limitation, a server MUST
+        return the most significant portion of the user ID in
+        the first 512 octets.
+
+   4)   The character sets and character set identifiers should
+        map directly to those defined in or referenced by RFC 1340,
+        "Assigned Numbers" or its successors.  Character set
+        identifiers only apply to the user identification field
+        - all other fields will be defined in and must be sent
+        as US-ASCII.
+
+   5)   Although <user-id> is defined as an <octet-string>
+        above, it must follow the format and character set
+        constraints implied by the <opsys-field>; see the
+        discussion above.
+
+   6)   The character set provides context for the client to
+        print or store the returned user identification string.
+        If the client does not recognize or implement the
+        returned character set, it should handle the returned
+        identification string as OCTET, but should in addition
+        store or report the character set.  An OCTET string
+        should be printed, stored or handled in hex notation
+        (0-9a-f) in addition to any other representation the
+        client implements - this provides a standard
+        representation among differing implementations.
+
+6.  Security Considerations
+
+   The information returned by this protocol is at most as trustworthy
+   as the host providing it OR the organization operating the host.  For
+   example, a PC in an open lab has few if any controls on it to prevent
+   a user from having this protocol return any identifier the user
+   wants.  Likewise, if the host has been compromised the information
+   returned may be completely erroneous and misleading.
+
+   The Identification Protocol is not intended as an authorization or
+   access control protocol.  At best, it provides some additional
+   auditing information with respect to TCP connections.  At worst, it
+   can provide misleading, incorrect, or maliciously incorrect
+   information.
+
+   The use of the information returned by this protocol for other than
+   auditing is strongly discouraged.  Specifically, using Identification
+   Protocol information to make access control decisions - either as the
+   primary method (i.e., no other checks) or as an adjunct to other
+   methods may result in a weakening of normal host security.
+
+
+
+
+St. Johns                                                       [Page 7]
+\f
+RFC 1413                Identification Protocol            February 1993
+
+
+   An Identification server may reveal information about users,
+   entities, objects or processes which might normally be considered
+   private.  An Identification server provides service which is a rough
+   analog of the CallerID services provided by some phone companies and
+   many of the same privacy considerations and arguments that apply to
+   the CallerID service apply to Identification.  If you wouldn't run a
+   "finger" server due to privacy considerations you may not want to run
+   this protocol.
+
+7.  ACKNOWLEDGEMENTS
+
+   Acknowledgement is given to Dan Bernstein who is primarily
+   responsible for renewing interest in this protocol and for pointing
+   out some annoying errors in RFC 931.
+
+References
+
+   [1] St. Johns, M., "Authentication Server", RFC 931, TPSC, January
+       1985.
+
+   [2] Reynolds, J., and J. Postel, "Assigned Numbers", STD 2, RFC 1340,
+       USC/Information Sciences Institute, July 1992.
+
+Author's Address
+
+       Michael C. St. Johns
+       DARPA/CSTO
+       3701 N. Fairfax Dr
+       Arlington, VA 22203
+
+       Phone: (703) 696-2271
+       EMail: stjohns@DARPA.MIL
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+St. Johns                                                       [Page 8]
+\f
diff --git a/doc/rfc1459.unet b/doc/rfc1459.unet
new file mode 100644 (file)
index 0000000..6a3f36b
--- /dev/null
@@ -0,0 +1,3657 @@
+Network Working Group                                      J. Oikarinen
+Request for Comments: 1459                                      D. Reed
+                                                               May 1993
+
+
+                      Internet Relay Chat Protocol
+
+Undernet Specific Annotations and Changes
+   This document exists here in order to attempt to describe the existing
+   protocol that is currently in use on the Undernet IRC Network. Since
+   the original standard was released, many networks have made
+   significant changes and enhancements to the protocol described in the
+   original version of this document. This version of the standard should
+   be updated by the current maintainers of the Undernet server software
+   distribution as changes are made that affect the protocol. Please be
+   aware that some sections may be out of date.
+
+Status of This Memo
+
+   This memo defines an Experimental Protocol for the Internet
+   community.  Discussion and suggestions for improvement are requested.
+   Please refer to the current edition of the "IAB Official Protocol
+   Standards" for the standardization state and status of this protocol.
+   Distribution of this memo is unlimited.
+
+Abstract
+
+   The IRC protocol was developed over the last 4 years since it was
+   first implemented as a means for users on a BBS to chat amongst
+   themselves.  Now it supports a world-wide network of servers and
+   clients, and is stringing to cope with growth. Over the past 2 years,
+   the average number of users connected to the main IRC network has
+   grown by a factor of 10.
+
+   The IRC protocol is a text-based protocol, with the simplest client
+   being any socket program capable of connecting to the server.
+
+Table of Contents
+
+   1.  INTRODUCTION ...............................................    4
+      1.1  Servers ................................................    4
+      1.2  Clients ................................................    5
+         1.2.1 Operators ..........................................    5
+      1.3 Channels ................................................    5
+      1.3.1  Channel Operators ....................................    6
+   2. THE IRC SPECIFICATION .......................................    7
+      2.1 Overview ................................................    7
+      2.2 Character codes .........................................    7
+      2.3 Messages ................................................    7
+         2.3.1  Message format in 'pseudo' BNF ....................    8
+      2.4 Numeric replies .........................................   10
+   3. IRC Concepts ................................................   10
+      3.1 One-to-one communication ................................   10
+      3.2 One-to-many .............................................   11
+         3.2.1 To a list ..........................................   11
+         3.2.2 To a group (channel) ...............................   11
+         3.2.3 To a host/server mask ..............................   12
+      3.3 One to all ..............................................   12
+
+
+
+Oikarinen & Reed                                                [Page 1]
+\f
+RFC 1459              Internet Relay Chat Protocol              May 1993
+
+
+         3.3.1 Client to Client ...................................   12
+         3.3.2 Clients to Server ..................................   12
+         3.3.3 Server to Server ...................................   12
+   4. MESSAGE DETAILS .............................................   13
+      4.1 Connection Registration .................................   13
+         4.1.1 Password message ...................................   14
+         4.1.2 Nickname message ...................................   14
+         4.1.3 User message .......................................   15
+         4.1.4 Server message .....................................   16
+         4.1.5 Operator message ...................................   17
+         4.1.6 Quit message .......................................   17
+         4.1.7 Server Quit message ................................   18
+      4.2 Channel operations ......................................   19
+         4.2.1 Join message .......................................   19
+         4.2.2 Part message .......................................   20
+         4.2.3 Mode message .......................................   21
+            4.2.3.1 Channel modes .................................   21
+            4.2.3.2 User modes ....................................   22
+         4.2.4 Topic message ......................................   23
+         4.2.5 Names message ......................................   24
+         4.2.6 List message .......................................   24
+         4.2.7 Invite message .....................................   25
+         4.2.8 Kick message .......................................   25
+      4.3 Server queries and commands .............................   26
+         4.3.1 Version message ....................................   26
+         4.3.2 Stats message ......................................   27
+         4.3.3 Links message ......................................   28
+         4.3.4 Time message .......................................   29
+         4.3.5 Connect message ....................................   29
+         4.3.6 Trace message ......................................   30
+         4.3.7 Admin message ......................................   31
+         4.3.8 Info message .......................................   31
+      4.4 Sending messages ........................................   32
+         4.4.1 Private messages ...................................   32
+         4.4.2 Notice messages ....................................   33
+      4.5 User-based queries ......................................   33
+         4.5.1 Who query ..........................................   33
+         4.5.2 Whois query ........................................   34
+         4.5.3 Whowas message .....................................   35
+      4.6 Miscellaneous messages ..................................   35
+         4.6.1 Kill message .......................................   36
+         4.6.2 Ping message .......................................   37
+         4.6.3 Pong message .......................................   37
+         4.6.4 Error message ......................................   38
+   5. OPTIONAL MESSAGES ...........................................   38
+      5.1 Away message ............................................   38
+      5.2 Rehash command ..........................................   39
+      5.3 Restart command .........................................   39
+
+
+
+Oikarinen & Reed                                                [Page 2]
+\f
+RFC 1459              Internet Relay Chat Protocol              May 1993
+
+
+      5.4 Summon message ..........................................   40
+      5.5 Users message ...........................................   40
+      5.6 Operwall command ........................................   41
+      5.7 Userhost message ........................................   42
+      5.8 Ison message ............................................   42
+   6. REPLIES .....................................................   43
+      6.1 Error Replies ...........................................   43
+      6.2 Command responses .......................................   48
+      6.3 Reserved numerics .......................................   56
+   7. Client and server authentication ............................   56
+   8. Current Implementations Details .............................   56
+      8.1 Network protocol: TCP ...................................   57
+         8.1.1 Support of Unix sockets ............................   57
+      8.2 Command Parsing .........................................   57
+      8.3 Message delivery ........................................   57
+      8.4 Connection 'Liveness' ...................................   58
+      8.5 Establishing a server-client connection .................   58
+      8.6 Establishing a server-server connection .................   58
+         8.6.1 State information exchange when connecting .........   59
+      8.7 Terminating server-client connections ...................   59
+      8.8 Terminating server-server connections ...................   59
+      8.9 Tracking nickname changes ...............................   60
+      8.10 Flood control of clients ...............................   60
+      8.11 Non-blocking lookups ...................................   61
+         8.11.1 Hostname (DNS) lookups ............................   61
+         8.11.2 Username (Ident) lookups ..........................   61
+      8.12 Configuration file .....................................   61
+         8.12.1 Allowing clients to connect .......................   62
+         8.12.2 Operators .........................................   62
+         8.12.3 Allowing servers to connect .......................   62
+         8.12.4 Administrivia .....................................   63
+      8.13 Channel membership .....................................   63
+   9. Current problems ............................................   63
+      9.1 Scalability .............................................   63
+      9.2 Labels ..................................................   63
+         9.2.1 Nicknames ..........................................   63
+         9.2.2 Channels ...........................................   64
+         9.2.3 Servers ............................................   64
+      9.3 Algorithms ..............................................   64
+   10. Support and availability ...................................   64
+   11. Security Considerations ....................................   65
+   12. Authors' Addresses .........................................   65
+
+
+
+
+
+
+
+
+
+Oikarinen & Reed                                                [Page 3]
+\f
+RFC 1459              Internet Relay Chat Protocol              May 1993
+
+
+1.  INTRODUCTION
+
+   The IRC (Internet Relay Chat) protocol has been designed over a
+   number of years for use with text based conferencing.  This document
+   describes the current IRC protocol.
+
+   The IRC protocol has been developed on systems using the TCP/IP
+   network protocol, although there is no requirement that this remain
+   the only sphere in which it operates.
+
+   IRC itself is a teleconferencing system, which (through the use of
+   the client-server model) is well-suited to running on many machines
+   in a distributed fashion.  A typical setup involves a single process
+   (the server) forming a central point for clients (or other servers)
+   to connect to, performing the required message delivery/multiplexing
+   and other functions.
+
+1.1 Servers
+
+   The server forms the backbone of IRC, providing a point to which
+   clients may connect to to talk to each other, and a point for other
+   servers to connect to, forming an IRC network.  The only network
+   configuration allowed for IRC servers is that of a spanning tree [see
+   Fig. 1] where each server acts as a central node for the rest of the
+   net it sees.
+
+
+                           [ Server 15 ]  [ Server 13 ] [ Server 14]
+                                 /                \         /
+                                /                  \       /
+        [ Server 11 ] ------ [ Server 1 ]       [ Server 12]
+                              /        \          /
+                             /          \        /
+                  [ Server 2 ]          [ Server 3 ]
+                    /       \                      \
+                   /         \                      \
+           [ Server 4 ]    [ Server 5 ]         [ Server 6 ]
+            /    |    \                           /
+           /     |     \                         /
+          /      |      \____                   /
+         /       |           \                 /
+ [ Server 7 ] [ Server 8 ] [ Server 9 ]   [ Server 10 ]
+
+                                  :
+                               [ etc. ]
+                                  :
+
+                 [ Fig. 1. Format of IRC server network ]
+
+
+
+Oikarinen & Reed                                                [Page 4]
+\f
+RFC 1459              Internet Relay Chat Protocol              May 1993
+
+
+1.2 Clients
+
+   A client is anything connecting to a server that is not another
+   server.  Each client is distinguished from other clients by a unique
+   nickname having a maximum length of nine (9) characters.  See the
+   protocol grammar rules for what may and may not be used in a
+   nickname.  In addition to the nickname, all servers must have the
+   following information about all clients: the real name of the host
+   that the client is running on, the username of the client on that
+   host, and the server to which the client is connected.
+
+1.2.1 Operators
+
+   To allow a reasonable amount of order to be kept within the IRC
+   network, a special class of clients (operators) is allowed to perform
+   general maintenance functions on the network.  Although the powers
+   granted to an operator can be considered as 'dangerous', they are
+   nonetheless required.  Operators should be able to perform basic
+   network tasks such as disconnecting and reconnecting servers as
+   needed to prevent long-term use of bad network routing.  In
+   recognition of this need, the protocol discussed herein provides for
+   operators only to be able to perform such functions.  See sections
+   4.1.7 (SQUIT) and 4.3.5 (CONNECT).
+
+   A more controversial power of operators is the ability  to  remove  a
+   user  from  the connected network by 'force', i.e. operators are able
+   to close the connection between any client and server.   The
+   justification for  this  is delicate since its abuse is both
+   destructive and annoying.  For further details on this type of
+   action, see section 4.6.1 (KILL).
+
+1.3 Channels
+
+   A channel is a named group of one or more clients which will all
+   receive messages addressed to that channel.  The channel is created
+   implicitly when the first client joins it, and the channel ceases to
+   exist when the last client leaves it.  While channel exists, any
+   client can reference the channel using the name of the channel.
+
+   Channels names are strings (beginning with a '&' or '#' character) of
+   length up to 200 characters.  Apart from the the requirement that the
+   first character being either '&' or '#'; the only restriction on a
+   channel name is that it may not contain any spaces (' '), a control G
+   (^G or ASCII 7), or a comma (',' which is used as a list item
+   separator by the protocol).
+
+   There are two types of channels allowed by this protocol.  One is a
+   distributed channel which is known to all the servers that are
+
+
+
+Oikarinen & Reed                                                [Page 5]
+\f
+RFC 1459              Internet Relay Chat Protocol              May 1993
+
+
+   connected to the network. These channels are marked by the first
+   character being a only clients on the server where it exists may join
+   it.  These are distinguished by a leading '&' character.  On top of
+   these two types, there are the various channel modes available to
+   alter the characteristics of individual channels.  See section 4.2.3
+   (MODE command) for more details on this.
+
+   To create a new channel or become part of an existing channel, a user
+   is required to JOIN the channel.  If the channel doesn't exist prior
+   to joining, the channel is created and the creating user becomes a
+   channel operator.  If the channel already exists, whether or not your
+   request to JOIN that channel is honoured depends on the current modes
+   of the channel. For example, if the channel is invite-only, (+i),
+   then you may only join if invited.  As part of the protocol, a user
+   may be a part of several channels at once, but a limit of ten (10)
+   channels is recommended as being ample for both experienced and
+   novice users.  See section 8.13 for more information on this.
+
+   If the IRC network becomes disjoint because of a split between two
+   servers, the channel on each side is only composed of those clients
+   which are connected to servers on the respective sides of the split,
+   possibly ceasing to exist on one side of the split.  When the split
+   is healed, the connecting servers announce to each other who they
+   think is in each channel and the mode of that channel.  If the
+   channel exists on both sides, the JOINs and MODEs are interpreted in
+   an inclusive manner so that both sides of the new connection will
+   agree about which clients are in the channel and what modes the
+   channel has.
+
+1.3.1 Channel Operators
+
+   The channel operator (also referred to as a "chop" or "chanop") on a
+   given channel is considered to 'own' that channel.  In recognition of
+   this status, channel operators are endowed with certain powers which
+   enable them to keep control and some sort of sanity in their channel.
+   As an owner of a channel, a channel operator is not required to have
+   reasons for their actions, although if their actions are generally
+   antisocial or otherwise abusive, it might be reasonable to ask an IRC
+   operator to intervene, or for the usersjust leave and go elsewhere
+   and form their own channel.
+
+   The commands which may only be used by channel operators are:
+
+        KICK    - Eject a client from the channel
+        MODE    - Change the channel's mode
+        INVITE  - Invite a client to an invite-only channel (mode +i)
+        TOPIC   - Change the channel topic in a mode +t channel
+
+
+
+
+Oikarinen & Reed                                                [Page 6]
+\f
+RFC 1459              Internet Relay Chat Protocol              May 1993
+
+
+   A channel operator is identified by the '@' symbol next to their
+   nickname whenever it is associated with a channel (ie replies to the
+   NAMES, WHO and WHOIS commands).
+
+2. The IRC Specification
+
+2.1 Overview
+
+   The protocol as described herein is for use both with server to
+   server and client to server connections.  There are, however, more
+   restrictions on client connections (which are considered to be
+   untrustworthy) than on server connections.
+
+2.2 Character codes
+
+   No specific character set is specified. The protocol is based on a a
+   set of codes which are composed of eight (8) bits, making up an
+   octet.  Each message may be composed of any number of these octets;
+   however, some octet values are used for control codes which act as
+   message delimiters.
+
+   Regardless of being an 8-bit protocol, the delimiters and keywords
+   are such that protocol is mostly usable from USASCII terminal and a
+   telnet connection.
+
+   Because of IRC's scandanavian origin, the characters {}| are
+   considered to be the lower case equivalents of the characters []\,
+   respectively. This is a critical issue when determining the
+   equivalence of two nicknames.
+
+2.3 Messages
+
+   Servers and clients send eachother messages which may or may not
+   generate a reply.  If the message contains a valid command, as
+   described in later sections, the client should expect a reply as
+   specified but it is not advised to wait forever for the reply; client
+   to server and server to server communication is essentially
+   asynchronous in nature.
+
+   Each IRC message may consist of up to three main parts: the prefix
+   (optional), the command, and the command parameters (of which there
+   may be up to 15).  The prefix, command, and all parameters are
+   separated by one (or more) ASCII space character(s) (0x20).
+
+   The presence of a prefix is indicated with a single leading ASCII
+   colon character (':', 0x3b), which must be the first character of the
+   message itself.  There must be no gap (whitespace) between the colon
+   and the prefix.  The prefix is used by servers to indicate the true
+
+
+
+Oikarinen & Reed                                                [Page 7]
+\f
+RFC 1459              Internet Relay Chat Protocol              May 1993
+
+
+   origin of the message.  If the prefix is missing from the message, it
+   is assumed to have originated from the connection from which it was
+   received.  Clients should not use prefix when sending a message from
+   themselves; if they use a prefix, the only valid prefix is the
+   registered nickname associated with the client.  If the source
+   identified by the prefix cannot be found from the server's internal
+   database, or if the source is registered from a different link than
+   from which the message arrived, the server must ignore the message
+   silently.
+
+   The command must either be a valid IRC command or a three (3) digit
+   number represented in ASCII text.
+
+   IRC messages are always lines of characters terminated with a CR-LF
+   (Carriage Return - Line Feed) pair, and these messages shall not
+   exceed 512 characters in length, counting all characters including
+   the trailing CR-LF. Thus, there are 510 characters maximum allowed
+   for the command and its parameters.  There is no provision for
+   continuation message lines.  See section 7 for more details about
+   current implementations.
+
+2.3.1 Message format in 'pseudo' BNF
+
+   The protocol messages must be extracted from the contiguous stream of
+   octets.  The current solution is to designate two characters, CR and
+   LF, as message separators.   Empty  messages  are  silently  ignored,
+   which permits  use  of  the  sequence  CR-LF  between  messages
+   without extra problems.
+
+   The extracted message is parsed into the components <prefix>,
+   <command> and list of parameters matched either by <middle> or
+   <trailing> components.
+
+   The BNF representation for this is:
+
+
+<server_message> ::= <numeric> <command> <params> <crlf>
+<message>  ::= [':' <prefix> <SPACE> ] <command> <params> <crlf>
+<prefix>   ::= <servername> | <nick> [ '!' <user> ] [ '@' <host> ]
+<command>  ::= <letter> { <letter> } | <number> <number> <number>
+<SPACE>    ::= ' ' { ' ' }
+<params>   ::= <SPACE> [ ':' <trailing> | <middle> <params> ]
+<numeric>  ::= <numeric> { <letter> | <number> | '[' | ']' }
+
+<middle>   ::= <Any *non-empty* sequence of octets not including SPACE
+               or NUL or CR or LF, the first of which may not be ':'>
+<trailing> ::= <Any, possibly *empty*, sequence of octets not including
+                 NUL or CR or LF>
+
+<crlf>     ::= CR LF
+
+
+
+Oikarinen & Reed                                                [Page 8]
+\f
+RFC 1459              Internet Relay Chat Protocol              May 1993
+
+
+NOTES:
+
+  1)    <SPACE> is consists only of SPACE character(s) (0x20).
+        Specially notice that TABULATION, and all other control
+        characters are considered NON-WHITE-SPACE.
+
+  2)    After extracting the parameter list, all parameters are equal,
+        whether matched by <middle> or <trailing>. <Trailing> is just
+        a syntactic trick to allow SPACE within parameter.
+
+  3)    The fact that CR and LF cannot appear in parameter strings is
+        just artifact of the message framing. This might change later.
+
+  4)    The NUL character is not special in message framing, and
+        basically could end up inside a parameter, but as it would
+        cause extra complexities in normal C string handling. Therefore
+        NUL is not allowed within messages.
+
+  5)    The last parameter may be an empty string.
+
+  6)    Use of the extended prefix (['!' <user> ] ['@' <host> ]) must
+        not be used in server to server communications and is only
+        intended for server to client messages in order to provide
+        clients with more useful information about who a message is
+        from without the need for additional queries.
+
+   Most protocol messages specify additional semantics and syntax for
+   the extracted parameter strings dictated by their position in the
+   list.  For example, many server commands will assume that the first
+   parameter after the command is the list of targets, which can be
+   described with:
+
+   <target>     ::= <to> [ "," <target> ]
+   <to>         ::= <channel> | <user> '@' <servername> | <nick> | <mask>
+   <channel>    ::= ('#' | '&' | '+') <chstring>
+   <servername> ::= <host>
+   <host>       ::= see RFC 952 [DNS:4] for details on allowed hostnames
+   <nick>       ::= <letter> { <letter> | <number> | <special> }
+   <mask>       ::= $(<servername> | @<hostname>)
+   <chstring>   ::= <any 8bit code except SPACE, BELL, NUL, CR, LF and
+                     comma (',')>
+
+   Other parameter syntaxes are:
+
+   <user>       ::= <nonwhite> { <nonwhite> }
+   <letter>     ::= 'a' ... 'z' | 'A' ... 'Z'
+   <number>     ::= '0' ... '9'
+   <special>    ::= '-' | '[' | ']' | '\' | '`' | '^' | '{' | '}'
+
+
+
+Oikarinen & Reed                                                [Page 9]
+\f
+RFC 1459              Internet Relay Chat Protocol              May 1993
+
+
+   <nonwhite>   ::= <any 8bit code except SPACE (0x20), NUL (0x0), CR
+                     (0xd), and LF (0xa)>
+
+2.4 Numeric replies
+
+   Most of the messages sent to the server generate a reply of some
+   sort.  The most common reply is the numeric reply, used for both
+   errors and normal replies.  The numeric reply must be sent as one
+   message consisting of the sender prefix, the three digit numeric, and
+   the target of the reply.  A numeric reply is not allowed to originate
+   from a client; any such messages received by a server are silently
+   dropped. In all other respects, a numeric reply is just like a normal
+   message, except that the keyword is made up of 3 numeric digits
+   rather than a string of letters.  A list of different replies is
+   supplied in section 6.
+
+3. IRC Concepts.
+
+   This section is devoted to describing the actual concepts behind  the
+   organization  of  the  IRC  protocol and how the current
+   implementations deliver different classes of messages.
+
+
+
+                          1--\
+                              A        D---4
+                          2--/ \      /
+                                B----C
+                               /      \
+                              3        E
+
+   Servers: A, B, C, D, E         Clients: 1, 2, 3, 4
+
+                    [ Fig. 2. Sample small IRC network ]
+
+3.1 One-to-one communication
+
+   Communication on a one-to-one basis is usually only performed by
+   clients, since most server-server traffic is not a result of servers
+   talking only to each other.  To provide a secure means for clients to
+   talk to each other, it is required that all servers be able to send a
+   message in exactly one direction along the spanning tree in order to
+   reach any client.  The path of a message being delivered is the
+   shortest path between any two points on the spanning tree.
+
+   The following examples all refer to Figure 2 above.
+
+
+
+
+
+Oikarinen & Reed                                               [Page 10]
+\f
+RFC 1459              Internet Relay Chat Protocol              May 1993
+
+
+Example 1:
+     A message between clients 1 and 2 is only seen by server A, which
+     sends it straight to client 2.
+
+Example 2:
+     A message between clients 1 and 3 is seen by servers A & B, and
+     client 3.  No other clients or servers are allowed see the message.
+
+Example 3:
+     A message between clients 2 and 4 is seen by servers A, B, C & D
+     and client 4 only.
+
+3.2 One-to-many
+
+   The main goal of IRC is to provide a  forum  which  allows  easy  and
+   efficient  conferencing (one to many conversations).  IRC offers
+   several means to achieve this, each serving its own purpose.
+
+3.2.1 To a list
+
+   The least efficient style of one-to-many conversation is through
+   clients talking to a 'list' of users.  How this is done is almost
+   self explanatory: the client gives a list of destinations to which
+   the message is to be delivered and the server breaks it up and
+   dispatches a separate copy of the message to each given destination.
+   This isn't as efficient as using a group since the destination list
+   is broken up and the dispatch sent without checking to make sure
+   duplicates aren't sent down each path.
+
+3.2.2 To a group (channel)
+
+   In IRC the channel has a role equivalent to that of the multicast
+   group; their existence is dynamic (coming and going as people join
+   and leave channels) and the actual conversation carried out on a
+   channel is only sent to servers which are supporting users on a given
+   channel.  If there are multiple users on a server in the same
+   channel, the message text is sent only once to that server and then
+   sent to each client on the channel.  This action is then repeated for
+   each client-server combination until the original message has fanned
+   out and reached each member of the channel.
+
+   The following examples all refer to Figure 2.
+
+Example 4:
+     Any channel with 1 client in it. Messages to the channel go to the
+     server and then nowhere else.
+
+
+
+
+
+Oikarinen & Reed                                               [Page 11]
+\f
+RFC 1459              Internet Relay Chat Protocol              May 1993
+
+
+Example 5:
+     2 clients in a channel. All messages traverse a path as if they
+     were private messages between the two clients outside a channel.
+
+Example 6:
+     Clients 1, 2 and 3 in a channel.  All messages to the channel are
+     sent to all clients and only those servers which must be traversed
+     by the message if it were a private message to a single client.  If
+     client 1 sends a message, it goes back to client 2 and then via
+     server B to client 3.
+
+3.2.3 To a host/server mask
+
+   To provide IRC operators with some mechanism to send  messages  to  a
+   large body of related users, host and server mask messages are
+   provided.  These messages are sent to users whose host or server
+   information  match that  of  the mask.  The messages are only sent to
+   locations where users are, in a fashion similar to that of channels.
+
+3.3 One-to-all
+
+   The one-to-all type of message is better described as a broadcast
+   message, sent to all clients or servers or both.  On a large network
+   of users and servers, a single message can result in a lot of traffic
+   being sent over the network in an effort to reach all of the desired
+   destinations.
+
+   For some messages, there is no option but to broadcast it to all
+   servers so that the state information held by each server is
+   reasonably consistent between servers.
+
+3.3.1 Client-to-Client
+
+   There is no class of message which, from a single message, results in
+   a message being sent to every other client.
+
+3.3.2 Client-to-Server
+
+   Most of the commands which result in a change of state information
+   (such as channel membership, channel mode, user status, etc) must be
+   sent to all servers by default, and this distribution may not be
+   changed by the client.
+
+3.3.3 Server-to-Server.
+
+   While most messages between servers are distributed to all 'other'
+   servers, this is only required for any message that affects either a
+   user, channel or server.  Since these are the basic items found in
+
+
+
+Oikarinen & Reed                                               [Page 12]
+\f
+RFC 1459              Internet Relay Chat Protocol              May 1993
+
+
+   IRC, nearly all messages originating from a server are broadcast to
+   all other connected servers.
+
+4. Message details
+
+   On the following pages are descriptions of each message recognized by
+   the IRC server and client.  All commands described in this section
+   must be implemented by any server for this protocol.
+
+   Where the reply ERR_NOSUCHSERVER is listed, it means that the
+   <server> parameter could not be found.  The server must not send any
+   other replies after this for that command.
+
+   The server to which a client is connected is required to parse the
+   complete message, returning any appropriate errors.  If the server
+   encounters a fatal error while parsing a message, an error must be
+   sent back to the client and the parsing terminated.  A fatal error
+   may be considered to be incorrect command, a destination which is
+   otherwise unknown to the server (server, nick or channel names fit
+   this category), not enough parameters or incorrect privileges.
+
+   If a full set of parameters is presented, then each must be checked
+   for validity and appropriate responses sent back to the client.  In
+   the case of messages which use parameter lists using the comma as an
+   item separator, a reply must be sent for each item.
+
+   In the examples below, some messages appear using the full format:
+
+   :Name COMMAND parameter list
+
+   Such examples represent a message from "Name" in transit between
+   servers, where it is essential to include the name of the original
+   sender of the message so remote servers may send back a reply along
+   the correct path.
+
+4.1 Connection Registration
+
+   The commands described here are used to register a connection with an
+   IRC server as either a user or a server as well as correctly
+   disconnect.
+
+   A "PASS" command is not required for either client or server
+   connection to be registered, but it must precede the server message
+   or the latter of the NICK/USER combination.  It is strongly
+   recommended that all server connections have a password in order to
+   give some level of security to the actual connections.  The
+   recommended order for a client to register is as follows:
+
+
+
+
+Oikarinen & Reed                                               [Page 13]
+\f
+RFC 1459              Internet Relay Chat Protocol              May 1993
+
+
+           1. Pass message
+           2. Nick message
+           3. User message
+
+4.1.1 Password message
+
+
+      Command: PASS
+   Parameters: <password>
+
+   The PASS command is used to set a 'connection password'.  The
+   password can and must be set before any attempt to register the
+   connection is made.  Currently this requires that clients send a PASS
+   command before sending the NICK/USER combination and servers *must*
+   send a PASS command before any SERVER command.  The password supplied
+   must match the one contained in the C/N lines (for servers) or I
+   lines (for clients).  It is possible to send multiple PASS commands
+   before registering but only the last one sent is used for
+   verification and it may not be changed once registered.  Numeric
+   Replies:
+
+           ERR_NEEDMOREPARAMS              ERR_ALREADYREGISTRED
+
+   Example:
+
+           PASS secretpasswordhere
+
+4.1.2 Nick message
+
+      Command: NICK
+   Parameters: <nickname> [ <hopcount> ]
+
+   NICK message is used to give user a nickname or change the previous
+   one.  The <hopcount> parameter is only used by servers to indicate
+   how far away a nick is from its home server.  A local connection has
+   a hopcount of 0.  If supplied by a client, it must be ignored.
+
+   If a NICK message arrives at a server which already knows about an
+   identical nickname for another client, a nickname collision occurs.
+   As a result of a nickname collision, all instances of the nickname
+   are removed from the server's database, and a KILL command is issued
+   to remove the nickname from all other server's database. If the NICK
+   message causing the collision was a nickname change, then the
+   original (old) nick must be removed as well.
+
+   If the server recieves an identical NICK from a client which is
+   directly connected, it may issue an ERR_NICKCOLLISION to the local
+   client, drop the NICK command, and not generate any kills.
+
+
+
+Oikarinen & Reed                                               [Page 14]
+\f
+RFC 1459              Internet Relay Chat Protocol              May 1993
+
+
+   Numeric Replies:
+
+           ERR_NONICKNAMEGIVEN             ERR_ERRONEUSNICKNAME
+           ERR_NICKNAMEINUSE               ERR_NICKCOLLISION
+
+   Example:
+
+   NICK Wiz                        ; Introducing new nick "Wiz".
+
+   :WiZ NICK Kilroy                ; WiZ changed his nickname to Kilroy.
+
+4.1.3 User message
+
+      Command: USER
+   Parameters: <username> <usermode> <snomask> <info>
+
+   The USER message is used at the beginning of connection to specify
+   the username, usermod, snomask and information of a new user. Servers
+   use the NICK command to send all information once USER and NICK have
+   been received from the client. Only after both USER and NICK have been
+   received from a client does a user become registered.
+
+   Undernet does not send USER between servers, NICK is used to send
+   all information about a user. The usermode parameter allows clients to
+   set their initial user mode (see MODE) upon registration, the snomask
+   parameter allows the user to specify a specific set of server notices
+   they wish to receive. If the usermode and snomasks look like host names
+   they are ignored. If a valid ident response is received from the
+   client's host upon connection, the name returned from the ident server
+   is used and username is ignored. 
+   It must be noted that info parameter must be the last parameter,
+   because it may contain space characters and must be prefixed with a
+   colon (':') to make sure this is recognised as such.
+
+   Since it is easy for a client to lie about its username by relying
+   solely on the USER message, the use of an "Identity Server" is
+   recommended.  If the host which a user connects from has such a
+   server enabled the username is set to that as in the reply from the
+   "Identity Server".
+
+   Numeric Replies:
+
+           ERR_NEEDMOREPARAMS              ERR_ALREADYREGISTRED
+
+   Examples:
+
+
+   USER guest tolmoon tolsun :Ronnie Reagan
+
+
+
+Oikarinen & Reed                                               [Page 15]
+\f
+RFC 1459              Internet Relay Chat Protocol              May 1993
+
+
+                                   ; User registering themselves with a
+                                   username of "guest" and real name
+                                   "Ronnie Reagan".
+
+
+   :testnick USER guest tolmoon tolsun :Ronnie Reagan
+                                   ; message between servers with the
+                                   nickname for which the USER command
+                                   belongs to
+
+4.1.4 Server message
+
+      Command: SERVER
+   Parameters: <servername> <hopcount> <info>
+
+   The server message is used to tell a server that the other end of a
+   new connection is a server. This message is also used to pass server
+   data over whole net.  When a new server is connected to net,
+   information about it be broadcast to the whole network.  <hopcount>
+   is used to give all servers some internal information on how far away
+   all servers are.  With a full server list, it would be possible to
+   construct a map of the entire server tree, but hostmasks prevent this
+   from being done.
+
+   The SERVER message must only be accepted from either (a) a connection
+   which is yet to be registered and is attempting to register as a
+   server, or (b) an existing connection to another server, in  which
+   case the SERVER message is introducing a new server behind that
+   server.
+
+   Most errors that occur with the receipt of a SERVER command result in
+   the connection being terminated by the destination host (target
+   SERVER).  Error replies are usually sent using the "ERROR" command
+   rather than the numeric since the ERROR command has several useful
+   properties which make it useful here.
+
+   If a SERVER message is parsed and attempts to introduce a server
+   which is already known to the receiving server, the connection from
+   which that message must be closed (following the correct procedures),
+   since a duplicate route to a server has formed and the acyclic nature
+   of the IRC tree broken.
+
+   Numeric Replies:
+
+           ERR_ALREADYREGISTRED
+
+   Example:
+
+
+
+
+Oikarinen & Reed                                               [Page 16]
+\f
+RFC 1459              Internet Relay Chat Protocol              May 1993
+
+
+SERVER test.oulu.fi 1 :[tolsun.oulu.fi] Experimental server
+                                ; New server test.oulu.fi introducing
+                                itself and attempting to register.  The
+                                name in []'s is the hostname for the
+                                host running test.oulu.fi.
+
+
+:tolsun.oulu.fi SERVER csd.bu.edu 5 :BU Central Server
+                                ; Server tolsun.oulu.fi is our uplink
+                                for csd.bu.edu which is 5 hops away.
+
+4.1.5 Oper
+
+      Command: OPER
+   Parameters: <user> <password>
+
+   OPER message is used by a normal user to obtain operator privileges.
+   The combination of <user> and <password> are required to gain
+   Operator privileges.
+
+   If the client sending the OPER command supplies the correct password
+   for the given user, the server then informs the rest of the network
+   of the new operator by issuing a "MODE +o" for the clients nickname.
+
+   The OPER message is client-server only.
+
+   Numeric Replies:
+
+           ERR_NEEDMOREPARAMS              RPL_YOUREOPER
+           ERR_NOOPERHOST                  ERR_PASSWDMISMATCH
+
+   Example:
+
+   OPER foo bar                    ; Attempt to register as an operator
+                                   using a username of "foo" and "bar" as
+                                   the password.
+
+4.1.6 Quit
+
+      Command: QUIT
+   Parameters: [<Quit message>]
+
+   A client session is ended with a quit message.  The server must close
+   the connection to a client which sends a QUIT message. If a "Quit
+   Message" is given, this will be sent instead of the default message,
+   the nickname.
+
+   When netsplits (disconnecting of two servers) occur, the quit message
+
+
+
+Oikarinen & Reed                                               [Page 17]
+\f
+RFC 1459              Internet Relay Chat Protocol              May 1993
+
+
+   is composed of the names of two servers involved, separated by a
+   space.  The first name is that of the server which is still connected
+   and the second name is that of the server that has become
+   disconnected.
+
+   If, for some other reason, a client connection is closed without  the
+   client  issuing  a  QUIT  command  (e.g.  client  dies and EOF occurs
+   on socket), the server is required to fill in the quit  message  with
+   some sort  of  message  reflecting the nature of the event which
+   caused it to happen.
+
+   Numeric Replies:
+
+           None.
+
+   Examples:
+
+   QUIT :Gone to have lunch        ; Preferred message format.
+
+4.1.7 Server quit message
+
+      Command: SQUIT
+   Parameters: <server> <comment>
+
+   The SQUIT message is needed to tell about quitting or dead servers.
+   If a server wishes to break the connection to another server it must
+   send a SQUIT message to the other server, using the the name of the
+   other server as the server parameter, which then closes its
+   connection to the quitting server.
+
+   This command is also available operators to help keep a network of
+   IRC servers connected in an orderly fashion.  Operators may also
+   issue an SQUIT message for a remote server connection.  In this case,
+   the SQUIT must be parsed by each server inbetween the operator and
+   the remote server, updating the view of the network held by each
+   server as explained below.
+
+   The <comment> should be supplied by all operators who execute a SQUIT
+   for a remote server (that is not connected to the server they are
+   currently on) so that other operators are aware for the reason of
+   this action.  The <comment> is also filled in by servers which may
+   place an error or similar message here.
+
+   Both of the servers which are on either side of the connection being
+   closed are required to to send out a SQUIT message (to all its other
+   server connections) for all other servers which are considered to be
+   behind that link.
+
+
+
+
+Oikarinen & Reed                                               [Page 18]
+\f
+RFC 1459              Internet Relay Chat Protocol              May 1993
+
+
+   Similarly, a QUIT message must be sent to the other connected servers
+   rest of the network on behalf of all clients behind that link.  In
+   addition to this, all channel members of a channel which lost a
+   member due to the split must be sent a QUIT message.
+
+   If a server connection is terminated prematurely (e.g. the server  on
+   the  other  end  of  the  link  died),  the  server  which  detects
+   this disconnection is required to inform the rest of  the  network
+   that  the connection  has  closed  and  fill  in  the comment field
+   with something appropriate.
+
+   Numeric replies:
+
+           ERR_NOPRIVILEGES                ERR_NOSUCHSERVER
+
+   Example:
+
+   SQUIT tolsun.oulu.fi :Bad Link ? ; the server link tolson.oulu.fi has
+                                   been terminated because of "Bad Link".
+
+   :Trillian SQUIT cm22.eng.umd.edu :Server out of control
+                                    ; message from Trillian to disconnect
+                                   "cm22.eng.umd.edu" from the net
+                                    because "Server out of control".
+
+4.2 Channel operations
+
+   This group of messages is concerned with manipulating channels, their
+   properties (channel modes), and their contents (typically clients).
+   In implementing these, a number of race conditions are inevitable
+   when clients at opposing ends of a network send commands which will
+   ultimately clash.  It is also required that servers keep a nickname
+   history to ensure that wherever a <nick> parameter is given, the
+   server check its history in case it has recently been changed.
+
+4.2.1 Join message
+
+      Command: JOIN
+   Parameters: <channel>{,<channel>} [<key>{,<key>}]
+
+   The JOIN command is used by client to start listening a specific
+   channel. Whether or not a client is allowed to join a channel is
+   checked only by the server the client is connected to; all other
+   servers automatically add the user to the channel when it is received
+   from other servers.  The conditions which affect this are as follows:
+
+           1.  the user must be invited if the channel is invite-only;
+
+
+
+
+Oikarinen & Reed                                               [Page 19]
+\f
+RFC 1459              Internet Relay Chat Protocol              May 1993
+
+
+           2.  the user's nick/username/hostname must not match any
+               active bans;
+
+           3.  the correct key (password) must be given if it is set.
+
+   These are discussed in more detail under the MODE command (see
+   section 4.2.3 for more details).
+
+   Once a user has joined a channel, they receive notice about all
+   commands their server receives which affect the channel.  This
+   includes MODE, KICK, PART, QUIT and of course PRIVMSG/NOTICE.  The
+   JOIN command needs to be broadcast to all servers so that each server
+   knows where to find the users who are on the channel.  This allows
+   optimal delivery of PRIVMSG/NOTICE messages to the channel.
+
+   If a JOIN is successful, the user is then sent the channel's topic
+   (using RPL_TOPIC) and the list of users who are on the channel (using
+   RPL_NAMREPLY), which must include the user joining.
+
+   Numeric Replies:
+
+           ERR_NEEDMOREPARAMS              ERR_BANNEDFROMCHAN
+           ERR_INVITEONLYCHAN              ERR_BADCHANNELKEY
+           ERR_CHANNELISFULL               ERR_BADCHANMASK
+           ERR_NOSUCHCHANNEL               ERR_TOOMANYCHANNELS
+           RPL_TOPIC
+
+   Examples:
+
+   JOIN #foobar                    ; join channel #foobar.
+
+   JOIN &foo fubar                 ; join channel &foo using key "fubar".
+
+   JOIN #foo,&bar fubar            ; join channel #foo using key "fubar"
+                                   and &bar using no key.
+
+   JOIN #foo,#bar fubar,foobar     ; join channel #foo using key "fubar".
+                                   and channel #bar using key "foobar".
+
+   JOIN #foo,#bar                  ; join channels #foo and #bar.
+
+   :WiZ JOIN #Twilight_zone        ; JOIN message from WiZ
+
+4.2.2 Part message
+
+      Command: PART
+   Parameters: <channel>{,<channel>}
+
+
+
+
+Oikarinen & Reed                                               [Page 20]
+\f
+RFC 1459              Internet Relay Chat Protocol              May 1993
+
+
+   The PART message causes the client sending the message to be removed
+   from the list of active users for all given channels listed in the
+   parameter string.
+
+   Numeric Replies:
+
+           ERR_NEEDMOREPARAMS              ERR_NOSUCHCHANNEL
+           ERR_NOTONCHANNEL
+
+   Examples:
+
+   PART #twilight_zone             ; leave channel "#twilight_zone"
+
+   PART #oz-ops,&group5            ; leave both channels "&group5" and
+                                   "#oz-ops".
+
+4.2.3 Mode message
+
+      Command: MODE
+
+   The MODE command is a dual-purpose command in IRC.  It allows both
+   usernames and channels to have their mode changed.  The rationale for
+   this choice is that one day nicknames will be obsolete and the
+   equivalent property will be the channel.
+
+   When parsing MODE messages, it is recommended that the entire message
+   be parsed first and then the changes which resulted then passed on.
+
+4.2.3.1 Channel modes
+
+   Parameters: <channel> {[+|-]|o|p|s|i|t|n|b|v} [<limit>] [<user>]
+               [<ban mask>]
+
+   The MODE command is provided so that channel operators may change the
+   characteristics of `their' channel.  It is also required that servers
+   be able to change channel modes so that channel operators may be
+   created.
+
+   The various modes available for channels are as follows:
+
+           o - give/take channel operator privileges;
+           p - private channel flag;
+           s - secret channel flag;
+           i - invite-only channel flag;
+           t - topic settable by channel operator only flag;
+           n - no messages to channel from clients on the outside;
+           m - moderated channel;
+           l - set the user limit to channel;
+
+
+
+Oikarinen & Reed                                               [Page 21]
+\f
+RFC 1459              Internet Relay Chat Protocol              May 1993
+
+
+           b - set a ban mask to keep users out;
+           v - give/take the ability to speak on a moderated channel;
+           k - set a channel key (password).
+
+   When using the 'o' and 'b' options, a restriction on a total of three
+   per mode command has been imposed.  That is, any combination of 'o'
+   and
+
+4.2.3.2 User modes
+
+   Parameters: <nickname> {[+|-]|i|w|s|o}
+
+   The user MODEs are typically changes which affect either how the
+   client is seen by others or what 'extra' messages the client is sent.
+   A user MODE command may only be accepted if both the sender of the
+   message and the nickname given as a parameter are both the same.
+
+   The available modes are as follows:
+
+           i - marks a users as invisible;
+           s - marks a user for receipt of server notices;
+           w - user receives wallops;
+           o - operator flag.
+
+   Additional modes may be available later on.
+
+   If a user attempts to make themselves an operator using the "+o"
+   flag, the attempt should be ignored.  There is no restriction,
+   however, on anyone `deopping' themselves (using "-o").  Numeric
+   Replies:
+
+           ERR_NEEDMOREPARAMS              RPL_CHANNELMODEIS
+           ERR_CHANOPRIVSNEEDED            ERR_NOSUCHNICK
+           ERR_NOTONCHANNEL                ERR_KEYSET
+           RPL_BANLIST                     RPL_ENDOFBANLIST
+           ERR_UNKNOWNMODE                 ERR_NOSUCHCHANNEL
+
+           ERR_USERSDONTMATCH              RPL_UMODEIS
+           ERR_UMODEUNKNOWNFLAG
+
+   Examples:
+
+           Use of Channel Modes:
+
+MODE #Finnish +im               ; Makes #Finnish channel moderated and
+                                'invite-only'.
+
+MODE #Finnish +o Kilroy         ; Gives 'chanop' privileges to Kilroy on
+
+
+
+Oikarinen & Reed                                               [Page 22]
+\f
+RFC 1459              Internet Relay Chat Protocol              May 1993
+
+
+                                channel #Finnish.
+
+MODE #Finnish +v Wiz            ; Allow WiZ to speak on #Finnish.
+
+MODE #Fins -s                   ; Removes 'secret' flag from channel
+                                #Fins.
+
+MODE #42 +k oulu                ; Set the channel key to "oulu".
+
+MODE #eu-opers +l 10            ; Set the limit for the number of users
+                                on channel to 10.
+
+MODE &oulu +b                   ; list ban masks set for channel.
+
+MODE &oulu +b *!*@*             ; prevent all users from joining.
+
+MODE &oulu +b *!*@*.edu         ; prevent any user from a hostname
+                                matching *.edu from joining.
+
+        Use of user Modes:
+
+:MODE WiZ -w                    ; turns reception of WALLOPS messages
+                                off for WiZ.
+
+:Angel MODE Angel +i            ; Message from Angel to make themselves
+                                invisible.
+
+MODE WiZ -o                     ; WiZ 'deopping' (removing operator
+                                status).  The plain reverse of this
+                                command ("MODE WiZ +o") must not be
+                                allowed from users since would bypass
+                                the OPER command.
+
+4.2.4 Topic message
+
+      Command: TOPIC
+   Parameters: <channel> [<topic>]
+
+   The TOPIC message is used to change or view the topic of a channel.
+   The topic for channel <channel> is returned if there is no <topic>
+   given.  If the <topic> parameter is present, the topic for that
+   channel will be changed, if the channel modes permit this action.
+   You may not query a topic from outside a secret channel.  Modeless
+   channels don't have a topic and thus ERR_CHANOPRIVSNEEDED is returned.
+   A list of channels may be specified comma seperated.
+
+   Numeric Replies:
+
+           ERR_NEEDMOREPARAMS              ERR_NOTONCHANNEL
+           RPL_NOTOPIC                     RPL_TOPIC
+           ERR_CHANOPRIVSNEEDED            ERR_NOSUCHCHANNEL
+          RPL_TOPICWHOTIME
+
+
+
+Oikarinen & Reed                                               [Page 23]
+\f
+RFC 1459              Internet Relay Chat Protocol              May 1993
+
+
+   Examples:
+
+   :Wiz TOPIC #test :New topic     ;User Wiz setting the topic.
+
+   TOPIC #test :another topic      ;set the topic on #test to "another
+                                   topic".
+
+   TOPIC #test                     ; check the topic for #test.
+
+   TOPIC #test,#testing            ; check the topic on #test and #testing
+
+   TOPIC #test,#testing :Topic     ; set the topic on #test and #testing
+0
+
+4.2.5 Names message
+
+      Command: NAMES
+   Parameters: [<channel>{,<channel>}]
+
+   By using the NAMES command, a user can list all nicknames that are
+   visible to them on any channel that they can see.  Channel names
+   which they can see are those which aren't private (+p) or secret (+s)
+   or those which they are actually on.  The <channel> parameter
+   specifies which channel(s) to return information about if valid.
+   There is no error reply for bad channel names.
+
+   If no <channel> parameter is given, a list of all channels and their
+   occupants is returned.  At the end of this list, a list of users who
+   are visible but either not on any channel or not on a visible channel
+   are listed as being on `channel' "*".
+
+   Numerics:
+
+           RPL_NAMREPLY                    RPL_ENDOFNAMES
+           ERR_NEEDMOREPARAMS
+
+   Examples:
+
+   NAMES #twilight_zone,#42        ; list visible users on #twilight_zone
+                                   and #42 if the channels are visible to
+                                   you.
+
+   NAMES 0                         ; list all visible channels and users
+
+   NAMES                           ; does nothing because of the amount
+                                   of users that would do it by accident
+
+4.2.6 List message
+
+      Command: LIST
+   Parameters: [<channel>{,<channel>} [<server>]]
+
+   The list message is used to list channels and their topics.  If  the
+   <channel>  parameter  is  used,  only  the  status  of  that  channel
+   is displayed.  Private  channels  are  listed  (without  their
+   topics)  as channel "Prv" unless the client generating the query is
+   actually on that channel.  Likewise, secret channels are not listed
+
+
+
+Oikarinen & Reed                                               [Page 24]
+\f
+RFC 1459              Internet Relay Chat Protocol              May 1993
+
+
+   at  all  unless  the client is a member of the channel in question.
+
+   Numeric Replies:
+
+           ERR_NOSUCHSERVER                RPL_LISTSTART
+           RPL_LIST                        RPL_LISTEND
+
+   Examples:
+
+   LIST                            ; List all channels.
+
+   LIST #twilight_zone,#42         ; List channels #twilight_zone and #42
+
+4.2.7 Invite message
+
+      Command: INVITE
+   Parameters: <nickname> <channel>
+
+   The INVITE message is used to invite users to a channel.  The
+   parameter <nickname> is the nickname of the person to be invited to
+   the target channel <channel>.  There is no requirement that the
+   channel the target user is being invited to must exist or be a valid
+   channel.  To invite a user to a channel which is invite only (MODE
+   +i), the client sending the invite must be recognised as being a
+   channel operator on the given channel.
+
+   Numeric Replies:
+
+           ERR_NEEDMOREPARAMS              ERR_NOSUCHNICK
+           ERR_NOTONCHANNEL                ERR_USERONCHANNEL
+           ERR_CHANOPRIVSNEEDED
+           RPL_INVITING                    RPL_AWAY
+
+   Examples:
+
+   :Angel INVITE Wiz #Dust         ; User Angel inviting WiZ to channel
+                                   #Dust
+
+   INVITE Wiz #Twilight_Zone       ; Command to invite WiZ to
+                                   #Twilight_zone
+
+4.2.8 Kick command
+
+      Command: KICK
+   Parameters: <channel> <user> [<comment>]
+
+   The KICK command can be  used  to  forcibly  remove  a  user  from  a
+   channel.   It  'kicks  them  out'  of the channel (forced PART).
+
+
+
+Oikarinen & Reed                                               [Page 25]
+\f
+RFC 1459              Internet Relay Chat Protocol              May 1993
+
+
+   Only a channel operator may kick another user out of a  channel.
+   Each  server that  receives  a KICK message checks that it is valid
+   (ie the sender is actually a  channel  operator)  before  removing
+   the  victim  from  the channel.
+
+   Numeric Replies:
+
+           ERR_NEEDMOREPARAMS              ERR_NOSUCHCHANNEL
+           ERR_BADCHANMASK                 ERR_CHANOPRIVSNEEDED
+           ERR_NOTONCHANNEL
+
+   Examples:
+
+KICK &Melbourne Matthew         ; Kick Matthew from &Melbourne
+
+KICK #Finnish John :Speaking English
+                                ; Kick John from #Finnish using
+                                "Speaking English" as the reason
+                                (comment).
+
+:WiZ KICK #Finnish John         ; KICK message from WiZ to remove John
+                                from channel #Finnish
+
+NOTE:
+     It is possible to extend the KICK command parameters to the
+following:
+
+<channel>{,<channel>} <user>{,<user>} [<comment>]
+
+4.3 Server queries and commands
+
+   The server query group of commands has been designed to return
+   information about any server which is connected to the network.  All
+   servers connected must respond to these queries and respond
+   correctly.  Any invalid response (or lack thereof) must be considered
+   a sign of a broken server and it must be disconnected/disabled as
+   soon as possible until the situation is remedied.
+
+   In these queries, where a parameter appears as "<server>", it will
+   usually mean it can be a nickname or a server or a wildcard name of
+   some sort.  For each parameter, however, only one query and set of
+   replies is to be generated.
+
+4.3.1 Version message
+
+      Command: VERSION
+   Parameters: [<server>]
+
+
+
+
+Oikarinen & Reed                                               [Page 26]
+\f
+RFC 1459              Internet Relay Chat Protocol              May 1993
+
+
+   The VERSION message is used  to  query  the  version  of  the  server
+   program.  An optional parameter <server> is used to query the version
+   of the server program which a client is not directly connected to.
+
+   Numeric Replies:
+
+           ERR_NOSUCHSERVER                RPL_VERSION
+
+   Examples:
+
+   :Wiz VERSION *.se               ; message from Wiz to check the version
+                                   of a server matching "*.se"
+
+   VERSION tolsun.oulu.fi          ; check the version of server
+                                   "tolsun.oulu.fi".
+
+4.3.2 Stats message
+
+      Command: STATS
+   Parameters: [<query> [<server>]]
+
+   Many stats commands are only available to opers, please document
+   which ones are available to users and which are available to opers.
+
+   The stats message is used to query statistics of certain server.  If
+   <server> parameter is omitted, only the end of stats reply is sent
+   back.  The implementation of this command is highly dependent on the
+   server which replies, although the server must be able to supply
+   information as described by the queries below (or similar).
+
+   A query may be given by any single letter which is only checked by
+   the destination server (if given as the <server> parameter) and is
+   otherwise passed on by intermediate servers, ignored and unaltered.
+   The following queries are those found in the current IRC
+   implementation and provide a large portion of the setup information
+   for that server.  Although these may not be supported in the same way
+   by other versions, all servers should be able to supply a valid reply
+   to a STATS query which is consistent with the reply formats currently
+   used and the purpose of the query.
+
+   The currently supported queries are:
+
+           c - returns a list of servers which the server may connect
+               to or allow connections from;
+           h - returns a list of servers which are either forced to be
+               treated as leaves or allowed to act as hubs;
+           i - returns a list of hosts which the server allows a client
+               to connect from;
+           k - returns a list of banned username/hostname combinations
+               for that server;
+           l - returns a list of the server's connections, showing how
+
+
+
+Oikarinen & Reed                                               [Page 27]
+\f
+RFC 1459              Internet Relay Chat Protocol              May 1993
+
+
+               long each connection has been established and the traffic
+               over that connection in bytes and messages for each
+               direction;
+           m - returns a list of commands supported by the server and
+               the usage count for each if the usage count is non zero;
+           o - returns a list of hosts from which normal clients may
+               become operators;
+           y - show Y (Class) lines from server's configuration file;
+           u - returns a string showing how long the server has been up.
+
+   Numeric Replies:
+
+           ERR_NOSUCHSERVER
+           RPL_STATSCLINE                  RPL_STATSNLINE
+           RPL_STATSILINE                  RPL_STATSKLINE
+           RPL_STATSQLINE                  RPL_STATSLLINE
+           RPL_STATSLINKINFO               RPL_STATSUPTIME
+           RPL_STATSCOMMANDS               RPL_STATSOLINE
+           RPL_STATSHLINE                  RPL_ENDOFSTATS
+
+   Examples:
+
+STATS m                         ; check the command usage for the server
+                                you are connected to
+
+:Wiz STATS c eff.org            ; request by WiZ for C/N line
+                                information from server eff.org
+
+4.3.3 Links message
+
+      Command: LINKS
+   Parameters: [[<remote server>] <server mask>]
+
+   With LINKS, a user can list all servers which are known by the server
+   answering the query.  The returned list of servers must match the
+   mask, or if no mask is given, the full list is returned.
+
+   If <remote server> is given in addition to <server mask>, the LINKS
+   command is forwarded to the first server found that matches that name
+   (if any), and that server is then required to answer the query.
+
+   Numeric Replies:
+
+           ERR_NOSUCHSERVER
+           RPL_LINKS                       RPL_ENDOFLINKS
+
+   Examples:
+
+
+
+
+Oikarinen & Reed                                               [Page 28]
+\f
+RFC 1459              Internet Relay Chat Protocol              May 1993
+
+
+LINKS *.au                      ; list all servers which have a name
+                                that matches *.au;
+
+:WiZ LINKS *.bu.edu *.edu       ; LINKS message from WiZ to the first
+                                server matching *.edu for a list of
+                                servers matching *.bu.edu.
+
+4.3.4 Time message
+
+      Command: TIME
+   Parameters: [<server>]
+
+   The time message is used to query local time from the specified
+   server. If the server parameter is not given, the server handling the
+   command must reply to the query.
+
+   Numeric Replies:
+
+           ERR_NOSUCHSERVER                RPL_TIME
+
+   Examples:
+
+   TIME tolsun.oulu.fi             ; check the time on the server
+                                   "tolson.oulu.fi"
+
+   Angel TIME *.au                 ; user angel checking the time on a
+                                   server matching "*.au"
+
+4.3.5 Connect message
+
+      Command: CONNECT
+   Parameters: <target server> [<port> [<remote server>]]
+
+   The CONNECT command can be used to force a server to try to establish
+   a new connection to another server immediately.  CONNECT is a
+   privileged command and is to be available only to IRC Operators.  If
+   a remote server is given then the CONNECT attempt is made by that
+   server to <target server> and <port>.  A port of 0 means use the default
+   port number.  Most errors are reported in notice's.
+
+   Numeric Replies:
+
+           ERR_NOSUCHSERVER                ERR_NOPRIVILEGES
+           ERR_NEEDMOREPARAMS
+
+   Examples:
+
+CONNECT tolsun.oulu.fi          ; Attempt to connect a server to
+                                tolsun.oulu.fi
+
+
+
+Oikarinen & Reed                                               [Page 29]
+\f
+RFC 1459              Internet Relay Chat Protocol              May 1993
+
+
+:WiZ CONNECT eff.org 6667 csd.bu.edu
+                                ; CONNECT attempt by WiZ to get servers
+                                eff.org and csd.bu.edu connected on port
+                                6667.
+
+4.3.6 Trace message
+
+      Command: TRACE
+   Parameters: [<server>]
+
+   TRACE command is used to find the route to specific server.  Each
+   server that processes this message must tell the sender about it by
+   sending a reply indicating it is a pass-through link, forming a chain
+   of replies similar to that gained from using "traceroute".  After
+   sending this reply back, it must then send the TRACE message to the
+   next server until given server is reached.  If the <server> parameter
+   is omitted, it is recommended that TRACE command send a message to
+   the sender telling which servers the current server has direct
+   connection to.
+
+   If the destination given by "<server>" is an actual server, then the
+   destination server is required to report all servers and users which
+   are connected to it, although only operators are permitted to see
+   users present.  If the destination given by <server> is a nickname,
+   they only a reply for that nickname is given.
+
+   Numeric Replies:
+
+           ERR_NOSUCHSERVER
+
+   If the TRACE message is destined for another server, all intermediate
+   servers must return a RPL_TRACELINK reply to indicate that the TRACE
+   passed through it and where its going next.
+
+           RPL_TRACELINK
+   A TRACE reply may be composed of any number of the following numeric
+   replies.
+
+           RPL_TRACECONNECTING             RPL_TRACEHANDSHAKE
+           RPL_TRACEUNKNOWN                RPL_TRACEOPERATOR
+           RPL_TRACEUSER                   RPL_TRACESERVER
+           RPL_TRACESERVICE                RPL_TRACENEWTYPE
+           RPL_TRACECLASS
+
+   Examples:
+
+TRACE *.oulu.fi                 ; TRACE to a server matching *.oulu.fi
+
+
+
+
+Oikarinen & Reed                                               [Page 30]
+\f
+RFC 1459              Internet Relay Chat Protocol              May 1993
+
+
+:WiZ TRACE AngelDust            ; TRACE issued by WiZ to nick AngelDust
+
+4.3.7 Admin command
+
+      Command: ADMIN
+   Parameters: [<server>]
+
+   The admin message is used to find the name of the administrator of
+   the given server, or current server if <server> parameter is omitted.
+   Each server must have the ability to forward ADMIN messages to other
+   servers.  The given server may be a nick, where the server that the
+   nick is on will be queried.
+
+   Numeric Replies:
+
+           ERR_NOSUCHSERVER
+           RPL_ADMINME                     RPL_ADMINLOC1
+           RPL_ADMINLOC2                   RPL_ADMINEMAIL
+
+   Examples:
+
+   ADMIN tolsun.oulu.fi            ; request an ADMIN reply from
+                                   tolsun.oulu.fi
+
+   :WiZ ADMIN *.edu                ; ADMIN request from WiZ for first
+                                   server found to match *.edu.
+
+4.3.8 Info command
+
+      Command: INFO
+   Parameters: [<server>]
+
+   The INFO command is required to return information which describes
+   the server: its version, when it was compiled, the patchlevel, when
+   it was started, and any other miscellaneous information which may be
+   considered to be relevant.
+
+   Numeric Replies:
+
+           ERR_NOSUCHSERVER
+           RPL_INFO                        RPL_ENDOFINFO
+
+   Examples:
+
+   INFO csd.bu.edu                 ; request an INFO reply from
+   csd.bu.edu
+
+   :Avalon INFO *.fi               ; INFO request from Avalon for first
+                                   server found to match *.fi.
+
+
+
+Oikarinen & Reed                                               [Page 31]
+\f
+RFC 1459              Internet Relay Chat Protocol              May 1993
+
+
+   INFO Angel                      ; request info from the server that
+                                   Angel is connected to.
+
+4.4 Sending messages
+
+   The main purpose of the IRC protocol is to provide a base for clients
+   to communicate with each other.  PRIVMSG and NOTICE are the only
+   messages available which actually perform delivery of a text message
+   from one client to another - the rest just make it possible and try
+   to ensure it happens in a reliable and structured manner.
+
+4.4.1 Private messages
+
+      Command: PRIVMSG
+   Parameters: <receiver>{,<receiver>} <text to be sent>
+
+   PRIVMSG is used to send private messages between users.  <receiver>
+   is the nickname of the receiver of the message.  <receiver> can also
+   be a list of names or channels separated with commas.
+
+   The <receiver> parameter may also me a host mask  ($@mask)  or  server
+   mask  ($mask).   In  both cases the server will only send the PRIVMSG
+   to those who have a server or host matching the mask.  The mask  must
+   have at  least  1  (one)  "."  in it and no wildcards following the
+   last ".".  This requirement exists to prevent people sending messages
+   to  "$@*"  or "$*",  which  would  broadcast  to  all  users; from
+   experience, this is abused more than used responsibly and properly.
+   Wildcards are  the  '*' and  '?'   characters.   This  extension  to
+   the PRIVMSG command is only available to Operators.
+
+   Numeric Replies:
+
+           ERR_NORECIPIENT                 ERR_NOTEXTTOSEND
+           ERR_CANNOTSENDTOCHAN            ERR_NOTOPLEVEL
+           ERR_WILDTOPLEVEL                ERR_TOOMANYTARGETS
+           ERR_NOSUCHNICK
+           RPL_AWAY
+
+   Examples:
+
+:Angel PRIVMSG Wiz :Hello are you receiving this message ?
+                                ; Message from Angel to Wiz.
+
+PRIVMSG Angel :yes I'm receiving it !receiving it !'u>(768u+1n) .br ;
+                                Message to Angel.
+
+PRIVMSG jto@tolsun.oulu.fi :Hello !
+                                ; Message to a client on server
+
+
+
+Oikarinen & Reed                                               [Page 32]
+\f
+RFC 1459              Internet Relay Chat Protocol              May 1993
+
+
+                                tolsun.oulu.fi with username of "jto".
+
+PRIVMSG $*.fi :Server tolsun.oulu.fi rebooting.
+                                ; Message to everyone on a server which
+                                has a name matching *.fi.
+
+PRIVMSG $@*.edu :NSFNet is undergoing work, expect interruptions
+                                ; Message to all users who come from a
+                                host which has a name matching *.edu.
+
+4.4.2 Notice
+
+      Command: NOTICE
+   Parameters: <nickname> <text>
+
+   The NOTICE message is used similarly to PRIVMSG.  The difference
+   between NOTICE and PRIVMSG is that automatic replies must never be
+   sent in response to a NOTICE message.  This rule applies to servers
+   too - they must not send any error reply back to the client on
+   receipt of a notice.  The object of this rule is to avoid loops
+   between a client automatically sending something in response to
+   something it received.  This is typically used by automatons (clients
+   with either an AI or other interactive program controlling their
+   actions) which are always seen to be replying lest they end up in a
+   loop with another automaton.
+
+   See PRIVMSG for more details on replies and examples.
+
+4.5 User based queries
+
+   User queries are a group of commands which are primarily concerned
+   with finding details on a particular user or group users.  When using
+   wildcards with any of these commands, if they match, they will only
+   return information on users who are 'visible' to you.  The visibility
+   of a user is determined as a combination of the user's mode and the
+   common set of channels you are both on.
+
+4.5.1 Who query
+
+      Command: WHO
+   Parameters: [<name> [<o>]]
+
+   The WHO message is used by a client to generate a query which returns
+   a list of information which 'matches' the <name> parameter given by
+   the client.  In the absence of the <name> parameter, all visible
+   (users who aren't invisible (user mode +i) and who don't have a
+   common channel with the requesting client) are listed.  The same
+   result can be achieved by using a <name> of "0" or any wildcard which
+
+
+
+Oikarinen & Reed                                               [Page 33]
+\f
+RFC 1459              Internet Relay Chat Protocol              May 1993
+
+
+   will end up matching every entry possible.
+
+   The <name> passed to WHO is matched against users' host, server, real
+   name and nickname if the channel <name> cannot be found.
+
+   If the "o" parameter is passed only operators are returned according
+   to the name mask supplied.
+
+   Numeric Replies:
+
+           ERR_NOSUCHSERVER
+           RPL_WHOREPLY                    RPL_ENDOFWHO
+
+   Examples:
+
+   WHO *.fi                        ; List all users who match against
+                                   "*.fi".
+
+   WHO jto* o                      ; List all users with a match against
+                                   "jto*" if they are an operator.
+
+4.5.2 Whois query
+
+      Command: WHOIS
+   Parameters: [<server>] <nickmask>[,<nickmask>[,...]]
+
+   This message is used to query information about particular user.  The
+   server will answer this message with several numeric messages
+   indicating different statuses of each user which matches the nickmask
+   (if you are entitled to see them).  If no wildcard is present in the
+   <nickmask>, any information about that nick which you are allowed to
+   see is presented.  A comma (',') separated list of nicknames may be
+   given.
+
+   The latter version sends the query to a specific server.  It is
+   useful if you want to know how long the user in question has been
+   idle as only local server (ie. the server the user is directly
+   connected to) knows that information, while everything else is
+   globally known.
+
+   Numeric Replies:
+
+           ERR_NOSUCHSERVER                ERR_NONICKNAMEGIVEN
+           RPL_WHOISUSER                   RPL_WHOISCHANNELS
+           RPL_WHOISCHANNELS               RPL_WHOISSERVER
+           RPL_AWAY                        RPL_WHOISOPERATOR
+           RPL_WHOISIDLE                   ERR_NOSUCHNICK
+           RPL_ENDOFWHOIS
+
+
+
+Oikarinen & Reed                                               [Page 34]
+\f
+RFC 1459              Internet Relay Chat Protocol              May 1993
+
+
+   Examples:
+
+   WHOIS wiz                       ; return available user information
+                                   about nick WiZ
+
+   WHOIS eff.org trillian          ; ask server eff.org for user
+                                   information about trillian
+
+4.5.3 Whowas
+
+      Command: WHOWAS
+   Parameters: <nickname> [<count> [<server>]]
+
+   Whowas asks for information about a nickname which no longer exists.
+   This may either be due to a nickname change or the user leaving IRC.
+   In response to this query, the server searches through its nickname
+   history, looking for any nicks which are lexically the same (no wild
+   card matching here).  The history is searched backward, returning the
+   most recent entry first.  If there are multiple entries, up to
+   <count> replies will be returned (or all of them if no <count>
+   parameter is given).  If a non-positive number is passed as being
+   <count>, then a full search is done.
+
+   Numeric Replies:
+
+           ERR_NONICKNAMEGIVEN             ERR_WASNOSUCHNICK
+           RPL_WHOWASUSER                  RPL_WHOISSERVER
+           RPL_ENDOFWHOWAS
+
+   Examples:
+
+   WHOWAS Wiz                      ; return all information in the nick
+                                   history about nick "WiZ";
+
+   WHOWAS Mermaid 9                ; return at most, the 9 most recent
+                                   entries in the nick history for
+                                   "Mermaid";
+
+   WHOWAS Trillian 1 *.edu         ; return the most recent history for
+                                   "Trillian" from the first server found
+                                   to match "*.edu".
+
+4.6 Miscellaneous messages
+
+   Messages in this category do not fit into any of the above categories
+   but are nonetheless still a part of and required by the protocol.
+
+
+
+
+
+Oikarinen & Reed                                               [Page 35]
+\f
+RFC 1459              Internet Relay Chat Protocol              May 1993
+
+
+4.6.1 Kill message
+
+      Command: KILL
+   Parameters: <nickname> <comment>
+
+   The KILL message is used to cause a client-server connection to be
+   closed by the server which has the actual connection.  KILL is used
+   by servers when they encounter a duplicate entry in the list of valid
+   nicknames and is used to remove both entries.  It is also available
+   to operators.
+
+   Clients which have automatic reconnect algorithms effectively make
+   this command useless since the disconnection is only brief.  It does
+   however break the flow of data and can be used to stop large amounts
+   of being abused, any user may elect to receive KILL messages
+   generated for others to keep an 'eye' on would be trouble spots.
+
+   In an arena where nicknames are required to be globally unique at all
+   times, KILL messages are sent whenever 'duplicates' are detected
+   (that is an attempt to register two users with the same nickname) in
+   the hope that both of them will disappear and only 1 reappear.
+
+   The comment given must reflect the actual reason for the KILL.  For
+   server-generated KILLs it usually is made up of details concerning
+   the origins of the two conflicting nicknames.  For users it is left
+   up to them to provide an adequate reason to satisfy others who see
+   it.  To prevent/discourage fake KILLs from being generated to hide
+   the identify of the KILLer, the comment also shows a 'kill-path'
+   which is updated by each server it passes through, each prepending
+   its name to the path.
+
+   Numeric Replies:
+
+           ERR_NOPRIVILEGES                ERR_NEEDMOREPARAMS
+           ERR_NOSUCHNICK                  ERR_CANTKILLSERVER
+
+
+   KILL David (csd.bu.edu <- tolsun.oulu.fi)
+                                   ; Nickname collision between csd.bu.edu
+                                   and tolson.oulu.fi
+
+
+   NOTE:
+   It is recommended that only Operators be allowed to kill other users
+   with KILL message.  In an ideal world not even operators would need
+   to do this and it would be left to servers to deal with.
+
+
+
+
+
+Oikarinen & Reed                                               [Page 36]
+\f
+RFC 1459              Internet Relay Chat Protocol              May 1993
+
+
+4.6.2 Ping message
+
+      Command: PING
+   Parameters: <server1> [<server2>]
+
+   The PING message is used to test the presence of an active client at
+   the other end of the connection.  A PING message is sent at regular
+   intervals if no other activity detected coming from a connection.  If
+   a connection fails to respond to a PING command within a set amount
+   of time, that connection is closed.
+
+   Any client which receives a PING message must respond to <server1>
+   (server which sent the PING message out) as quickly as possible with
+   an appropriate PONG message to indicate it is still there and alive.
+   Servers should not respond to PING commands but rely on PINGs from
+   the other end of the connection to indicate the connection is alive.
+   If the <server2> parameter is specified, the PING message gets
+   forwarded there.
+
+   Numeric Replies:
+
+           ERR_NOORIGIN                    ERR_NOSUCHSERVER
+
+   Examples:
+
+   PING tolsun.oulu.fi             ; server sending a PING message to
+                                   another server to indicate it is still
+                                   alive.
+
+   PING WiZ                        ; PING message being sent to nick WiZ
+
+4.6.3 Pong message
+
+      Command: PONG
+   Parameters: <daemon> [<daemon2>]
+
+   PONG message is a reply to ping message.  If parameter <daemon2> is
+   given this message must be forwarded to given daemon.  The <daemon>
+   parameter is the name of the daemon who has responded to PING message
+   and generated this message.
+
+   Numeric Replies:
+
+           ERR_NOORIGIN                    ERR_NOSUCHSERVER
+
+   Examples:
+
+   PONG csd.bu.edu tolsun.oulu.fi  ; PONG message from csd.bu.edu to
+
+
+
+Oikarinen & Reed                                               [Page 37]
+\f
+RFC 1459              Internet Relay Chat Protocol              May 1993
+
+
+                                   tolsun.oulu.fi
+
+4.6.4 Error
+
+      Command: ERROR
+   Parameters: <error message>
+
+   The ERROR command is for use by servers when reporting a serious or
+   fatal error to its operators.  It may also be sent from one server to
+   another but must not be accepted from any normal unknown clients.
+
+   An ERROR message is for use for reporting errors which occur with a
+   server-to-server link only.  An ERROR message is sent to the server
+   at the other end (which sends it to all of its connected operators)
+   and to all operators currently connected.  It is not to be passed
+   onto any other servers by a server if it is received from a server.
+
+   When a server sends a received ERROR message to its operators, the
+   message should be encapsulated inside a NOTICE message, indicating
+   that the client was not responsible for the error.
+
+   Numerics:
+
+           None.
+
+   Examples:
+
+   ERROR :Server *.fi already exists; ERROR message to the other server
+                                   which caused this error.
+
+   NOTICE WiZ :ERROR from csd.bu.edu -- Server *.fi already exists
+                                   ; Same ERROR message as above but sent
+                                   to user WiZ on the other server.
+
+5. OPTIONALS
+
+   This section describes OPTIONAL messages.  They are not required in a
+   working server implementation of the protocol described herein.  In
+   the absence of the option, an error reply message must be generated
+   or an unknown command error.  If the message is destined for another
+   server to answer then it must be passed on (elementary parsing
+   required) The allocated numerics for this are listed with the
+   messages below.
+
+5.1 Away
+
+      Command: AWAY
+   Parameters: [message]
+
+
+
+Oikarinen & Reed                                               [Page 38]
+\f
+RFC 1459              Internet Relay Chat Protocol              May 1993
+
+
+   With the AWAY message, clients can set an automatic reply string for
+   any PRIVMSG commands directed at them (not to a channel they are on).
+   The automatic reply is sent by the server to client sending the
+   PRIVMSG command.  The only replying server is the one to which the
+   sending client is connected to.
+
+   The AWAY message is used either with one parameter (to set an AWAY
+   message) or with no parameters (to remove the AWAY message).
+
+   Numeric Replies:
+
+           RPL_UNAWAY                      RPL_NOWAWAY
+
+   Examples:
+
+   AWAY :Gone to lunch.  Back in 5 ; set away message to "Gone to lunch.
+                                   Back in 5".
+
+   :WiZ AWAY                       ; unmark WiZ as being away.
+
+
+5.2 Rehash message
+
+      Command: REHASH
+   Parameters: None
+
+   The rehash message can be used by the operator to force the server to
+   re-read and process its configuration file.
+
+   Numeric Replies:
+
+        RPL_REHASHING                   ERR_NOPRIVILEGES
+
+Examples:
+
+REHASH                          ; message from client with operator
+                                status to server asking it to reread its
+                                configuration file.
+
+5.3 Restart message
+
+      Command: RESTART
+   Parameters: None
+
+   The restart message can only be used by an operator to force a server
+   restart itself.  This message is optional since it may be viewed as a
+   risk to allow arbitrary people to connect to a server as an operator
+   and execute this command, causing (at least) a disruption to service.
+
+
+
+Oikarinen & Reed                                               [Page 39]
+\f
+RFC 1459              Internet Relay Chat Protocol              May 1993
+
+
+   The RESTART command must always be fully processed by the server to
+   which the sending client is connected and not be passed onto other
+   connected servers.
+
+   Numeric Replies:
+
+           ERR_NOPRIVILEGES
+
+   Examples:
+
+   RESTART                         ; no parameters required.
+
+                                   running.
+
+5.5 Users
+
+      Command: USERS
+   Parameters: [<server>]
+
+
+
+Oikarinen & Reed                                               [Page 40]
+\f
+RFC 1459              Internet Relay Chat Protocol              May 1993
+
+
+   The USERS command returns a list of users logged into the server in a
+   similar  format  to  who(1),  rusers(1)  and finger(1).  Some people
+   may disable this command on their server for security related
+   reasons.   If disabled, the correct numeric must be returned to
+   indicate this.
+
+   Numeric Replies:
+
+           ERR_NOSUCHSERVER                ERR_FILEERROR
+           RPL_USERSSTART                  RPL_USERS
+           RPL_NOUSERS                     RPL_ENDOFUSERS
+           ERR_USERSDISABLED
+
+   Disabled Reply:
+
+           ERR_USERSDISABLED
+
+   Examples:
+
+USERS eff.org                   ; request a list of users logged in on
+                                server eff.org
+
+:John USERS tolsun.oulu.fi      ; request from John for a list of users
+                                logged in on server tolsun.oulu.fi
+
+5.6 Operwall message
+
+      Command: WALLOPS
+   Parameters: Text to be sent to all operators currently online
+
+   Sends  a  message  to  all   operators   currently   online.    After
+   implementing  WALLOPS  as  a user command it was found that it was
+   often and commonly abused as a means of sending a message to a lot
+   of  people (much  similar to WALL).  Due to this it is recommended
+   that the current implementation of  WALLOPS  be  used  as  an
+   example  by  allowing  and recognising only servers as the senders of
+   WALLOPS.
+
+   Numeric Replies:
+
+           ERR_NEEDMOREPARAMS
+
+   Examples:
+
+   :csd.bu.edu WALLOPS :Connect '*.uiuc.edu 6667' from Joshua; WALLOPS
+                                   message from csd.bu.edu announcing a
+                                   CONNECT message it received and acted
+                                   upon from Joshua.
+
+
+
+Oikarinen & Reed                                               [Page 41]
+\f
+RFC 1459              Internet Relay Chat Protocol              May 1993
+
+
+5.7 Userhost message
+
+      Command: USERHOST
+   Parameters: <nickname>{<space><nickname>}
+
+   The USERHOST command takes a list of up to 5 nicknames, each
+   separated by a space character and returns a list of information
+   about each nickname that it found.  The returned list has each reply
+   separated by a space.
+
+   Numeric Replies:
+
+           RPL_USERHOST                    ERR_NEEDMOREPARAMS
+
+   Examples:
+
+   USERHOST Wiz Michael Marty p    ;USERHOST request for information on
+                                   nicks "Wiz", "Michael", "Marty" and "p"
+
+5.7.1 Userip message
+
+      Command: USERIP
+   Parameters: <nickname>{<space><nickname>}
+
+   The USERHOST command takes a list of up to 5 nicknames, each
+   separated by a space character and returns a list of information
+   about each nickname that it found.  The returned list has each reply
+   separated by a space.
+
+   Numeric Replies:
+
+           RPL_USERIP                    ERR_NEEDMOREPARAMS
+
+   Examples:
+
+   USERIP Wiz Michael Marty p    ;USERIP request for information on
+                                   nicks "Wiz", "Michael", "Marty" and "p"
+
+5.8 Ison message
+
+      Command: ISON
+   Parameters: <nickname>{<space><nickname>}
+
+   The ISON command was implemented to provide  a  quick  and  efficient
+   means  to get a response about whether a given nickname was currently
+   on IRC. ISON only takes one (1) parameter: a space-separated list of
+   nicks.  For  each  nickname in the list that is present, the server
+   adds that to its reply string.  Thus the reply string may return
+   empty (none  of  the given  nicks are present), an exact copy of the
+   parameter string (all of them present) or as any other subset of the
+   set of nicks  given  in  the parameter.  The only limit on the number
+   of nicks that may be checked is that the combined length must not be
+   too large as to cause the server to chop it off so it fits in 512
+   characters.
+
+   ISON is only be processed by the server local to the client sending
+   the command and thus not passed onto other servers for further
+   processing.
+
+   Numeric Replies:
+
+           RPL_ISON                ERR_NEEDMOREPARAMS
+
+   Examples:
+
+   ISON phone trillian WiZ jarlek Avalon Angel Monstah
+                                   ; Sample ISON request for 7 nicks.
+
+
+
+Oikarinen & Reed                                               [Page 42]
+\f
+RFC 1459              Internet Relay Chat Protocol              May 1993
+
+
+6. REPLIES
+
+   The following is a list of numeric replies which are generated in
+   response to the commands given above.  Each numeric is given with its
+   number, name and reply string.
+
+6.1 Error Replies.
+
+        401     ERR_NOSUCHNICK
+                        "<nickname> :No such nick/channel"
+
+                - Used to indicate the nickname parameter supplied to a
+                  command is currently unused.
+
+        402     ERR_NOSUCHSERVER
+                        "<server name> :No such server"
+
+                - Used to indicate the server name given currently
+                  doesn't exist.
+
+        403     ERR_NOSUCHCHANNEL
+                        "<channel name> :No such channel"
+
+                - Used to indicate the given channel name is invalid.
+
+        404     ERR_CANNOTSENDTOCHAN
+                        "<channel name> :Cannot send to channel"
+
+                - Sent to a user who is either (a) not on a channel
+                  which is mode +n or (b) not a chanop (or mode +v) on
+                  a channel which has mode +m set and is trying to send
+                  a PRIVMSG message to that channel.
+
+        405     ERR_TOOMANYCHANNELS
+                        "<channel name> :You have joined too many \
+                         channels"
+                - Sent to a user when they have joined the maximum
+                  number of allowed channels and they try to join
+                  another channel.
+
+        406     ERR_WASNOSUCHNICK
+                        "<nickname> :There was no such nickname"
+
+                - Returned by WHOWAS to indicate there is no history
+                  information for that nickname.
+
+        407     ERR_TOOMANYTARGETS
+                        "<target> :Duplicate recipients. No message \
+
+
+
+Oikarinen & Reed                                               [Page 43]
+\f
+RFC 1459              Internet Relay Chat Protocol              May 1993
+
+
+                         delivered"
+
+                - Returned to a client which is attempting to send a
+                  PRIVMSG/NOTICE using the user@host destination format
+                  and for a user@host which has several occurrences.
+
+        409     ERR_NOORIGIN
+                        ":No origin specified"
+
+                - PING or PONG message missing the originator parameter
+                  which is required since these commands must work
+                  without valid prefixes.
+
+        411     ERR_NORECIPIENT
+                        ":No recipient given (<command>)"
+        412     ERR_NOTEXTTOSEND
+                        ":No text to send"
+        413     ERR_NOTOPLEVEL
+                        "<mask> :No toplevel domain specified"
+        414     ERR_WILDTOPLEVEL
+                        "<mask> :Wildcard in toplevel domain"
+
+                - 412 - 414 are returned by PRIVMSG to indicate that
+                  the message wasn't delivered for some reason.
+                  ERR_NOTOPLEVEL and ERR_WILDTOPLEVEL are errors that
+                  are returned when an invalid use of
+                  "PRIVMSG $<server>" or "PRIVMSG #<host>" is attempted.
+
+        421     ERR_UNKNOWNCOMMAND
+                        "<command> :Unknown command"
+
+                - Returned to a registered client to indicate that the
+                  command sent is unknown by the server.
+
+        422     ERR_NOMOTD
+                        ":MOTD File is missing"
+
+                - Server's MOTD file could not be opened by the server.
+
+        423     ERR_NOADMININFO
+                        "<server> :No administrative info available"
+
+                - Returned by a server in response to an ADMIN message
+                  when there is an error in finding the appropriate
+                  information.
+
+        424     ERR_FILEERROR
+                ":File error doing <file op> on <file>"
+
+
+
+Oikarinen & Reed                                               [Page 44]
+\f
+RFC 1459              Internet Relay Chat Protocol              May 1993
+
+
+                - Generic error message used to report a failed file
+                  operation during the processing of a message.
+
+        431     ERR_NONICKNAMEGIVEN
+                        ":No nickname given"
+
+                - Returned when a nickname parameter expected for a
+                  command and isn't found.
+
+        432     ERR_ERRONEUSNICKNAME
+                        "<nick> :Erroneus nickname"
+
+                - Returned after receiving a NICK message which contains
+                  characters which do not fall in the defined set.  See
+                  section x.x.x for details on valid nicknames.
+
+        433     ERR_NICKNAMEINUSE
+                        "<nick> :Nickname is already in use"
+
+                - Returned when a NICK message is processed that results
+                  in an attempt to change to a currently existing
+                  nickname.
+
+        436     ERR_NICKCOLLISION
+                        "<nick> :Nickname collision KILL"
+
+                - Returned by a server to a client when it detects a
+                  nickname collision (registered of a NICK that
+                  already exists by another server).
+
+        441     ERR_USERNOTINCHANNEL
+                        "<nick> <channel> :They aren't on that channel"
+
+                - Returned by the server to indicate that the target
+                  user of the command is not on the given channel.
+
+        442     ERR_NOTONCHANNEL
+                        "<channel> :You're not on that channel"
+
+                - Returned by the server whenever a client tries to
+                  perform a channel effecting command for which the
+                  client isn't a member.
+
+        443     ERR_USERONCHANNEL
+                        "<user> <channel> :is already on channel"
+
+                - Returned when a client tries to invite a user to a
+                  channel they are already on.
+
+
+
+Oikarinen & Reed                                               [Page 45]
+\f
+RFC 1459              Internet Relay Chat Protocol              May 1993
+
+
+        444     ERR_NOLOGIN
+                        "<user> :User not logged in"
+
+                - Returned by the summon after a SUMMON command for a
+                  user was unable to be performed since they were not
+                  logged in.
+
+        445     ERR_SUMMONDISABLED
+                        ":SUMMON has been disabled"
+
+                - Returned as a response to the SUMMON command.  Must be
+                  returned by any server which does not implement it.
+
+        446     ERR_USERSDISABLED
+                        ":USERS has been disabled"
+
+                - Returned as a response to the USERS command.  Must be
+                  returned by any server which does not implement it.
+
+        451     ERR_NOTREGISTERED
+                        ":You have not registered"
+
+                - Returned by the server to indicate that the client
+                  must be registered before the server will allow it
+                  to be parsed in detail.
+
+        461     ERR_NEEDMOREPARAMS
+                        "<command> :Not enough parameters"
+
+                - Returned by the server by numerous commands to
+                  indicate to the client that it didn't supply enough
+                  parameters.
+
+        462     ERR_ALREADYREGISTRED
+                        ":You may not reregister"
+
+                - Returned by the server to any link which tries to
+                  change part of the registered details (such as
+                  password or user details from second USER message).
+
+
+        463     ERR_NOPERMFORHOST
+                        ":Your host isn't among the privileged"
+
+                - Returned to a client which attempts to register with
+                  a server which does not been setup to allow
+                  connections from the host the attempted connection
+                  is tried.
+
+
+
+Oikarinen & Reed                                               [Page 46]
+\f
+RFC 1459              Internet Relay Chat Protocol              May 1993
+
+
+        464     ERR_PASSWDMISMATCH
+                        ":Password incorrect"
+
+                - Returned to indicate a failed attempt at registering
+                  a connection for which a password was required and
+                  was either not given or incorrect.
+
+        465     ERR_YOUREBANNEDCREEP
+                        ":You are banned from this server"
+
+                - Returned after an attempt to connect and register
+                  yourself with a server which has been setup to
+                  explicitly deny connections to you.
+
+        467     ERR_KEYSET
+                        "<channel> :Channel key already set"
+        471     ERR_CHANNELISFULL
+                        "<channel> :Cannot join channel (+l)"
+        472     ERR_UNKNOWNMODE
+                        "<char> :is unknown mode char to me"
+        473     ERR_INVITEONLYCHAN
+                        "<channel> :Cannot join channel (+i)"
+        474     ERR_BANNEDFROMCHAN
+                        "<channel> :Cannot join channel (+b)"
+        475     ERR_BADCHANNELKEY
+                        "<channel> :Cannot join channel (+k)"
+        481     ERR_NOPRIVILEGES
+                        ":Permission Denied- You're not an IRC operator"
+
+                - Any command requiring operator privileges to operate
+                  must return this error to indicate the attempt was
+                  unsuccessful.
+
+        482     ERR_CHANOPRIVSNEEDED
+                        "<channel> :You're not channel operator"
+
+                - Any command requiring 'chanop' privileges (such as
+                  MODE messages) must return this error if the client
+                  making the attempt is not a chanop on the specified
+                  channel.
+
+        483     ERR_CANTKILLSERVER
+                        ":You cant kill a server!"
+
+                - Any attempts to use the KILL command on a server
+                  are to be refused and this error returned directly
+                  to the client.
+
+
+
+
+Oikarinen & Reed                                               [Page 47]
+\f
+RFC 1459              Internet Relay Chat Protocol              May 1993
+
+
+        491     ERR_NOOPERHOST
+                        ":No O-lines for your host"
+
+                - If a client sends an OPER message and the server has
+                  not been configured to allow connections from the
+                  client's host as an operator, this error must be
+                  returned.
+
+        501     ERR_UMODEUNKNOWNFLAG
+                        ":Unknown MODE flag"
+
+                - Returned by the server to indicate that a MODE
+                  message was sent with a nickname parameter and that
+                  the a mode flag sent was not recognized.
+
+        502     ERR_USERSDONTMATCH
+                        ":Cant change mode for other users"
+
+                - Error sent to any user trying to view or change the
+                  user mode for a user other than themselves.
+
+6.2 Command responses.
+
+        300     RPL_NONE
+                        Dummy reply number. Not used.
+
+        302     RPL_USERHOST
+                        ":[<reply>{<space><reply>}]"
+
+                - Reply format used by USERHOST to list replies to
+                  the query list.  The reply string is composed as
+                  follows:
+
+                  <reply> ::= <nick>['*'] '=' <'+'|'-'><hostname>
+
+                  The '*' indicates whether the client has registered
+                  as an Operator.  The '-' or '+' characters represent
+                  whether the client has set an AWAY message or not
+                  respectively.
+
+        303     RPL_ISON
+                        ":[<nick> {<space><nick>}]"
+
+                - Reply format used by ISON to list replies to the
+                  query list.
+
+        301     RPL_AWAY
+                        "<nick> :<away message>"
+
+
+
+Oikarinen & Reed                                               [Page 48]
+\f
+RFC 1459              Internet Relay Chat Protocol              May 1993
+
+
+        305     RPL_UNAWAY
+                        ":You are no longer marked as being away"
+        306     RPL_NOWAWAY
+                        ":You have been marked as being away"
+
+                - These replies are used with the AWAY command (if
+                  allowed).  RPL_AWAY is sent to any client sending a
+                  PRIVMSG to a client which is away.  RPL_AWAY is only
+                  sent by the server to which the client is connected.
+                  Replies RPL_UNAWAY and RPL_NOWAWAY are sent when the
+                  client removes and sets an AWAY message.
+
+        311     RPL_WHOISUSER
+                        "<nick> <user> <host> * :<real name>"
+        312     RPL_WHOISSERVER
+                        "<nick> <server> :<server info>"
+        313     RPL_WHOISOPERATOR
+                        "<nick> :is an IRC operator"
+        317     RPL_WHOISIDLE
+                        "<nick> <integer> :seconds idle"
+        318     RPL_ENDOFWHOIS
+                        "<nick> :End of /WHOIS list"
+        319     RPL_WHOISCHANNELS
+                        "<nick> :{[@|+]<channel><space>}"
+
+                - Replies 311 - 313, 317 - 319 are all replies
+                  generated in response to a WHOIS message.  Given that
+                  there are enough parameters present, the answering
+                  server must either formulate a reply out of the above
+                  numerics (if the query nick is found) or return an
+                  error reply.  The '*' in RPL_WHOISUSER is there as
+                  the literal character and not as a wild card.  For
+                  each reply set, only RPL_WHOISCHANNELS may appear
+                  more than once (for long lists of channel names).
+                  The '@' and '+' characters next to the channel name
+                  indicate whether a client is a channel operator or
+                  has been granted permission to speak on a moderated
+                  channel.  The RPL_ENDOFWHOIS reply is used to mark
+                  the end of processing a WHOIS message.
+
+        314     RPL_WHOWASUSER
+                        "<nick> <user> <host> * :<real name>"
+        369     RPL_ENDOFWHOWAS
+                        "<nick> :End of WHOWAS"
+
+                - When replying to a WHOWAS message, a server must use
+                  the replies RPL_WHOWASUSER, RPL_WHOISSERVER or
+                  ERR_WASNOSUCHNICK for each nickname in the presented
+
+
+
+Oikarinen & Reed                                               [Page 49]
+\f
+RFC 1459              Internet Relay Chat Protocol              May 1993
+
+
+                  list.  At the end of all reply batches, there must
+                  be RPL_ENDOFWHOWAS (even if there was only one reply
+                  and it was an error).
+
+        321     RPL_LISTSTART
+                        "Channel :Users  Name"
+        322     RPL_LIST
+                        "<channel> <# visible> :<topic>"
+        323     RPL_LISTEND
+                        ":End of /LIST"
+
+                - Replies RPL_LISTSTART, RPL_LIST, RPL_LISTEND mark
+                  the start, actual replies with data and end of the
+                  server's response to a LIST command.  If there are
+                  no channels available to return, only the start
+                  and end reply must be sent.
+
+        324     RPL_CHANNELMODEIS
+                        "<channel> <mode> <mode params>"
+
+        331     RPL_NOTOPIC
+                        "<channel> :No topic is set"
+        332     RPL_TOPIC
+                        "<channel> :<topic>"
+
+                - When sending a TOPIC message to determine the
+                  channel topic, one of two replies is sent.  If
+                  the topic is set, RPL_TOPIC is sent back else
+                  RPL_NOTOPIC.
+
+        341     RPL_INVITING
+                        "<channel> <nick>"
+
+                - Returned by the server to indicate that the
+                  attempted INVITE message was successful and is
+                  being passed onto the end client.
+
+        342     RPL_SUMMONING
+                        "<user> :Summoning user to IRC"
+
+                - Returned by a server answering a SUMMON message to
+                  indicate that it is summoning that user.
+
+        351     RPL_VERSION
+                        "<version>.<debuglevel> <server> :<comments>"
+
+                - Reply by the server showing its version details.
+                  The <version> is the version of the software being
+
+
+
+Oikarinen & Reed                                               [Page 50]
+\f
+RFC 1459              Internet Relay Chat Protocol              May 1993
+
+
+                  used (including any patchlevel revisions) and the
+                  <debuglevel> is used to indicate if the server is
+                  running in "debug mode".
+
+                  The "comments" field may contain any comments about
+                  the version or further version details.
+
+        352     RPL_WHOREPLY
+                        "<channel> <user> <host> <server> <nick> \
+                         <H|G>[*][@|+] :<hopcount> <real name>"
+        315     RPL_ENDOFWHO
+                        "<name> :End of /WHO list"
+
+                - The RPL_WHOREPLY and RPL_ENDOFWHO pair are used
+                  to answer a WHO message.  The RPL_WHOREPLY is only
+                  sent if there is an appropriate match to the WHO
+                  query.  If there is a list of parameters supplied
+                  with a WHO message, a RPL_ENDOFWHO must be sent
+                  after processing each list item with <name> being
+                  the item.
+
+        353     RPL_NAMREPLY
+                        "<channel> :[[@|+]<nick> [[@|+]<nick> [...]]]"
+        366     RPL_ENDOFNAMES
+                        "<channel> :End of /NAMES list"
+
+                - To reply to a NAMES message, a reply pair consisting
+                  of RPL_NAMREPLY and RPL_ENDOFNAMES is sent by the
+                  server back to the client.  If there is no channel
+                  found as in the query, then only RPL_ENDOFNAMES is
+                  returned.  The exception to this is when a NAMES
+                  message is sent with no parameters and all visible
+                  channels and contents are sent back in a series of
+                  RPL_NAMEREPLY messages with a RPL_ENDOFNAMES to mark
+                  the end.
+
+        364     RPL_LINKS
+                        "<mask> <server> :<hopcount> <server info>"
+        365     RPL_ENDOFLINKS
+                        "<mask> :End of /LINKS list"
+
+                - In replying to the LINKS message, a server must send
+                  replies back using the RPL_LINKS numeric and mark the
+                  end of the list using an RPL_ENDOFLINKS reply.
+
+        367     RPL_BANLIST
+                        "<channel> <banid>"
+        368     RPL_ENDOFBANLIST
+
+
+
+Oikarinen & Reed                                               [Page 51]
+\f
+RFC 1459              Internet Relay Chat Protocol              May 1993
+
+
+                        "<channel> :End of channel ban list"
+
+                - When listing the active 'bans' for a given channel,
+                  a server is required to send the list back using the
+                  RPL_BANLIST and RPL_ENDOFBANLIST messages.  A separate
+                  RPL_BANLIST is sent for each active banid.  After the
+                  banids have been listed (or if none present) a
+                  RPL_ENDOFBANLIST must be sent.
+
+        371     RPL_INFO
+                        ":<string>"
+        374     RPL_ENDOFINFO
+                        ":End of /INFO list"
+
+                - A server responding to an INFO message is required to
+                  send all its 'info' in a series of RPL_INFO messages
+                  with a RPL_ENDOFINFO reply to indicate the end of the
+                  replies.
+
+        375     RPL_MOTDSTART
+                        ":- <server> Message of the day - "
+        372     RPL_MOTD
+                        ":- <text>"
+        376     RPL_ENDOFMOTD
+                        ":End of /MOTD command"
+
+                - When responding to the MOTD message and the MOTD file
+                  is found, the file is displayed line by line, with
+                  each line no longer than 80 characters, using
+                  RPL_MOTD format replies.  These should be surrounded
+                  by a RPL_MOTDSTART (before the RPL_MOTDs) and an
+                  RPL_ENDOFMOTD (after).
+
+        381     RPL_YOUREOPER
+                        ":You are now an IRC operator"
+
+                - RPL_YOUREOPER is sent back to a client which has
+                  just successfully issued an OPER message and gained
+                  operator status.
+
+        382     RPL_REHASHING
+                        "<config file> :Rehashing"
+
+                - If the REHASH option is used and an operator sends
+                  a REHASH message, an RPL_REHASHING is sent back to
+                  the operator.
+
+        391     RPL_TIME
+
+
+
+Oikarinen & Reed                                               [Page 52]
+\f
+RFC 1459              Internet Relay Chat Protocol              May 1993
+
+
+                        "<server> :<string showing server's local time>"
+
+                - When replying to the TIME message, a server must send
+                  the reply using the RPL_TIME format above.  The string
+                  showing the time need only contain the correct day and
+                  time there.  There is no further requirement for the
+                  time string.
+
+        392     RPL_USERSSTART
+                        ":UserID   Terminal  Host"
+        393     RPL_USERS
+                        ":%-8s %-9s %-8s"
+        394     RPL_ENDOFUSERS
+                        ":End of users"
+        395     RPL_NOUSERS
+                        ":Nobody logged in"
+
+                - If the USERS message is handled by a server, the
+                  replies RPL_USERSTART, RPL_USERS, RPL_ENDOFUSERS and
+                  RPL_NOUSERS are used.  RPL_USERSSTART must be sent
+                  first, following by either a sequence of RPL_USERS
+                  or a single RPL_NOUSER.  Following this is
+                  RPL_ENDOFUSERS.
+
+        200     RPL_TRACELINK
+                        "Link <version & debug level> <destination> \
+                         <next server>"
+        201     RPL_TRACECONNECTING
+                        "Try. <class> <server>"
+        202     RPL_TRACEHANDSHAKE
+                        "H.S. <class> <server>"
+        203     RPL_TRACEUNKNOWN
+                        "???? <class> [<client IP address in dot form>]"
+        204     RPL_TRACEOPERATOR
+                        "Oper <class> <nick>"
+        205     RPL_TRACEUSER
+                        "User <class> <nick>"
+        206     RPL_TRACESERVER
+                        "Serv <class> <int>S <int>C <server> \
+                         <nick!user|*!*>@<host|server>"
+        208     RPL_TRACENEWTYPE
+                        "<newtype> 0 <client name>"
+        261     RPL_TRACELOG
+                        "File <logfile> <debug level>"
+
+                - The RPL_TRACE* are all returned by the server in
+                  response to the TRACE message.  How many are
+                  returned is dependent on the the TRACE message and
+
+
+
+Oikarinen & Reed                                               [Page 53]
+\f
+RFC 1459              Internet Relay Chat Protocol              May 1993
+
+
+                  whether it was sent by an operator or not.  There
+                  is no predefined order for which occurs first.
+                  Replies RPL_TRACEUNKNOWN, RPL_TRACECONNECTING and
+                  RPL_TRACEHANDSHAKE are all used for connections
+                  which have not been fully established and are either
+                  unknown, still attempting to connect or in the
+                  process of completing the 'server handshake'.
+                  RPL_TRACELINK is sent by any server which handles
+                  a TRACE message and has to pass it on to another
+                  server.  The list of RPL_TRACELINKs sent in
+                  response to a TRACE command traversing the IRC
+                  network should reflect the actual connectivity of
+                  the servers themselves along that path.
+                  RPL_TRACENEWTYPE is to be used for any connection
+                  which does not fit in the other categories but is
+                  being displayed anyway.
+
+        211     RPL_STATSLINKINFO
+                        "<linkname> <sendq> <sent messages> \
+                         <sent bytes> <received messages> \
+                         <received bytes> <time open>"
+        212     RPL_STATSCOMMANDS
+                        "<command> <count>"
+        213     RPL_STATSCLINE
+                        "C <host> * <name> <port> <class>"
+        214     RPL_STATSNLINE
+                        "N <host> * <name> <port> <class>"
+        215     RPL_STATSILINE
+                        "I <host> * <host> <port> <class>"
+        216     RPL_STATSKLINE
+                        "K <host> * <username> <port> <class>"
+        218     RPL_STATSYLINE
+                        "Y <class> <ping frequency> <connect \
+                         frequency> <max sendq>"
+        219     RPL_ENDOFSTATS
+                        "<stats letter> :End of /STATS report"
+        241     RPL_STATSLLINE
+                        "L <hostmask> * <servername> <maxdepth>"
+        242     RPL_STATSUPTIME
+                        ":Server Up %d days %d:%02d:%02d"
+        243     RPL_STATSOLINE
+                        "O <hostmask> * <name>"
+        244     RPL_STATSHLINE
+                        "H <hostmask> * <servername>"
+
+        221     RPL_UMODEIS
+                        "<user mode string>"
+
+
+
+
+Oikarinen & Reed                                               [Page 54]
+\f
+RFC 1459              Internet Relay Chat Protocol              May 1993
+
+
+                        - To answer a query about a client's own mode,
+                          RPL_UMODEIS is sent back.
+
+        251     RPL_LUSERCLIENT
+                        ":There are <integer> users and <integer> \
+                         invisible on <integer> servers"
+        252     RPL_LUSEROP
+                        "<integer> :operator(s) online"
+        253     RPL_LUSERUNKNOWN
+                        "<integer> :unknown connection(s)"
+        254     RPL_LUSERCHANNELS
+                        "<integer> :channels formed"
+        255     RPL_LUSERME
+                        ":I have <integer> clients and <integer> \
+                          servers"
+
+                        - In processing an LUSERS message, the server
+                          sends a set of replies from RPL_LUSERCLIENT,
+                          RPL_LUSEROP, RPL_USERUNKNOWN,
+                          RPL_LUSERCHANNELS and RPL_LUSERME.  When
+                          replying, a server must send back
+                          RPL_LUSERCLIENT and RPL_LUSERME.  The other
+                          replies are only sent back if a non-zero count
+                          is found for them.
+
+        256     RPL_ADMINME
+                        "<server> :Administrative info"
+        257     RPL_ADMINLOC1
+                        ":<admin info>"
+        258     RPL_ADMINLOC2
+                        ":<admin info>"
+        259     RPL_ADMINEMAIL
+                        ":<admin info>"
+
+                        - When replying to an ADMIN message, a server
+                          is expected to use replies RLP_ADMINME
+                          through to RPL_ADMINEMAIL and provide a text
+                          message with each.  For RPL_ADMINLOC1 a
+                          description of what city, state and country
+                          the server is in is expected, followed by
+                          details of the university and department
+                          (RPL_ADMINLOC2) and finally the administrative
+                          contact for the server (an email address here
+                          is required) in RPL_ADMINEMAIL.
+
+
+
+
+
+
+
+Oikarinen & Reed                                               [Page 55]
+\f
+RFC 1459              Internet Relay Chat Protocol              May 1993
+
+
+6.3 Reserved numerics.
+
+   These numerics are not described above since they fall into one of
+   the following categories:
+
+        1. no longer in use;
+
+        2. reserved for future planned use;
+
+        3. in current use but are part of a non-generic 'feature' of
+           the current IRC server.
+
+        209     RPL_TRACECLASS          217     RPL_STATSQLINE
+        231     RPL_SERVICEINFO         232     RPL_ENDOFSERVICES
+        233     RPL_SERVICE             234     RPL_SERVLIST
+        235     RPL_SERVLISTEND
+        316     RPL_WHOISCHANOP         361     RPL_KILLDONE
+        362     RPL_CLOSING             363     RPL_CLOSEEND
+        373     RPL_INFOSTART           384     RPL_MYPORTIS
+        466     ERR_YOUWILLBEBANNED     476     ERR_BADCHANMASK
+        492     ERR_NOSERVICEHOST
+
+7. Client and server authentication
+
+   Clients and servers are both subject to the same level of
+   authentication.  For both, an IP number to hostname lookup (and
+   reverse check on this) is performed for all connections made to the
+   server.  Both connections are then subject to a password check (if
+   there is a password set for that connection).  These checks are
+   possible on all connections although the password check is only
+   commonly used with servers.
+
+   An additional check that is becoming of more and more common is that
+   of the username responsible for making the connection.  Finding the
+   username of the other end of the connection typically involves
+   connecting to an authentication server such as IDENT as described in
+   RFC 1413.
+
+   Given that without passwords it is not easy to reliably determine who
+   is on the other end of a network connection, use of passwords is
+   strongly recommended on inter-server connections in addition to any
+   other measures such as using an ident server.
+
+8. Current implementations
+
+   The only current implementation of this protocol is the IRC server,
+   version 2.8. Earlier versions may implement some or all of the
+   commands described by this document with NOTICE messages replacing
+
+
+
+Oikarinen & Reed                                               [Page 56]
+\f
+RFC 1459              Internet Relay Chat Protocol              May 1993
+
+
+   many of the numeric replies.  Unfortunately, due to backward
+   compatibility requirements, the implementation of some parts of this
+   document varies with what is laid out.  On notable difference is:
+
+        * recognition that any LF or CR anywhere in a message marks the
+          end of that message (instead of requiring CR-LF);
+
+   The rest of this section deals with issues that are mostly of
+   importance to those who wish to implement a server but some parts
+   also apply directly to clients as well.
+
+8.1 Network protocol: TCP - why it is best used here.
+
+   IRC has been implemented on top of TCP since TCP supplies a reliable
+   network protocol which is well suited to this scale of conferencing.
+   The use of multicast IP is an alternative, but it is not widely
+   available or supported at the present time.
+
+8.1.1 Support of Unix sockets
+
+   Given that Unix domain sockets allow listen/connect operations, the
+   current implementation can be configured to listen and accept both
+   client and server connections on a Unix domain socket.  These are
+   recognized as sockets where the hostname starts with a '/'.
+
+   When providing any information about the connections on a Unix domain
+   socket, the server is required to supplant the actual hostname in
+   place of the pathname unless the actual socket name is being asked
+   for.
+
+8.2 Command Parsing
+
+   To provide useful 'non-buffered' network IO for clients and servers,
+   each connection is given its own private 'input buffer' in which the
+   results of the most recent read and parsing are kept.  A buffer size
+   of 512 bytes is used so as to hold 1 full message, although, this
+   will usually hold several commands.  The private buffer is parsed
+   after every read operation for valid messages.  When dealing with
+   multiple messages from one client in the buffer, care should be taken
+   in case one happens to cause the client to be 'removed'.
+
+8.3 Message delivery
+
+   It is common to find network links saturated or hosts to which you
+   are sending data unable to send data.  Although Unix typically
+   handles this through the TCP window and internal buffers, the server
+   often has large amounts of data to send (especially when a new
+   server-server link forms) and the small buffers provided in the
+
+
+
+Oikarinen & Reed                                               [Page 57]
+\f
+RFC 1459              Internet Relay Chat Protocol              May 1993
+
+
+   kernel are not enough for the outgoing queue.  To alleviate this
+   problem, a "send queue" is used as a FIFO queue for data to be sent.
+   A typical "send queue" may grow to 200 Kbytes on a large IRC network
+   with a slow network connection when a new server connects.
+
+   When polling its connections, a server will first read and parse all
+   incoming data, queuing any data to be sent out. When all available
+   input is processed, the queued data is sent. This reduces the number
+   of write() system calls and helps TCP make bigger packets.
+
+8.4 Connection 'Liveness'
+
+   To detect when a connection has died or become unresponsive, the
+   server must ping each of its connections that it doesn't get a
+   response from in a given amount of time.
+
+   If a connection doesn't respond in time, its connection is closed
+   using the appropriate procedures.  A connection is also dropped if
+   its sendq grows beyond the maximum allowed, because it is better to
+   close a slow connection than have a server process block.
+
+8.5 Establishing a server to client connection
+
+   Upon connecting to an IRC server, a client is sent the MOTD (if
+   present) as well as the current user/server count (as per the LUSER
+   command).  The server is also required to give an unambiguous message
+   to the client which states its name and version as well as any other
+   introductory messages which may be deemed appropriate.
+
+   After dealing with this, the server must then send out the new user's
+   nickname and other information as supplied by itself (USER command)
+   and as the server could discover (from DNS/authentication servers).
+   The server must send this information out with NICK first followed by
+   USER.
+
+8.6 Establishing a server-server connection.
+
+   The process of establishing of a server-to-server connection is
+   fraught with danger since there are many possible areas where
+   problems can occur - the least of which are race conditions.
+
+   After a server has received a connection following by a PASS/SERVER
+   pair which were recognised as being valid, the server should then
+   reply with its own PASS/SERVER information for that connection as
+   well as all of the other state information it knows about as
+   described below.
+
+   When the initiating server receives a PASS/SERVER pair, it too then
+
+
+
+Oikarinen & Reed                                               [Page 58]
+\f
+RFC 1459              Internet Relay Chat Protocol              May 1993
+
+
+   checks that the server responding is authenticated properly before
+   accepting the connection to be that server.
+
+8.6.1 Server exchange of state information when connecting
+
+   The order of state information being exchanged between servers is
+   essential.  The required order is as follows:
+
+        * all known other servers;
+
+        * all known user information;
+
+        * all known channel information.
+
+   Information regarding servers is sent via extra SERVER messages, user
+   information with NICK/USER/MODE/JOIN messages and channels with MODE
+   messages.
+
+   NOTE: channel topics are *NOT* exchanged here because the TOPIC
+   command overwrites any old topic information, so at best, the two
+   sides of the connection would exchange topics.
+
+   By passing the state information about servers first, any collisions
+   with servers that already exist occur before nickname collisions due
+   to a second server introducing a particular nickname.  Due to the IRC
+   network only being able to exist as an acyclic graph, it may be
+   possible that the network has already reconnected in another
+   location, the place where the collision occurs indicating where the
+   net needs to split.
+
+8.7 Terminating server-client connections
+
+   When a client connection closes, a QUIT message is generated on
+   behalf of the client by the server to which the client connected.  No
+   other message is to be generated or used.
+
+8.8 Terminating server-server connections
+
+   If a server-server connection is closed, either via a remotely
+   generated SQUIT or 'natural' causes, the rest of the connected IRC
+   network must have its information updated with by the server which
+   detected the closure.  The server then sends a list of SQUITs (one
+   for each server behind that connection) and a list of QUITs (again,
+   one for each client behind that connection).
+
+
+
+
+
+
+
+Oikarinen & Reed                                               [Page 59]
+\f
+RFC 1459              Internet Relay Chat Protocol              May 1993
+
+
+8.9 Tracking nickname changes
+
+   All IRC servers are required to keep a history of recent nickname
+   changes.  This is required to allow the server to have a chance of
+   keeping in touch of things when nick-change race conditions occur
+   with commands which manipulate them.  Commands which must trace nick
+   changes are:
+
+        * KILL (the nick being killed)
+
+        * MODE (+/- o,v)
+
+        * KICK (the nick being kicked)
+
+   No other commands are to have nick changes checked for.
+
+   In the above cases, the server is required to first check for the
+   existence of the nickname, then check its history to see who that
+   nick currently belongs to (if anyone!).  This reduces the chances of
+   race conditions but they can still occur with the server ending up
+   affecting the wrong client.  When performing a change trace for an
+   above command it is recommended that a time range be given and
+   entries which are too old ignored.
+
+   For a reasonable history, a server should be able to keep previous
+   nickname for every client it knows about if they all decided to
+   change.  This size is limited by other factors (such as memory, etc).
+
+8.10 Flood control of clients
+
+   With a large network of interconnected IRC servers, it is quite easy
+   for any single client attached to the network to supply a continuous
+   stream of messages that result in not only flooding the network, but
+   also degrading the level of service provided to others.  Rather than
+   require every 'victim' to be provide their own protection, flood
+   protection was written into the server and is applied to all clients
+   except services.  The current algorithm is as follows:
+
+        * check to see if client's `message timer' is less than
+          current time (set to be equal if it is);
+
+        * read any data present from the client;
+
+        * while the timer is less than ten seconds ahead of the current
+          time, parse any present messages and penalize the client by
+          2 seconds for each message;
+
+   which in essence means that the client may send 1 message every 2
+
+
+
+Oikarinen & Reed                                               [Page 60]
+\f
+RFC 1459              Internet Relay Chat Protocol              May 1993
+
+
+   seconds without being adversely affected.
+
+8.11 Non-blocking lookups
+
+   In a real-time environment, it is essential that a server process do
+   as little waiting as possible so that all the clients are serviced
+   fairly.  Obviously this requires non-blocking IO on all network
+   read/write operations.  For normal server connections, this was not
+   difficult, but there are other support operations that may cause the
+   server to block (such as disk reads).  Where possible, such activity
+   should be performed with a short timeout.
+
+8.11.1 Hostname (DNS) lookups
+
+   Using the standard resolver libraries from Berkeley and others has
+   meant large delays in some cases where replies have timed out.  To
+   avoid this, a separate set of DNS routines were written which were
+   setup for non-blocking IO operations and then polled from within the
+   main server IO loop.
+
+8.11.2 Username (Ident) lookups
+
+   Although there are numerous ident libraries for use and inclusion
+   into other programs, these caused problems since they operated in a
+   synchronous manner and resulted in frequent delays.  Again the
+   solution was to write a set of routines which would cooperate with
+   the rest of the server and work using non-blocking IO.
+
+8.12 Configuration File
+
+   To provide a flexible way of setting up and running the server, it is
+   recommended that a configuration file be used which contains
+   instructions to the server on the following:
+
+        * which hosts to accept client connections from;
+
+        * which hosts to allow to connect as servers;
+
+        * which hosts to connect to (both actively and
+          passively);
+
+        * information about where the server is (university,
+          city/state, company are examples of this);
+
+        * who is responsible for the server and an email address
+          at which they can be contacted;
+
+        * hostnames and passwords for clients which wish to be given
+
+
+
+Oikarinen & Reed                                               [Page 61]
+\f
+RFC 1459              Internet Relay Chat Protocol              May 1993
+
+
+          access to restricted operator commands.
+
+   In specifying hostnames, both domain names and use of the 'dot'
+   notation (127.0.0.1) should both be accepted.  It must be possible to
+   specify the password to be used/accepted for all outgoing and
+   incoming connections (although the only outgoing connections are
+   those to other servers).
+
+   The above list is the minimum requirement for any server which wishes
+   to make a connection with another server.  Other items which may be
+   of use are:
+
+        * specifying which servers other server may introduce;
+
+        * how deep a server branch is allowed to become;
+
+        * hours during which clients may connect.
+
+8.12.1 Allowing clients to connect
+
+   A server should use some sort of 'access control list' (either in the
+   configuration file or elsewhere) that is read at startup and used to
+   decide what hosts clients may use to connect to it.
+
+   Both 'deny' and 'allow' should be implemented to provide the required
+   flexibility for host access control.
+
+8.12.2 Operators
+
+   The granting of operator privileges to a disruptive person can have
+   dire consequences for the well-being of the IRC net in general due to
+   the powers given to them.  Thus, the acquisition of such powers
+   should not be very easy.  The current setup requires two 'passwords'
+   to be used although one of them is usually easy guessed.  Storage of
+   oper passwords in configuration files is preferable to hard coding
+   them in and should be stored in a crypted format (ie using crypt(3)
+   from Unix) to prevent easy theft.
+
+8.12.3 Allowing servers to connect
+
+   The interconnection of server is not a trivial matter: a bad
+   connection can have a large impact on the usefulness of IRC.  Thus,
+   each server should have a list of servers to which it may connect and
+   which servers may connect to it.  Under no circumstances should a
+   server allow an arbitrary host to connect as a server.  In addition
+   to which servers may and may not connect, the configuration file
+   should also store the password and other characteristics of that
+   link.
+
+
+
+Oikarinen & Reed                                               [Page 62]
+\f
+RFC 1459              Internet Relay Chat Protocol              May 1993
+
+
+8.12.4 Administrivia
+
+   To provide accurate and valid replies to the ADMIN command (see
+   section 4.3.7), the server should find the relevant details in the
+   configuration.
+
+8.13 Channel membership
+
+   The current server allows any registered local user to join upto 10
+   different channels.  There is no limit imposed on non-local users so
+   that the server remains (reasonably) consistant with all others on a
+   channel membership basis
+
+9. Current problems
+
+   There are a number of recognized problems with this protocol, all  of
+   which  hope to be solved sometime in the near future during its
+   rewrite.  Currently, work is underway to find working solutions to
+   these problems.
+
+9.1 Scalability
+
+   It is widely recognized that this protocol does not scale
+   sufficiently well when used in a large arena.  The main problem comes
+   from the requirement that all servers know about all other servers
+   and users and that information regarding them be updated as soon as
+   it changes.  It is also desirable to keep the number of servers low
+   so that the path length between any two points is kept minimal and
+   the spanning tree as strongly branched as possible.
+
+9.2 Labels
+
+   The current IRC protocol has 3 types of labels: the nickname, the
+   channel name and the server name.  Each of the three types has its
+   own domain and no duplicates are allowed inside that domain.
+   Currently, it is possible for users to pick the label for any of the
+   three, resulting in collisions.  It is widely recognized that this
+   needs reworking, with a plan for unique names for channels and nicks
+   that don't collide being desirable as well as a solution allowing a
+   cyclic tree.
+
+9.2.1 Nicknames
+
+   The idea of the nickname on IRC is very convenient for users to use
+   when talking to each other outside of a channel, but there is only a
+   finite nickname space and being what they are, its not uncommon for
+   several people to want to use the same nick.  If a nickname is chosen
+   by two people using this protocol, either one will not succeed or
+
+
+
+Oikarinen & Reed                                               [Page 63]
+\f
+RFC 1459              Internet Relay Chat Protocol              May 1993
+
+
+   both will removed by use of KILL (4.6.1).
+
+9.2.2 Channels
+
+   The current channel layout requires that all servers know about all
+   channels, their inhabitants and properties.  Besides not scaling
+   well, the issue of privacy is also a concern.  A collision of
+   channels is treated as an inclusive event (both people who create the
+   new channel are considered to be members of it) rather than an
+   exclusive one such as used to solve nickname collisions.
+
+9.2.3 Servers
+
+   Although the number of servers is usually small relative to the
+   number of users and channels, they two currently required to be known
+   globally, either each one separately or hidden behind a mask.
+
+9.3 Algorithms
+
+   In some places within the server code, it has not  been  possible  to
+   avoid  N^2  algorithms  such  as  checking  the channel list of a set
+   of clients.
+
+   In current server versions, there are no database consistency checks,
+   each server assumes that a neighbouring server is correct.  This
+   opens the door to large problems if a connecting server is buggy or
+   otherwise tries to introduce contradictions to the existing net.
+
+   Currently, because of the lack of unique internal and global labels,
+   there are a multitude of race conditions that exist.  These race
+   conditions generally arise from the problem of it taking time for
+   messages to traverse and effect the IRC network.  Even by changing to
+   unique labels, there are problems with channel-related commands being
+   disrupted.
+
+10. Current support and availability
+
+           Mailing lists for IRC related discussion:
+                Future protocol: ircd-three-request@eff.org
+                General discussion: operlist-request@eff.org
+
+           Software implemenations
+                cs.bu.edu:/irc
+                nic.funet.fi:/pub/irc
+                coombs.anu.edu.au:/pub/irc
+
+           Newsgroup: alt.irc
+
+
+
+
+Oikarinen & Reed                                               [Page 64]
+\f
+RFC 1459              Internet Relay Chat Protocol              May 1993
+
+
+Security Considerations
+
+   Security issues are discussed in sections 4.1, 4.1.1, 4.1.3, 5.5, and
+   7.
+
+12. Authors' Addresses
+
+   Jarkko Oikarinen
+   Tuirantie 17 as 9
+   90500 OULU
+   FINLAND
+
+   Email: jto@tolsun.oulu.fi
+
+
+   Darren Reed
+   4 Pateman Street
+   Watsonia, Victoria 3087
+   Australia
+
+   Email: avalon@coombs.anu.edu.au
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Oikarinen & Reed                                               [Page 65]
+\f
diff --git a/doc/snomask.html b/doc/snomask.html
new file mode 100644 (file)
index 0000000..8ab35e8
--- /dev/null
@@ -0,0 +1,221 @@
+<html>
+<head>
+<title>SNOMASK - Server Notice Masks</title>
+</head>
+<body bgcolor=#FFFFFF text=#000000 link=#700000 vlink=#404040>
+<center>
+<font face="arial">
+<h2>SNOMASK - Server Notice Masks</h2></font>
+<font face="arial" size="2">
+Written by <a href="mailto:foxxe@trms.com">Ghostwolf</a> 18th June 1997<br>
+Modified with permission by <a href="mailto:loki@undernet.org">loki</a> 12th November 1997
+</center>
+<p><hr width="80%" noshade>
+
+<blockquote>
+This document (hopefully) gives a brief explanation of the use of server
+notice masks new to ircu2.10.00. This mask allows clients to specify which
+types of server notices they will receive when usermode +s. The mask may
+optionally be omitted, and reasonable defaults will be used by the server.
+<p>
+Note: the descriptions here will be best understood by those with knowledge
+of C syntax. We do not attempt to explain either this or hexadecimal values
+in this document, and familiarity with these is assumed of the reader.
+<p>
+Usage:
+</font><kbd><strong>
+/mode &lt;nick&gt; +s [+/-][mask]</kbd></strong>
+<font face="arial" size="2">
+<p>
+<center>
+<table border=0 cellspacing=5 cellpadding=0 width=85%>
+<tr align=center valign=middle>
+<th align=left><font face="arial" size="2">Mask</th>
+<th align=left>&nbsp;</th>
+<th align=left><font face="arial" size="2">Hex value</th>
+<th align=left><font face="arial" size="2">Description</th>
+</tr>
+<tr>
+<td><font face="arial" size="2">1</td>
+<td><font face="arial" size="2">SNO_OLDSNO</td>
+<td><font face="arial" size="2">0x1</td>
+<td><font face="arial" size="2">/* unsorted old messages */</td>
+</tr>
+<tr>
+<td><font face="arial" size="2">2</td>
+<td><font face="arial" size="2">SNO_SERVKILL</td>
+<td><font face="arial" size="2">0x2</td>
+<td><font face="arial" size="2">/* server kills (nick collisions) */</td>
+</tr>
+<tr>
+<td><font face="arial" size="2">4</td>
+<td><font face="arial" size="2">SNO_OPERKILL</td>
+<td><font face="arial" size="2">0x4</td>
+<td><font face="arial" size="2">/* oper kills */</td>
+</tr>
+<tr>
+<td><font face="arial" size="2">8</td>
+<td><font face="arial" size="2">SNO_HACK2</td>
+<td><font face="arial" size="2">0x8</td>
+<td><font face="arial" size="2">/* desyncs */</td>
+</tr>
+<tr>
+<td><font face="arial" size="2">16</td>
+<td><font face="arial" size="2">SNO_HACK3
+<td><font face="arial" size="2">0x10</td>
+<td><font face="arial" size="2">/* temporary desyncs */</td>
+</tr>
+<tr>
+<td><font face="arial" size="2">32</td>
+<td><font face="arial" size="2">SNO_UNAUTH</td>
+<td><font face="arial" size="2">0x20</td>
+<td><font face="arial" size="2">/* unauthorized connections */</td>
+</tr>
+<tr>
+<td><font face="arial" size="2">64</td>
+<td><font face="arial" size="2">SNO_TCPCOMMON</td>
+<td><font face="arial" size="2">0x40</td>
+<td><font face="arial" size="2">/* common TCP or socket errors */</td>
+</tr>
+<tr>
+<td><font face="arial" size="2">128</td>
+<td><font face="arial" size="2">SNO_TOOMANY</td>
+<td><font face="arial" size="2">0x80</td>
+<td><font face="arial" size="2">/* too many connections */</td>
+</tr>
+<tr>
+<td><font face="arial" size="2">256</td>
+<td><font face="arial" size="2">SNO_HACK4</td>
+<td><font face="arial" size="2">0x100</td>
+<td><font face="arial" size="2">/* Uworld actions on channels */</td>
+</tr>
+<tr>
+<td><font face="arial" size="2">512</td>
+<td><font face="arial" size="2">SNO_GLINE</td>
+<td><font face="arial" size="2">0x200</td>
+<td><font face="arial" size="2">/* glines */</td>
+</tr>
+<tr>
+<td><font face="arial" size="2">1024</td>
+<td><font face="arial" size="2">SNO_NETWORK</td>
+<td><font face="arial" size="2">0x400</td>
+<td><font face="arial" size="2">/* net join/break, etc */</td>
+</tr>
+<tr>
+<td><font face="arial" size="2">2048</td>
+<td><font face="arial" size="2">SNO_IPMISMATCH</td>
+<td><font face="arial" size="2">0x800</td>
+<td><font face="arial" size="2">/* IP mismatches */</td>
+</tr>
+<tr>
+<td><font face="arial" size="2">4096</td>
+<td><font face="arial" size="2">SNO_THROTTLE</td>
+<td><font face="arial" size="2">0x1000</td>
+<td><font face="arial" size="2">/* host throttle add/remove notices */</td>
+</tr>
+<tr>
+<td><font face="arial" size="2">8192</td>
+<td><font face="arial" size="2">SNO_OLDREALOP</td>
+<td><font face="arial" size="2">0x2000</td>
+<td><font face="arial" size="2">/* old oper-only messages */</td>
+</tr>
+<tr>
+<td><font face="arial" size="2">16384</td>
+<td><font face="arial" size="2">SNO_CONNEXIT</td>
+<td><font face="arial" size="2">0x4000</td>
+<td><font face="arial" size="2">/* client connect/exit (ugh) */</td>
+</tr>
+<tr>
+<td><font face="arial" size="2">32768</td>
+<td><font face="arial" size="2">SNO_AUTO</td>
+<td><font face="arial" size="2">0x8000</td>
+<td><font face="arial" size="2">/* AUTO G-Lines */</td>
+</tr>
+<tr>
+<td><font face="arial" size="2">65536</td>
+<td><font face="arial" size="2">SNO_DEBUG</td>
+<td><font face="arial" size="2">0x10000</td>
+<td><font face="arial" size="2">/* debugging messages (DEBUGMODE only) */</td>
+</tr>
+<tr>
+<td><font face="arial" size="2">131072</td>
+<td><font face="arial" size="2">SNO_AUTH</td>
+<td><font face="arial" size="2">0x20000</td>
+<td><font face="arial" size="2">/* iauth status messages */</td>
+</tr>
+</table>
+</center>
+
+<p>
+
+<table border=0 cellpadding=0 cellspacing=5 width=90%>
+<tr>
+<td><font face="arial" size="2">standard +s</td>
+<td><font face="arial" size="2">SNO_DEFAULT (SNO_NETWORK | SNO_OPERKILL | SNO_GLINE)</td>
+</tr>
+<tr>
+<td><font face="arial" size="2">standard +s when +o/O</td>
+<td><font face="arial" size="2">SNO_DEFAULT | SNO_HACK2 | SNO_HACK4 | SNO_THROTTLE | SNO_OLDSNO)</td>
+</tr>
+<tr>
+<td><font face="arial" size="2">only opers may set</td>
+<td><font face="arial" size="2">SNO_OPER (SNO_CONNEXIT | SNO_OLDREALOP | SNO_AUTH)</td>
+</tr>
+</table>
+
+<p><hr width="80%" noshade>
+<h3 align=center>Examples of Usage</h3>
+To receive only operkills, use /mode <nick> +s 4<br>
+To receive operkills and glines, add the values:
+</font>
+<blockquote><kbd><strong>
+/mode &lt;nick&gt; +s 516</kbd></strong><p>
+<font face="arial" size="2">
+(512+4=516)
+</blockquote>
+<p>
+If you are already receiving some notices and you wish to add notices of
+netjoins/breaks use:
+</font>
+<blockquote><kbd><strong>
+/mode Ghostwolf +s +1024</kbd></strong><p>
+</blockquote>
+<font face="arial" size="2">
+<p>
+If you wish to stop receiving netjoin/break notices, but continue to receive
+other notices, use:
+</font>
+<blockquote><kbd><strong>
+/mode Ghostwolf +s -1024<br>
+ OR<br>
+/mode Ghostwolf -s +1024</kbd></strong>
+</blockquote>
+<font face="arial" size="2">
+<p>
+A user typing <strong>/mode Ghostwolf +s </strong>will receive netsplits/joins, operkills, and g-lines.<p>
+
+Opers who are +s will additionally receive HACK notices and anything that
+was originally in sendto_ops() and wasn't changed. Only opers can choose to
+receive connect/exit notices and anything that originally was in
+sendtoreal_ops() and hasn't been changed (connect/exit notices also require
+a #define in config.h).
+<p>
+</font><center>
+<hr width=80% noshade><font size=-1><strong>
+If you have further questions about server notices (implementation, etc.),<br>
+please consult the ircu source code and/or e-mail <a
+href="mailto:coder-com@undernet.org">coder-com@undernet.org</a>.
+</strong></font></center>
+<hr width="80%" noshade><p>
+
+<p align="right">
+<em>
+<font face="times new roman" font size="-1">
+Return to <a href="http://www.user-com.undernet.org/documents/" target="nfo">main Documents Project page</a><br>
+</em>
+</font>
+
+</body>
+</html>
+
+
diff --git a/doc/strings.txt b/doc/strings.txt
new file mode 100644 (file)
index 0000000..ce3562f
--- /dev/null
@@ -0,0 +1,33 @@
+Strings Information for ircu
+
+Client:
+
+name: (nickname for clients, server name for servers)
+  set in s_conf.c when checking C/N lines for a server
+  set in s_user.c during client registration
+
+username: (user name string)
+  set in s_auth.c if the client RFC 931 authentication query successful.
+  set in s_user.c if auth query unsuccessful.
+  
+info: (string)
+  set in s_serv.c during server registration
+  set in s_user.c during client registration
+
+passwd: (password string)
+  set in xxx.c when
+  used in xxx.c
+  cleared in xxx.c when
+
+sock_ip: (ip address)
+  set in s_bsd.c when connection is established
+  used in s_conf.c when looking for conf entries
+  not cleared
+
+sockhost: (resolved host name or ip address)
+  set in s_bsd.c when connection is established (copied from sock_ip)
+  set in s_auth.c if dns query is successful
+  set in s_conf.c if a C line is found that matches something in dns_reply.hp
+  used in opercmds.c
+  
+
diff --git a/include/IPcheck.h b/include/IPcheck.h
new file mode 100644 (file)
index 0000000..9be2e60
--- /dev/null
@@ -0,0 +1,27 @@
+/** @file IPcheck.h
+ * @brief Interface to count users connected from particular IP addresses.
+ * @version $Id: IPcheck.h 1329 2005-03-19 23:22:09Z entrope $
+ */
+#ifndef INCLUDED_ipcheck_h
+#define INCLUDED_ipcheck_h
+
+#ifndef INCLUDED_sys_types_h
+#include <sys/types.h>          /* time_t, size_t */
+#define INCLUDED_sys_types_h
+#endif
+
+struct Client;
+struct irc_in_addr;
+
+/*
+ * Prototypes
+ */
+extern void IPcheck_init(void);
+extern int IPcheck_local_connect(const struct irc_in_addr *ip, time_t *next_target_out);
+extern void IPcheck_connect_fail(const struct Client *cptr);
+extern void IPcheck_connect_succeeded(struct Client *cptr);
+extern int IPcheck_remote_connect(struct Client *cptr, int is_burst);
+extern void IPcheck_disconnect(struct Client *cptr);
+extern unsigned short IPcheck_nr(struct Client* cptr);
+
+#endif /* INCLUDED_ipcheck_h */
diff --git a/include/capab.h b/include/capab.h
new file mode 100644 (file)
index 0000000..8dd893e
--- /dev/null
@@ -0,0 +1,52 @@
+#ifndef INCLUDED_capab_h
+#define INCLUDED_capab_h
+/*
+ * IRC - Internet Relay Chat, include/capab.h
+ * Copyright (C) 2004 Kevin L. Mitchell <klmitch@mit.edu>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+/** @file
+ * @brief Interface and public definitions for capabilities extension
+ * @version $Id: capab.h 1349 2005-04-05 01:46:05Z entrope $
+ */
+
+#ifndef INCLUDED_client_h
+#include "client.h"
+#endif
+
+#define CAPFL_HIDDEN   0x0001  /**< Do not advertize this capability */
+#define CAPFL_PROHIBIT 0x0002  /**< Client may not set this capability */
+#define CAPFL_PROTO    0x0004  /**< Cap must be acknowledged by client */
+#define CAPFL_STICKY    0x0008  /**< Cap may not be cleared once set */
+
+#define CAPLIST        \
+       _CAP(USERPFX, 0, "undernet.org/userpfx")
+
+/** Client capabilities */
+enum Capab {
+#define _CAP(cap, flags, name) CAP_ ## cap
+  CAPLIST,
+#undef _CAP
+  _CAP_LAST_CAP
+};
+
+DECLARE_FLAGSET(CapSet, _CAP_LAST_CAP);
+
+#define CapHas(cs, cap)        FlagHas(cs, cap)
+#define CapSet(cs, cap)        FlagSet(cs, cap)
+#define CapClr(cs, cap)        FlagClr(cs, cap)
+
+#endif /* INCLUDED_capab_h */
diff --git a/include/channel.h b/include/channel.h
new file mode 100644 (file)
index 0000000..353aeae
--- /dev/null
@@ -0,0 +1,470 @@
+/*
+ * IRC - Internet Relay Chat, ircd/channel.h
+ * Copyright (C) 1990 Jarkko Oikarinen
+ * Copyright (C) 1996 - 1997 Carlo Wood
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+/** @file
+ * @brief Channel management and maintenance.
+ * @version $Id: channel.h 1860 2007-12-28 15:52:43Z klmitch $
+ */
+#ifndef INCLUDED_channel_h
+#define INCLUDED_channel_h
+#ifndef INCLUDED_ircd_defs_h
+#include "ircd_defs.h"        /* NICKLEN */
+#endif
+#ifndef INCLUDED_sys_types_h
+#include <sys/types.h>
+#define INCLUDED_sys_types_h
+#endif
+#ifndef INCLUDED_res_h
+#include "res.h"
+#endif
+
+struct SLink;
+struct Client;
+
+/*
+ * General defines
+ */
+
+#define MAXMODEPARAMS   6      /**< Maximum number of mode parameters */
+#define MODEBUFLEN      200    /**< Maximum length of a mode */
+
+#define KEYLEN          23     /**< Maximum length of a key */
+#define CHANNELLEN      200    /**< Maximum length of a channel */
+
+#define MAXJOINARGS    15      /**< number of slots for join buffer */
+#define STARTJOINLEN   10      /**< fuzzy numbers */
+#define STARTCREATELEN 20
+
+/*
+ * Macro's
+ */
+
+#define ChannelExists(n)        (0 != FindChannel(n))
+
+#define CHFL_CHANOP             0x0001  /**< Channel operator */
+#define CHFL_VOICE              0x0002  /**< the power to speak */
+#define CHFL_DEOPPED            0x0004  /**< Is de-opped by a server */
+#define CHFL_SERVOPOK           0x0008  /**< Server op allowed */
+#define CHFL_ZOMBIE             0x0010  /**< Kicked from channel */
+#define CHFL_BURST_JOINED       0x0100  /**< Just joined by net.junction */
+#define CHFL_BANVALID           0x0800  /**< CHFL_BANNED bit is valid */
+#define CHFL_BANNED             0x1000  /**< Channel member is banned */
+#define CHFL_SILENCE_IPMASK     0x2000  /**< silence mask is a CIDR */
+#define CHFL_BURST_ALREADY_OPPED       0x04000  
+                                       /**< In oob BURST, but was already 
+                                        * joined and opped 
+                                        */
+#define CHFL_BURST_ALREADY_VOICED      0x08000  
+                                       /**, In oob BURST, but was already 
+                                        * joined and voiced 
+                                        */
+#define CHFL_CHANNEL_MANAGER   0x10000 /**< Set when creating channel or using 
+                                        * Apass 
+                                        */
+#define CHFL_USER_PARTING       0x20000 /**< User is already parting that 
+                                        * channel 
+                                        */
+#define CHFL_DELAYED            0x40000 /**< User's join message is delayed */
+#define CHFL_INVISIBLE            0x80000 /**< User's join message is delayed */
+
+#define CHFL_OVERLAP         (CHFL_CHANOP | CHFL_VOICE)
+#define CHFL_BANVALIDMASK    (CHFL_BANVALID | CHFL_BANNED)
+#define CHFL_VOICED_OR_OPPED (CHFL_CHANOP | CHFL_VOICE)
+
+/* Channel Visibility macros */
+
+#define MODE_CHANOP     CHFL_CHANOP    /**< +o Chanop */
+#define MODE_VOICE      CHFL_VOICE     /**< +v Voice */
+#define MODE_PRIVATE    0x0004         /**< +p Private */
+#define MODE_SECRET     0x0008         /**< +s Secret */
+#define MODE_MODERATED  0x0010         /**< +m Moderated */
+#define MODE_TOPICLIMIT 0x0020         /**< +t Topic Limited */
+#define MODE_INVITEONLY 0x0040         /**< +i Invite only */
+#define MODE_NOPRIVMSGS 0x0080         /**< +n No Private Messages */
+#define MODE_KEY        0x0100         /**< +k Keyed */
+#define MODE_BAN        0x0200         /**< +b Ban */
+#define MODE_LIMIT      0x0400         /**< +l Limit */
+#define MODE_REGONLY    0x0800         /**< Only +r users may join */
+#define MODE_DELJOINS   0x1000         /**< New join messages are delayed */
+#define MODE_REGISTERED 0x2000         /**< Channel marked as registered
+                                        * (for future semantic expansion) */
+#define MODE_PERSIST    0x4000      /**< +z persistant channel */
+#define MODE_NOCOLOUR   0x8000      /**< no ANSI color codes */
+#define MODE_NOCTCP    0x10000      /**< no channel CTCPs */
+#define MODE_SAVE      0x20000         /**< save this mode-with-arg 'til 
+                                        * later */
+#define MODE_FREE      0x40000         /**< string needs to be passed to 
+                                        * MyFree() */
+#define MODE_BURSTADDED        0x80000         /**< channel was created by a BURST */
+#define MODE_UPASS     0x100000
+#define MODE_APASS     0x200000
+#define MODE_WASDELJOINS 0x400000      /**< Not DELJOINS, but some joins 
+                                        * pending */
+#define MODE_EXCEPTION  0x800000    /**< ban exceptions */
+#define MODE_NOAMSGS 0x1000000    /**< No multi target messages */
+#define MODE_NONOTICE 0x2000000    /**< No channel notices */
+#define MODE_QUARANTINE 0x4000000    /**< No channel notices */
+#define MODE_ALTCHAN 0x8000000    /**< Alternative channel */
+#define MODE_ACCESS 0x10000000    /**< ChanServ access */
+/** mode flags which take another parameter (With PARAmeterS)
+ */
+#define MODE_WPARAS     (MODE_CHANOP|MODE_VOICE|MODE_BAN|MODE_KEY|MODE_LIMIT|MODE_APASS|MODE_UPASS|MODE_EXCEPTION|MODE_ALTCHAN|MODE_ACCESS)
+
+/** Available Channel modes */
+#define infochanmodes feature_bool(FEAT_OPLEVELS) ? "AcCbiklmMnNopstUvrDRzQ" : "cCbiklmMnNopstvrDRzQ"
+/** Available Channel modes that take parameters */
+#define infochanmodeswithparams feature_bool(FEAT_OPLEVELS) ? "AbkloUvFa" : "bklovFa"
+
+#define HoldChannel(x)          (!(x))
+/** name invisible */
+#define SecretChannel(x)        ((x) && ((x)->mode.mode & MODE_SECRET))
+/** channel not shown but names are */
+#define HiddenChannel(x)        ((x) && ((x)->mode.mode & MODE_PRIVATE))
+/** channel visible */
+#define ShowChannel(v,c)        (PubChannel(c) || find_channel_member((v),(c)))
+#define PubChannel(x)           ((!x) || ((x)->mode.mode & \
+                                    (MODE_PRIVATE | MODE_SECRET)) == 0)
+
+#define IsGlobalChannel(name)   (*(name) == '#')
+#define IsLocalChannel(name)    (*(name) == '&')
+#define IsChannelName(name)     (IsGlobalChannel(name) || IsLocalChannel(name))
+
+typedef enum ChannelGetType {
+  CGT_NO_CREATE,
+  CGT_CREATE
+} ChannelGetType;
+
+/* used in SetMode() in channel.c and m_umode() in s_msg.c */
+
+#define MODE_NULL      0
+#define MODE_ADD       0x40000000
+#define MODE_DEL       0x20000000
+
+/* used in ListingArgs.flags */
+
+#define LISTARG_TOPICLIMITS     0x0001
+#define LISTARG_SHOWSECRET      0x0002
+#define LISTARG_NEGATEWILDCARD  0x0004
+#define LISTARG_SHOWMODES       0x0008
+
+/**
+ * Maximum acceptable lag time in seconds: A channel younger than
+ * this is not protected against hacking admins.
+ * Mainly here to check if the TS clocks really sync (otherwise this
+ * will start causing HACK notices.
+ * This value must be the same on all servers.
+ *
+ * This value has been increased to 1 day in order to distinguish this
+ * "normal" type of HACK wallops / desyncs, from possiblity still
+ * existing bugs.
+ */
+#define TS_LAG_TIME 86400
+
+
+
+extern const char* const PartFmt1;
+extern const char* const PartFmt2;
+extern const char* const PartFmt1serv;
+extern const char* const PartFmt2serv;
+
+
+/*
+ * Structures
+ */
+
+/** Information about a client on one channel
+ *
+ * This structure forms a sparse matrix with users down the side, and
+ * channels across the top.  This matrix holds all the information about
+ * which users are on what channels, and what modes that user has on that
+ * channel (if they are op'd, voice'd and cached information if they are
+ * banned or not)
+ */
+struct Membership {
+  struct Client*     user;             /**< The user */
+  struct Channel*    channel;          /**< The channel */
+  struct Membership* next_member;      /**< The next user on this channel */
+  struct Membership* prev_member;      /**< The previous user on this channel*/
+  struct Membership* next_channel;     /**< Next channel this user is on */
+  struct Membership* prev_channel;     /**< Previous channel this user is on*/
+  unsigned int       status;           /**< Flags for op'd, voice'd, etc */
+  unsigned short     oplevel;          /**< Op level */
+};
+
+#define MAXOPLEVELDIGITS    3
+#define MAXOPLEVEL          999
+
+#define IsZombie(x)         ((x)->status & CHFL_ZOMBIE) /**< see \ref zombie */
+#define IsDeopped(x)        ((x)->status & CHFL_DEOPPED)
+#define IsBanned(x)         ((x)->status & CHFL_BANNED)
+#define IsBanValid(x)       ((x)->status & CHFL_BANVALID)
+#define IsChanOp(x)         ((x)->status & CHFL_CHANOP)
+#define OpLevel(x)          ((x)->oplevel)
+#define HasVoice(x)         ((x)->status & CHFL_VOICE)
+#define IsServOpOk(x)       ((x)->status & CHFL_SERVOPOK)
+#define IsBurstJoined(x)    ((x)->status & CHFL_BURST_JOINED)
+#define IsVoicedOrOpped(x)  ((x)->status & CHFL_VOICED_OR_OPPED)
+#define IsChannelManager(x) ((x)->status & CHFL_CHANNEL_MANAGER)
+#define IsUserParting(x)    ((x)->status & CHFL_USER_PARTING)
+#define IsDelayedJoin(x)    ((x)->status & CHFL_DELAYED)
+#define IsInvisibleJoin(x)    ((x)->status & CHFL_INVISIBLE)
+
+#define SetBanned(x)        ((x)->status |= CHFL_BANNED)
+#define SetBanValid(x)      ((x)->status |= CHFL_BANVALID)
+#define SetDeopped(x)       ((x)->status |= CHFL_DEOPPED)
+#define SetServOpOk(x)      ((x)->status |= CHFL_SERVOPOK)
+#define SetBurstJoined(x)   ((x)->status |= CHFL_BURST_JOINED)
+#define SetZombie(x)        ((x)->status |= CHFL_ZOMBIE)
+#define SetChannelManager(x) ((x)->status |= CHFL_CHANNEL_MANAGER)
+#define SetOpLevel(x, v)    (void)((x)->oplevel = (v))
+#define SetUserParting(x)   ((x)->status |= CHFL_USER_PARTING)
+#define SetDelayedJoin(x)   ((x)->status |= CHFL_DELAYED)
+
+#define ClearBanned(x)      ((x)->status &= ~CHFL_BANNED)
+#define ClearBanValid(x)    ((x)->status &= ~CHFL_BANVALID)
+#define ClearDeopped(x)     ((x)->status &= ~CHFL_DEOPPED)
+#define ClearServOpOk(x)    ((x)->status &= ~CHFL_SERVOPOK)
+#define ClearBurstJoined(x) ((x)->status &= ~CHFL_BURST_JOINED)
+#define ClearDelayedJoin(x) ((x)->status &= ~CHFL_DELAYED)
+#define ClearInvisibleJoin(x) ((x)->status &= ~CHFL_DELAYED)
+
+/** Mode information for a channel */
+struct Mode {
+  unsigned int mode;
+  unsigned int limit;
+  unsigned int access;
+  char key[KEYLEN + 1];
+  char upass[KEYLEN + 1];
+  char apass[KEYLEN + 1];
+  char altchan[CHANNELLEN + 1];
+};
+
+#define BAN_IPMASK         0x0001  /**< ban mask is an IP-number mask */
+#define BAN_OVERLAPPED     0x0002  /**< ban overlapped, need bounce */
+#define BAN_BURSTED        0x0004  /**< Ban part of last BURST */
+#define BAN_BURST_WIPEOUT  0x0008  /**< Ban will be wiped at EOB */
+#define BAN_EXCEPTION      0x0010  /**< Ban is an exception */
+#define BAN_DEL            0x4000  /**< Ban is being removed */
+#define BAN_ADD            0x8000  /**< Ban is being added */
+
+/** A single ban for a channel. */
+struct Ban {
+  struct Ban* next;           /**< next ban in the channel */
+  struct irc_in_addr address; /**< address for BAN_IPMASK bans */
+  time_t when;                /**< timestamp when ban was added */
+  unsigned short flags;       /**< modifier flags for the ban */
+  unsigned char nu_len;       /**< length of nick!user part of banstr */
+  unsigned char addrbits;     /**< netmask length for BAN_IPMASK bans */
+  char who[NICKLEN+1];        /**< name of client that set the ban */
+  char banstr[NICKLEN+USERLEN+HOSTLEN+3];  /**< hostmask that the ban matches */
+};
+
+/** Information about a channel */
+struct Channel {
+  struct Channel*    next;     /**< next channel in the global channel list */
+  struct Channel*    prev;     /**< previous channel */
+  struct Channel*    hnext;    /**< Next channel in the hash table */
+  struct DestructEvent* destruct_event;        
+  time_t             creationtime; /**< Creation time of this channel */
+  time_t             topic_time;   /**< Modification time of the topic */
+  unsigned int       users;       /**< Number of clients on this channel */
+  struct Membership* members;     /**< Pointer to the clients on this channel*/
+  struct SLink*      invites;     /**< List of invites on this channel */
+  struct Ban*        banlist;      /**< List of bans on this channel */
+  struct Mode        mode;        /**< This channels mode */
+  char               topic[TOPICLEN + 1]; /**< Channels topic */
+  char               topic_nick[NICKLEN + 1]; /**< Nick of the person who set                   
+                                               *  The topic
+                                               */
+  char                          chanowner[NICKLEN + 1]; //channel owner (auth)
+  char               chname[1];           /**< Dynamically allocated string of the 
+                                    * channel name
+                                    */
+};
+
+/** Information about a /list in progress */
+struct ListingArgs {
+  time_t max_time;
+  time_t min_time;
+  unsigned int max_users;
+  unsigned int min_users;
+  unsigned int flags;
+  time_t max_topic_time;
+  time_t min_topic_time;
+  unsigned int bucket;
+  char wildcard[CHANNELLEN];
+};
+
+struct ModeBuf {
+  unsigned int         mb_add;         /**< Modes to add */
+  unsigned int         mb_rem;         /**< Modes to remove */
+  struct Client               *mb_source;      /**< Source of MODE changes */
+  struct Client               *mb_connect;     /**< Connection of MODE changes */
+  struct Channel       *mb_channel;    /**< Channel they affect */
+  unsigned int         mb_dest;        /**< Destination of MODE changes */
+  unsigned int         mb_count;       /**< Number of modes w/args */
+  struct {
+    unsigned int       mbm_type;       /**< Type of argument */
+    union {
+      unsigned int     mbma_uint;      /**< A limit */
+      char            *mbma_string;    /**< A string */
+      struct Client    *mbma_client;   /**< A client */
+    }                  mbm_arg;        /**< The mode argument */
+    unsigned short      mbm_oplevel;    /**< Oplevel for a bounce */
+  }                    mb_modeargs[MAXMODEPARAMS];
+                                       /**< A mode w/args */
+};
+
+#define MODEBUF_DEST_CHANNEL   0x00001 /**< Mode is flushed to channel */
+#define MODEBUF_DEST_SERVER    0x00002 /**< Mode is flushed to server */
+
+#define MODEBUF_DEST_OPMODE    0x00100 /**< Send server mode as OPMODE */
+#define MODEBUF_DEST_DEOP      0x00200 /**< Deop the offender */
+#define MODEBUF_DEST_BOUNCE    0x00400 /**< Bounce the modes */
+#define MODEBUF_DEST_LOG       0x00800 /**< Log the mode changes to OPATH */
+
+#define MODEBUF_DEST_HACK2     0x02000 /**< Send a HACK(2) notice, reverse */
+#define MODEBUF_DEST_HACK3     0x04000 /**< Send a HACK(3) notice, TS == 0 */
+#define MODEBUF_DEST_HACK4     0x08000 /**< Send a HACK(4) notice, TS == 0 */
+
+#define MODEBUF_DEST_NOKEY     0x10000 /**< Don't send the real key */
+
+#define MB_TYPE(mb, i)         ((mb)->mb_modeargs[(i)].mbm_type)
+#define MB_UINT(mb, i)         ((mb)->mb_modeargs[(i)].mbm_arg.mbma_uint)
+#define MB_STRING(mb, i)       ((mb)->mb_modeargs[(i)].mbm_arg.mbma_string)
+#define MB_CLIENT(mb, i)       ((mb)->mb_modeargs[(i)].mbm_arg.mbma_client)
+#define MB_OPLEVEL(mb, i)       ((mb)->mb_modeargs[(i)].mbm_oplevel)
+
+/** A buffer represeting a list of joins to send */
+struct JoinBuf {
+  struct Client               *jb_source;      /**< Source of joins (ie, joiner) */
+  struct Client               *jb_connect;     /**< Connection of joiner */
+  unsigned int         jb_type;        /**< Type of join (JOIN or CREATE) */
+  char                *jb_comment;     /**< part comment */
+  time_t               jb_create;      /**< Creation timestamp */
+  unsigned int         jb_count;       /**< Number of channels */
+  unsigned int         jb_strlen;      /**< length so far */
+  struct Channel       *jb_channels[MAXJOINARGS];
+                                       /**< channels joined or whatever */
+};
+
+#define JOINBUF_TYPE_JOIN      0       /**< send JOINs */
+#define JOINBUF_TYPE_CREATE    1       /**< send CREATEs */
+#define JOINBUF_TYPE_PART      2       /**< send PARTs */
+#define JOINBUF_TYPE_PARTALL   3       /**< send local PARTs, but not remote */
+
+extern struct Channel* GlobalChannelList;
+extern int             LocalChanOperMode;
+
+/*
+ * Proto types
+ */
+extern void channel_modes(struct Client *cptr, char *mbuf, char *pbuf,
+                          int buflen, struct Channel *chptr,
+                         struct Membership *member);
+extern int set_mode(struct Client* cptr, struct Client* sptr,
+                    struct Channel* chptr, int parc, char* parv[],
+                    char* mbuf, char* pbuf, char* npbuf, int* badop);
+extern void send_hack_notice(struct Client *cptr, struct Client *sptr,
+                             int parc, char *parv[], int badop, int mtype);
+extern struct Channel *get_channel(struct Client *cptr,
+                                   char *chname, ChannelGetType flag);
+extern struct Membership* find_member_link(struct Channel * chptr,
+                                           const struct Client* cptr);
+extern int sub1_from_channel(struct Channel* chptr);
+extern int destruct_channel(struct Channel* chptr);
+extern void add_user_to_channel(struct Channel* chptr, struct Client* who,
+                                unsigned int flags, int oplevel);
+extern void make_zombie(struct Membership* member, struct Client* who,
+                        struct Client* cptr, struct Client* sptr,
+                        struct Channel* chptr);
+extern struct Client* find_chasing(struct Client* sptr, const char* user, int* chasing);
+void add_invite(struct Client *cptr, struct Channel *chptr);
+int number_of_zombies(struct Channel *chptr);
+
+extern const char* find_no_nickchange_channel(struct Client* cptr);
+extern struct Membership* find_channel_member(struct Client* cptr, struct Channel* chptr);
+extern int member_can_send_to_channel(struct Membership* member, int reveal);
+extern int client_can_send_to_channel(struct Client *cptr, struct Channel *chptr, int reveal);
+
+extern void remove_user_from_channel(struct Client *sptr, struct Channel *chptr);
+extern void remove_user_from_all_channels(struct Client* cptr);
+
+extern int is_chan_op(struct Client *cptr, struct Channel *chptr);
+extern int is_zombie(struct Client *cptr, struct Channel *chptr);
+extern int has_voice(struct Client *cptr, struct Channel *chptr);
+/*
+   NOTE: pointer is compared, and not dereferenced, called by
+   add_target with a void*, since targets could be anything,
+   this function can't make any assumptions that it has a channel
+*/
+extern int IsInvited(struct Client* cptr, const void* chptr);
+extern void send_channel_modes(struct Client *cptr, struct Channel *chptr);
+extern char *pretty_mask(char *mask);
+extern void del_invite(struct Client *cptr, struct Channel *chptr);
+extern void list_set_default(void); /* this belongs elsewhere! */
+
+extern void RevealDelayedJoinIfNeeded(struct Client *sptr, struct Channel *chptr);
+extern void RevealDelayedJoin(struct Membership *member);
+extern void CheckDelayedJoins(struct Channel *chan);
+
+extern void modebuf_init(struct ModeBuf *mbuf, struct Client *source,
+                        struct Client *connect, struct Channel *chan,
+                        unsigned int dest);
+extern void modebuf_mode(struct ModeBuf *mbuf, unsigned int mode);
+extern void modebuf_mode_uint(struct ModeBuf *mbuf, unsigned int mode,
+                             unsigned int uint);
+extern void modebuf_mode_string(struct ModeBuf *mbuf, unsigned int mode,
+                               char *string, int free);
+extern void modebuf_mode_client(struct ModeBuf *mbuf, unsigned int mode,
+                               struct Client *client, int oplevel);
+extern int modebuf_flush(struct ModeBuf *mbuf);
+extern void modebuf_extract(struct ModeBuf *mbuf, char *buf);
+
+extern void mode_ban_invalidate(struct Channel *chan);
+extern void mode_invite_clear(struct Channel *chan);
+
+extern int mode_parse(struct ModeBuf *mbuf, struct Client *cptr,
+                     struct Client *sptr, struct Channel *chptr,
+                     int parc, char *parv[], unsigned int flags,
+                     struct Membership* member);
+
+#define MODE_PARSE_SET         0x01    /**< actually set channel modes */
+#define MODE_PARSE_STRICT      0x02    /**< +m +n +t style not supported */
+#define MODE_PARSE_FORCE       0x04    /**< force the mode to be applied */
+#define MODE_PARSE_BOUNCE      0x08    /**< we will be bouncing the modes */
+#define MODE_PARSE_NOTOPER     0x10    /**< send "not chanop" to user */
+#define MODE_PARSE_NOTMEMBER   0x20    /**< send "not member" to user */
+#define MODE_PARSE_WIPEOUT     0x40    /**< wipe out +k and +l during burst */
+#define MODE_PARSE_BURST       0x80    /**< be even more strict w/extra args */
+
+extern void joinbuf_init(struct JoinBuf *jbuf, struct Client *source,
+                        struct Client *connect, unsigned int type,
+                        char *comment, time_t create);
+extern void joinbuf_join(struct JoinBuf *jbuf, struct Channel *chan,
+                        unsigned int flags);
+extern int joinbuf_flush(struct JoinBuf *jbuf);
+extern struct Ban *make_ban(const char *banstr);
+extern struct Ban *find_ban(struct Client *cptr, struct Ban *banlist);
+extern int apply_ban(struct Ban **banlist, struct Ban *newban, int free);
+extern void free_ban(struct Ban *ban);
+extern signed int destruct_nonpers_channel(struct Channel *chptr);
+extern int ext_amsg_block(struct Client *cptr, struct Channel *chptr, const char *msg);
+
+#endif /* INCLUDED_channel_h */
diff --git a/include/class.h b/include/class.h
new file mode 100644 (file)
index 0000000..8dc4faa
--- /dev/null
@@ -0,0 +1,121 @@
+/*
+ * IRC - Internet Relay Chat, include/class.h
+ * Copyright (C) 1990 Darren Reed
+ * Copyright (C) 1996 - 1997 Carlo Wood
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+/** @file
+ * @brief Declarations and interfaces for handling connection classes.
+ * @version $Id: class.h 1511 2005-10-05 01:53:30Z entrope $
+ */
+#ifndef INCLUDED_class_h
+#define INCLUDED_class_h
+#ifndef INCLUDED_sys_types_h
+#include <sys/types.h>
+#define INCLUDED_sys_types_h
+#endif
+
+#include "client.h"
+
+struct ConfItem;
+struct StatDesc;
+
+/*
+ * Structures
+ */
+/** Represents a connection class. */
+struct ConnectionClass {
+  struct ConnectionClass* next;           /**< Link to next connection class. */
+  char                    *cc_name;       /**< Name of connection class. */
+  char                    *default_umode; /**< Default usermode for users
+                                             in this class. */
+  struct Privs            privs;          /**< Privilege bits that are set on
+                                             or off. */
+  struct Privs            privs_dirty;    /**< Indication of which bits in
+                                             ConnectionClass::privs are valid. */
+  unsigned int            max_sendq;      /**< Maximum client SendQ in bytes. */
+  unsigned int            max_links;      /**< Maximum connections allowed. */
+  unsigned int            ref_count;      /**< Number of references to class. */
+  unsigned int            max_channels;   /**< Maximum number of channels */
+  unsigned short          ping_freq;      /**< Ping frequency for clients. */
+  unsigned short          conn_freq;      /**< Auto-connect frequency. */
+  unsigned char           valid;          /**< Valid flag (cleared after this
+                                             class is removed from the config).*/
+};
+
+/*
+ * Macro's
+ */
+
+/** Get class name for \a x. */
+#define ConClass(x)     ((x)->cc_name)
+/** Get ping frequency for \a x. */
+#define PingFreq(x)     ((x)->ping_freq)
+/** Get connection frequency for \a x. */
+#define ConFreq(x)      ((x)->conn_freq)
+/** Get maximum links allowed for \a x. */
+#define MaxLinks(x)     ((x)->max_links)
+/** Get maximum SendQ size for \a x. */
+#define MaxSendq(x)     ((x)->max_sendq)
+/** Get number of references to \a x. */
+#define Links(x)        ((x)->ref_count)
+/** Get maximum number of channels for \a x. */
+#define MaxChannels(x)  (((x)->max_channels)?((x)->max_channels):feature_int(FEAT_MAXCHANNELSPERUSER))
+
+/** Get class name for ConfItem \a x. */
+#define ConfClass(x)    ((x)->conn_class->cc_name)
+/** Get ping frequency for ConfItem \a x. */
+#define ConfPingFreq(x) ((x)->conn_class->ping_freq)
+/** Get connection frequency for ConfItem \a x. */
+#define ConfConFreq(x)  ((x)->conn_class->conn_freq)
+/** Get maximum links allowed for ConfItem \a x. */
+#define ConfMaxLinks(x) ((x)->conn_class->max_links)
+/** Get maximum SendQ size for ConfItem \a x. */
+#define ConfSendq(x)    ((x)->conn_class->max_sendq)
+/** Get number of references to class in ConfItem \a x. */
+#define ConfLinks(x)    ((x)->conn_class->ref_count)
+/** Get default usermode for ConfItem \a x. */
+#define ConfUmode(x)    ((x)->conn_class->default_umode)
+/** Get maximum number of channels for ConfItem \a x. */
+#define ConfMaxChannels(x) (((x)->conn_class->max_channels)?((x)->conn_class->max_channels):feature_int(FEAT_MAXCHANNELSPERUSER))
+/** Find a valid configuration class by name. */
+#define find_class(name) do_find_class((name), 0)
+
+/*
+ * Proto types
+ */
+
+extern void init_class(void);
+
+extern const struct ConnectionClass* get_class_list(void);
+extern void class_mark_delete(void);
+extern void class_delete_marked(void);
+
+extern struct ConnectionClass *do_find_class(const char *name, int extras);
+extern struct ConnectionClass *make_class(void);
+extern void free_class(struct ConnectionClass * tmp);
+extern char *get_conf_class(const struct ConfItem *aconf);
+extern int get_conf_ping(const struct ConfItem *aconf);
+extern char *get_client_class(struct Client *acptr);
+extern void add_class(char *name, unsigned int ping,
+                      unsigned int confreq, unsigned int maxli,
+                      unsigned int sendq, unsigned int max_channels);
+extern void report_classes(struct Client *sptr, const struct StatDesc *sd,
+                           char *param);
+extern unsigned int get_sendq(struct Client* cptr);
+
+extern void class_send_meminfo(struct Client* cptr);
+#endif /* INCLUDED_class_h */
diff --git a/include/client.h b/include/client.h
new file mode 100644 (file)
index 0000000..175dd94
--- /dev/null
@@ -0,0 +1,863 @@
+/*
+ * IRC - Internet Relay Chat, include/client.h
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ *                    University of Oulu, Computing Center
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+/** @file
+ * @brief Structures and functions for handling local clients.
+ * @version $Id: client.h 1907 2009-02-09 04:11:04Z entrope $
+ */
+#ifndef INCLUDED_client_h
+#define INCLUDED_client_h
+#ifndef INCLUDED_ircd_defs_h
+#include "ircd_defs.h"
+#endif
+#ifndef INCLUDED_dbuf_h
+#include "dbuf.h"
+#endif
+#ifndef INCLUDED_msgq_h
+#include "msgq.h"
+#endif
+#ifndef INCLUDED_ircd_events_h
+#include "ircd_events.h"
+#endif
+#ifndef INCLUDED_ircd_handler_h
+#include "ircd_handler.h"
+#endif
+#ifndef INCLUDED_res_h
+#include "res.h"
+#endif
+#ifndef INCLUDED_sys_types_h
+#include <sys/types.h>          /* time_t, size_t */
+#define INCLUDED_sys_types_h
+#endif
+
+struct ConfItem;
+struct Listener;
+struct ListingArgs;
+struct SLink;
+struct Server;
+struct User;
+struct Whowas;
+struct hostent;
+struct Privs;
+struct AuthRequest;
+
+/*
+ * Structures
+ *
+ * Only put structures here that are being used in a very large number of
+ * source files. Other structures go in the header file of there corresponding
+ * source file, or in the source file itself (when only used in that file).
+ */
+
+/** Single element in a flag bitset array. */
+typedef unsigned long flagpage_t;
+
+/** Number of bits in a flagpage_t. */
+#define FLAGSET_NBITS (8 * sizeof(flagpage_t))
+/** Element number for flag \a flag. */
+#define FLAGSET_INDEX(flag) ((flag) / FLAGSET_NBITS)
+/** Element bit for flag \a flag. */
+#define FLAGSET_MASK(flag) (1ul<<((flag) % FLAGSET_NBITS))
+
+/** Declare a flagset structure of a particular size. */
+#define DECLARE_FLAGSET(name,max) \
+  struct name \
+  { \
+    unsigned long bits[((max + FLAGSET_NBITS - 1) / FLAGSET_NBITS)]; \
+  }
+
+/** Test whether a flag is set in a flagset. */
+#define FlagHas(set,flag) ((set)->bits[FLAGSET_INDEX(flag)] & FLAGSET_MASK(flag))
+/** Set a flag in a flagset. */
+#define FlagSet(set,flag) ((set)->bits[FLAGSET_INDEX(flag)] |= FLAGSET_MASK(flag))
+/** Clear a flag in a flagset. */
+#define FlagClr(set,flag) ((set)->bits[FLAGSET_INDEX(flag)] &= ~FLAGSET_MASK(flag))
+
+/** String containing valid user modes, in no particular order. */
+#define infousermodes "dioswkgxnIXSHc"
+
+/** Operator privileges. */
+enum Priv
+  {
+    PRIV_CHAN_LIMIT, /**< no channel limit on oper */
+    PRIV_MODE_LCHAN, /**< oper can mode local chans */
+    PRIV_WALK_LCHAN, /**< oper can walk through local modes */
+    PRIV_DEOP_LCHAN, /**< no deop oper on local chans */
+    PRIV_SHOW_INVIS, /**< show local invisible users */
+    PRIV_SHOW_ALL_INVIS, /**< show all invisible users */
+    PRIV_UNLIMIT_QUERY, /**< unlimit who queries */
+    PRIV_KILL, /**< oper can KILL */
+    PRIV_LOCAL_KILL, /**< oper can local KILL */
+    PRIV_REHASH, /**< oper can REHASH */
+    PRIV_RESTART, /**< oper can RESTART */
+    PRIV_DIE, /**< oper can DIE */
+    PRIV_GLINE, /**< oper can GLINE */
+    PRIV_LOCAL_GLINE, /**< oper can local GLINE */
+    PRIV_JUPE, /**< oper can JUPE */
+    PRIV_LOCAL_JUPE, /**< oper can local JUPE */
+    PRIV_OPMODE, /**< oper can OP/CLEARMODE */
+    PRIV_LOCAL_OPMODE, /**< oper can local OP/CLEARMODE */
+    PRIV_SET,  /**< oper can SET */
+    PRIV_WHOX, /**< oper can use /who x */
+    PRIV_BADCHAN, /**< oper can BADCHAN */
+    PRIV_LOCAL_BADCHAN, /**< oper can local BADCHAN */
+    PRIV_SEE_CHAN, /**< oper can see in secret chans */
+    PRIV_PROPAGATE, /**< propagate oper status */
+    PRIV_DISPLAY, /**< "Is an oper" displayed */
+    PRIV_SEE_OPERS, /**< display hidden opers */
+    PRIV_WIDE_GLINE, /**< oper can set wider G-lines */
+    PRIV_LIST_CHAN, /**< oper can list secret channels */
+    PRIV_FORCE_OPMODE, /**< can hack modes on quarantined channels */
+    PRIV_FORCE_LOCAL_OPMODE, /**< can hack modes on quarantined local channels */
+    PRIV_APASS_OPMODE, /**< can hack modes +A/-A/+U/-U */
+    PRIV_UMODE_NOCHAN, /**< can set umode +n (hide channels) */
+    PRIV_UMODE_NOIDLE, /**< can set umode +I (hide idle time) */
+    PRIV_UMODE_CHSERV, /**< can set umode +k (channel service) */
+    PRIV_UMODE_XTRAOP, /**< can set umode +X (eXtra oper; override +k) */
+    PRIV_UMODE_NETSERV, /**< can set umode +S (network service) */
+    PRIV_SEE_IDLETIME, /**< can see idle time of +I users */
+    PRIV_HIDE_IDLETIME, /**< hide idle time in 2nd layer */
+    PRIV_HALFFLOOD, /**< user has less throttling */
+    PRIV_FLOOD, /**< no more excess floods */
+    PRIV_UNLIMITED_TARGET, /**< unlimited target changes */
+    PRIV_UMODE_OVERRIDECC, /**< can set umode +c (override cmodes +cC) */
+    PRIV_NOAMSG_OVERRIDE, /**< can override the +M channelmode */
+    PRIV_LAST_PRIV /**< number of privileges */
+  };
+
+/** Client flags and modes.
+ * Note that flags at least FLAG_LOCAL_UMODES but less than
+ * FLAG_GLOBAL_UMODES are treated as local modes, and flags at least
+ * FLAG_GLOBAL_UMODES (but less than FLAG_LAST_FLAG) are treated as
+ * global modes.
+ */
+enum Flag
+  {
+    FLAG_PINGSENT,                  /**< Unreplied ping sent */
+    FLAG_DEADSOCKET,                /**< Local socket is dead--Exiting soon */
+    FLAG_KILLED,                    /**< Prevents "QUIT" from being sent for this */
+    FLAG_BLOCKED,                   /**< socket is in a blocked condition */
+    FLAG_CLOSING,                   /**< set when closing to suppress errors */
+    FLAG_UPING,                     /**< has active UDP ping request */
+    FLAG_HUB,                       /**< server is a hub */
+    FLAG_IPV6,                      /**< server understands P10 IPv6 addrs */
+    FLAG_SERVICE,                   /**< server is a service */
+    FLAG_MASTER,                    /**< server is a master */
+    FLAG_GOTID,                     /**< successful ident lookup achieved */
+    FLAG_DOID,                      /**< I-lines say must use ident return */
+    FLAG_NONL,                      /**< No \n in buffer */
+    FLAG_TS8,                       /**< Why do you want to know? */
+    FLAG_MAP,                       /**< Show server on the map */
+    FLAG_JUNCTION,                  /**< Junction causing the net.burst. */
+    FLAG_BURST,                     /**< Server is receiving a net.burst */
+    FLAG_BURST_ACK,                 /**< Server is waiting for eob ack */
+    FLAG_IPCHECK,                   /**< Added or updated IPregistry data */
+    FLAG_LOCOP,                     /**< Local operator -- SRB */
+    FLAG_SERVNOTICE,                /**< server notices such as kill */
+    FLAG_OPER,                      /**< Operator */
+    FLAG_INVISIBLE,                 /**< makes user invisible */
+    FLAG_WALLOP,                    /**< send wallops to them */
+    FLAG_DEAF,                      /**< Makes user deaf */
+    FLAG_CHSERV,                    /**< Disallow KICK or MODE -o on the user;
+                                       don't display channels in /whois */
+    FLAG_DEBUG,                     /**< send global debug/anti-hack info */
+    FLAG_ACCOUNT,                   /**< account name has been set */
+    FLAG_HIDDENHOST,                /**< user's host is hidden */
+    FLAG_FAKEHOST,                  /**< user has a fakehost */
+    FLAG_NOCHAN,                    /**< hide user's channels for non-opers */
+    FLAG_NOIDLE,                    /**< hide user's idle time for non-opers */
+    FLAG_XTRAOP,                    /**< allow overriding +k */
+    FLAG_NETSERV,                   /**< mark as service; no special rights */
+    FLAG_HIDDENOPER,                /**< mark as hidden oper */
+    FLAG_OVERRIDECC,                /**< can override chanmodes +cCN */
+    FLAG_SSL,                       /**< SSL user */
+    FLAG_WEBIRC,                    /**< Is a WebIRC client with spoofed host/ip */
+    FLAG_SEE_IDLETIME,              /**< Can see idletime of +I users. */
+       FLAG_SECURITY_SERV,             /**< Securityflag, that can only be set by IAuth */
+    FLAG_LAST_FLAG,                 /**< number of flags */
+    FLAG_LOCAL_UMODES = FLAG_LOCOP, /**< First local mode flag */
+    FLAG_GLOBAL_UMODES = FLAG_OPER  /**< First global mode flag */
+  };
+
+/** Declare flagset type for operator privileges. */
+DECLARE_FLAGSET(Privs, PRIV_LAST_PRIV);
+/** Declare flagset type for user flags. */
+DECLARE_FLAGSET(Flags, FLAG_LAST_FLAG);
+
+#include "capab.h" /* client capabilities */
+
+/** Represents a local connection.
+ * This contains a lot of stuff irrelevant to server connections, but
+ * those are so rare as to not be worth special-casing.
+ */
+struct Connection
+{
+  unsigned long       con_magic;     /**< magic number */
+  struct Connection*  con_next;      /**< Next connection with queued data */
+  struct Connection** con_prev_p;    /**< What points to us */
+  struct Client*      con_client;    /**< Client associated with connection */
+  unsigned int        con_count;     /**< Amount of data in buffer */
+  int                 con_freeflag;  /**< indicates if connection can be freed */
+  int                 con_error;     /**< last socket level error for client */
+  int                 con_sentalong; /**< sentalong marker for connection */
+  unsigned int        con_snomask;   /**< mask for server messages */
+  time_t              con_nextnick;  /**< Next time a nick change is allowed */
+  time_t              con_nexttarget;/**< Next time a target change is allowed */
+  time_t              con_lasttime;  /**< Last time data read from socket */
+  time_t              con_since;     /**< Last time we accepted a command */
+  struct MsgQ         con_sendQ;     /**< Outgoing message queue */
+  struct DBuf         con_recvQ;     /**< Incoming data yet to be parsed */
+  unsigned int        con_sendM;     /**< Stats: protocol messages sent */
+  unsigned int        con_receiveM;  /**< Stats: protocol messages received */
+  uint64_t            con_sendB;     /**< Bytes sent. */
+  uint64_t            con_receiveB;  /**< Bytes received. */
+  struct Listener*    con_listener;  /**< Listening socket which we accepted
+                                        from. */
+  struct SLink*       con_confs;     /**< Associated configuration records. */
+  HandlerType         con_handler;   /**< Message index into command table
+                                        for parsing. */
+  struct ListingArgs* con_listing;   /**< Current LIST status. */
+  unsigned int        con_max_sendq; /**< cached max send queue for client */
+  unsigned int        con_ping_freq; /**< cached ping freq */
+  unsigned short      con_lastsq;    /**< # 2k blocks when sendqueued
+                                        called last. */
+  unsigned char       con_targets[MAXTARGETS]; /**< Hash values of
+                                                 current targets. */
+  char con_sock_ip[SOCKIPLEN + 1];   /**< Remote IP address as a string. */
+  char con_real_sock_ip[SOCKIPLEN + 1]; /**< Unspoofed ip address as a string. */
+  char con_sockhost[HOSTLEN + 1];    /**< This is the host name from
+                                        the socket and after which the
+                                        connection was accepted. */
+  char con_real_sockhost[HOSTLEN + 1]; /**< Unspoofed host name from the socket. */
+  char con_passwd[PASSWDLEN + 1];    /**< Password given by user. */
+  char con_buffer[BUFSIZE];          /**< Incoming message buffer; or
+                                        the error that caused this
+                                        clients socket to close. */
+  struct Socket       con_socket;    /**< socket descriptor for
+                                      client */
+  struct Timer        con_proc;      /**< process latent messages from
+                                      client */
+  struct Privs        con_privs;     /**< Oper privileges */
+  struct CapSet       con_capab;     /**< Client capabilities (from us) */
+  struct CapSet       con_active;    /**< Active capabilities (to us) */
+  struct AuthRequest* con_auth;      /**< Auth request for client */
+};
+
+/** Magic constant to identify valid Connection structures. */
+#define CONNECTION_MAGIC 0x12f955f3
+
+/** Represents a client anywhere on the network. */
+struct Client {
+  unsigned long  cli_magic;       /**< magic number */
+  struct Client* cli_next;        /**< link in GlobalClientList */
+  struct Client* cli_prev;        /**< link in GlobalClientList */
+  struct Client* cli_hnext;       /**< link in hash table bucket or this */
+  struct Connection* cli_connect; /**< Connection structure associated with us */
+  struct User*   cli_user;        /**< Defined if this client is a user */
+  struct Server* cli_serv;        /**< Defined if this client is a server */
+  struct Whowas* cli_whowas;      /**< Pointer to ww struct to be freed on quit */
+  char cli_webirc[NICKLEN + 1];   /**< Contains the name of the WebIRC block */
+  char           cli_yxx[4];      /**< Numeric Nick: YY if this is a
+                                     server, XXX if this is a user */
+  unsigned int maxchans;
+  char cli_connclass[NICKLEN + 1];
+  time_t         cli_firsttime;   /**< time client was created */
+  time_t         cli_lastnick;    /**< TimeStamp on nick */
+  int            cli_marker;      /**< /who processing marker */
+  struct Flags   cli_flags;       /**< client flags */
+  unsigned int   cli_hopcount;    /**< number of servers to this 0 = local */
+  struct irc_in_addr cli_ip;      /**< Real IP of client */
+  struct irc_in_addr cli_real_ip; /**< Unspoofed ip of the client. */
+  short          cli_status;      /**< Client type */
+  char cli_name[HOSTLEN + 1];     /**< Unique name of the client, nick or host */
+  char cli_username[USERLEN + 1]; /**< Username determined by ident lookup */
+  char cli_info[REALLEN + 1];     /**< Free form additional client information */
+};
+
+/** Magic constant to identify valid Client structures. */
+#define CLIENT_MAGIC 0x4ca08286
+
+/** Verify that a client is valid. */
+#define cli_verify(cli)                ((cli)->cli_magic == CLIENT_MAGIC)
+/** Get client's magic number. */
+#define cli_magic(cli)         ((cli)->cli_magic)
+/** Get global next client. */
+#define cli_next(cli)          ((cli)->cli_next)
+/** Get global previous client. */
+#define cli_prev(cli)          ((cli)->cli_prev)
+/** Get next client in hash bucket chain. */
+#define cli_hnext(cli)         ((cli)->cli_hnext)
+/** Get connection associated with client. */
+#define cli_connect(cli)       ((cli)->cli_connect)
+/** Get local client that links us to \a cli. */
+#define cli_from(cli)          con_client(cli_connect(cli))
+/** Get User structure for client, if client is a user. */
+#define cli_user(cli)          ((cli)->cli_user)
+/** Get Server structure for client, if client is a server. */
+#define cli_serv(cli)          ((cli)->cli_serv)
+/** Get Whowas link for client. */
+#define cli_whowas(cli)                ((cli)->cli_whowas)
+/** Get WebIRC block name for client. */
+#define cli_webirc(cli)                ((cli)->cli_webirc)
+/** Get ConnectionClass. */
+#define cli_connclass(cli)             ((cli)->cli_connclass)
+/** Get client numnick. */
+#define cli_yxx(cli)           ((cli)->cli_yxx)
+/** Get time we last read data from the client socket. */
+#define cli_lasttime(cli)      con_lasttime(cli_connect(cli))
+/** Get time we last parsed something from the client. */
+#define cli_since(cli)         con_since(cli_connect(cli))
+/** Get time client was created. */
+#define cli_firsttime(cli)     ((cli)->cli_firsttime)
+/** Get time client last changed nickname. */
+#define cli_lastnick(cli)      ((cli)->cli_lastnick)
+/** Get WHO marker for client. */
+#define cli_marker(cli)                ((cli)->cli_marker)
+/** Get flags flagset for client. */
+#define cli_flags(cli)         ((cli)->cli_flags)
+/** Get hop count to client. */
+#define cli_hopcount(cli)      ((cli)->cli_hopcount)
+/** Get client IP address. */
+#define cli_ip(cli)            ((cli)->cli_ip)
+/** Get unspoofed client IP address. */
+#define cli_real_ip(cli)               ((cli)->cli_real_ip)
+/** Get status bitmask for client. */
+#define cli_status(cli)                ((cli)->cli_status)
+/** Return non-zero if the client is local. */
+#define cli_local(cli)          (cli_from(cli) == cli)
+/** Get oper privileges for client. */
+#define cli_privs(cli)         con_privs(cli_connect(cli))
+/** Get client capabilities for client */
+#define cli_capab(cli)         con_capab(cli_connect(cli))
+/** Get active client capabilities for client */
+#define cli_active(cli)                con_active(cli_connect(cli))
+/** Get client name. */
+#define cli_name(cli)          ((cli)->cli_name)
+/** Get client username (ident). */
+#define cli_username(cli)      ((cli)->cli_username)
+/** Get client realname (information field). */
+#define cli_info(cli)          ((cli)->cli_info)
+
+/** Get number of incoming bytes queued for client. */
+#define cli_count(cli)         con_count(cli_connect(cli))
+/** Get file descriptor for sending in client's direction. */
+#define cli_fd(cli)            con_fd(cli_connect(cli))
+/** Get free flags for the client's connection. */
+#define cli_freeflag(cli)      con_freeflag(cli_connect(cli))
+/** Get last error code for the client's connection. */
+#define cli_error(cli)         con_error(cli_connect(cli))
+/** Get server notice mask for the client. */
+#define cli_snomask(cli)       con_snomask(cli_connect(cli))
+/** Get next time a nick change is allowed for the client. */
+#define cli_nextnick(cli)      con_nextnick(cli_connect(cli))
+/** Get next time a target change is allowed for the client. */
+#define cli_nexttarget(cli)    con_nexttarget(cli_connect(cli))
+/** Get SendQ for client. */
+#define cli_sendQ(cli)         con_sendQ(cli_connect(cli))
+/** Get RecvQ for client. */
+#define cli_recvQ(cli)         con_recvQ(cli_connect(cli))
+/** Get count of messages sent to client. */
+#define cli_sendM(cli)         con_sendM(cli_connect(cli))
+/** Get number of messages received from client. */
+#define cli_receiveM(cli)      con_receiveM(cli_connect(cli))
+/** Get number of bytes (modulo 1024) sent to client. */
+#define cli_sendB(cli)         con_sendB(cli_connect(cli))
+/** Get number of bytes (modulo 1024) received from client. */
+#define cli_receiveB(cli)      con_receiveB(cli_connect(cli))
+/** Get listener that accepted the client's connection. */
+#define cli_listener(cli)      con_listener(cli_connect(cli))
+/** Get list of attached conf lines. */
+#define cli_confs(cli)         con_confs(cli_connect(cli))
+/** Get handler type for client. */
+#define cli_handler(cli)       con_handler(cli_connect(cli))
+/** Get LIST status for client. */
+#define cli_listing(cli)       con_listing(cli_connect(cli))
+/** Get cached max SendQ for client. */
+#define cli_max_sendq(cli)     con_max_sendq(cli_connect(cli))
+/** Get ping frequency for client. */
+#define cli_ping_freq(cli)     con_ping_freq(cli_connect(cli))
+/** Get lastsq for client's connection. */
+#define cli_lastsq(cli)                con_lastsq(cli_connect(cli))
+/** Get the array of current targets for the client.  */
+#define cli_targets(cli)       con_targets(cli_connect(cli))
+/** Get the string form of the client's IP address. */
+#define cli_sock_ip(cli)       con_sock_ip(cli_connect(cli))
+/** Get the unspoofed string form of the client's IP address. */
+#define cli_real_sock_ip(cli)  con_real_sock_ip(cli_connect(cli))
+/** Get the resolved hostname for the client. */
+#define cli_sockhost(cli)      con_sockhost(cli_connect(cli))
+/** Get the unspoofed resolved hostname for the client. */
+#define cli_real_sockhost(cli) con_real_sockhost(cli_connect(cli))
+/** Get the client's password. */
+#define cli_passwd(cli)                con_passwd(cli_connect(cli))
+/** Get the unprocessed input buffer for a client's connection.  */
+#define cli_buffer(cli)                con_buffer(cli_connect(cli))
+/** Get the Socket structure for sending to a client. */
+#define cli_socket(cli)                con_socket(cli_connect(cli))
+/** Get Timer for processing waiting messages from the client. */
+#define cli_proc(cli)          con_proc(cli_connect(cli))
+/** Get auth request for client. */
+#define cli_auth(cli)          con_auth(cli_connect(cli))
+/** Get sentalong marker for client. */
+#define cli_sentalong(cli)      con_sentalong(cli_connect(cli))
+
+/** Verify that a connection is valid. */
+#define con_verify(con)                ((con)->con_magic == CONNECTION_MAGIC)
+/** Get connection's magic number. */
+#define con_magic(con)         ((con)->con_magic)
+/** Get global next connection. */
+#define con_next(con)          ((con)->con_next)
+/** Get global previous connection. */
+#define con_prev_p(con)                ((con)->con_prev_p)
+/** Get locally connected client for connection. */
+#define con_client(con)                ((con)->con_client)
+/** Get number of unprocessed data bytes from connection. */
+#define con_count(con)         ((con)->con_count)
+/** Get file descriptor for connection. */
+#define con_fd(con)            s_fd(&(con)->con_socket)
+/** Get freeable flags for connection. */
+#define con_freeflag(con)      ((con)->con_freeflag)
+/** Get last error code on connection. */
+#define con_error(con)         ((con)->con_error)
+/** Get sentalong marker for connection. */
+#define con_sentalong(con)      ((con)->con_sentalong)
+/** Get server notice mask for connection. */
+#define con_snomask(con)       ((con)->con_snomask)
+/** Get next nick change time for connection. */
+#define con_nextnick(con)      ((con)->con_nextnick)
+/** Get next new target time for connection. */
+#define con_nexttarget(con)    ((con)->con_nexttarget)
+/** Get last time we read from the connection. */
+#define con_lasttime(con)       ((con)->con_lasttime)
+/** Get last time we accepted a command from the connection. */
+#define con_since(con)          ((con)->con_since)
+/** Get SendQ for connection. */
+#define con_sendQ(con)         ((con)->con_sendQ)
+/** Get RecvQ for connection. */
+#define con_recvQ(con)         ((con)->con_recvQ)
+/** Get number of messages sent to connection. */
+#define con_sendM(con)         ((con)->con_sendM)
+/** Get number of messages received from connection. */
+#define con_receiveM(con)      ((con)->con_receiveM)
+/** Get number of bytes (modulo 1024) sent to connection. */
+#define con_sendB(con)         ((con)->con_sendB)
+/** Get number of bytes (modulo 1024) received from connection. */
+#define con_receiveB(con)      ((con)->con_receiveB)
+/** Get listener that accepted the connection. */
+#define con_listener(con)      ((con)->con_listener)
+/** Get list of ConfItems attached to the connection. */
+#define con_confs(con)         ((con)->con_confs)
+/** Get command handler for the connection. */
+#define con_handler(con)       ((con)->con_handler)
+/** Get the LIST status for the connection. */
+#define con_listing(con)       ((con)->con_listing)
+/** Get the maximum permitted SendQ size for the connection. */
+#define con_max_sendq(con)     ((con)->con_max_sendq)
+/** Get the ping frequency for the connection. */
+#define con_ping_freq(con)     ((con)->con_ping_freq)
+/** Get the lastsq for the connection. */
+#define con_lastsq(con)                ((con)->con_lastsq)
+/** Get the current targets array for the connection. */
+#define con_targets(con)       ((con)->con_targets)
+/** Get the string-formatted IP address for the connection. */
+#define con_sock_ip(con)       ((con)->con_sock_ip)
+/** Get the unspoofed string-formatted IP address for the connection. */
+#define con_real_sock_ip(con)  ((con)->con_real_sock_ip)
+/** Get the resolved hostname for the connection. */
+#define con_sockhost(con)      ((con)->con_sockhost)
+/** Get the unspoofed resolved hostname for the connection. */
+#define con_real_sockhost(con) ((con)->con_real_sockhost)
+/** Get the password sent by the remote end of the connection.  */
+#define con_passwd(con)                ((con)->con_passwd)
+/** Get the buffer of unprocessed incoming data from the connection. */
+#define con_buffer(con)                ((con)->con_buffer)
+/** Get the Socket for the connection. */
+#define con_socket(con)                ((con)->con_socket)
+/** Get the Timer for processing more data from the connection. */
+#define con_proc(con)          ((con)->con_proc)
+/** Get the oper privilege set for the connection. */
+#define con_privs(con)          (&(con)->con_privs)
+/** Get the peer's capabilities for the connection. */
+#define con_capab(con)          (&(con)->con_capab)
+/** Get the active capabilities for the connection. */
+#define con_active(con)         (&(con)->con_active)
+/** Get the auth request for the connection. */
+#define con_auth(con)          ((con)->con_auth)
+
+#define STAT_CONNECTING         0x001 /**< connecting to another server */
+#define STAT_HANDSHAKE          0x002 /**< pass - server sent */
+#define STAT_ME                 0x004 /**< this server */
+#define STAT_UNKNOWN            0x008 /**< unidentified connection */
+#define STAT_UNKNOWN_USER       0x010 /**< connection on a client port */
+#define STAT_UNKNOWN_SERVER     0x020 /**< connection on a server port */
+#define STAT_SERVER             0x040 /**< fully registered server */
+#define STAT_USER               0x080 /**< fully registered user */
+
+/*
+ * status macros.
+ */
+/** Return non-zero if the client is registered. */
+#define IsRegistered(x)         (cli_status(x) & (STAT_SERVER | STAT_USER))
+/** Return non-zero if the client is an outbound connection that is
+ * still connecting. */
+#define IsConnecting(x)         (cli_status(x) == STAT_CONNECTING)
+/** Return non-zero if the client is an outbound connection that has
+ * sent our password. */
+#define IsHandshake(x)          (cli_status(x) == STAT_HANDSHAKE)
+/** Return non-zero if the client is this server. */
+#define IsMe(x)                 (cli_status(x) == STAT_ME)
+/** Return non-zero if the client has not yet registered. */
+#define IsUnknown(x)            (cli_status(x) & \
+        (STAT_UNKNOWN | STAT_UNKNOWN_USER | STAT_UNKNOWN_SERVER))
+/** Return non-zero if the client is an unregistered connection on a
+ * server port. */
+#define IsServerPort(x)         (cli_status(x) == STAT_UNKNOWN_SERVER )
+/** Return non-zero if the client is an unregistered connection on a
+ * user port. */
+#define IsUserPort(x)           (cli_status(x) == STAT_UNKNOWN_USER )
+/** Return non-zero if the client is a real client connection. */
+#define IsClient(x)             (cli_status(x) & \
+        (STAT_HANDSHAKE | STAT_ME | STAT_UNKNOWN |\
+         STAT_UNKNOWN_USER | STAT_UNKNOWN_SERVER | STAT_SERVER | STAT_USER))
+/** Return non-zero if the client ignores flood limits. */
+#define IsTrusted(x)            (cli_status(x) & \
+        (STAT_CONNECTING | STAT_HANDSHAKE | STAT_ME | STAT_SERVER))
+/** Return non-zero if the client is a registered server. */
+#define IsServer(x)             (cli_status(x) == STAT_SERVER)
+/** Return non-zero if the client is a registered user. */
+#define IsUser(x)               (cli_status(x) == STAT_USER)
+
+
+/** Mark a client with STAT_CONNECTING. */
+#define SetConnecting(x)        (cli_status(x) = STAT_CONNECTING)
+/** Mark a client with STAT_HANDSHAKE. */
+#define SetHandshake(x)         (cli_status(x) = STAT_HANDSHAKE)
+/** Mark a client with STAT_SERVER. */
+#define SetServer(x)            (cli_status(x) = STAT_SERVER)
+/** Mark a client with STAT_ME. */
+#define SetMe(x)                (cli_status(x) = STAT_ME)
+/** Mark a client with STAT_USER. */
+#define SetUser(x)              (cli_status(x) = STAT_USER)
+
+/** Return non-zero if a client is directly connected to me. */
+#define MyConnect(x)    (cli_from(x) == (x))
+/** Return non-zero if a client is a locally connected user. */
+#define MyUser(x)       (MyConnect(x) && IsUser(x))
+/** Return non-zero if a client is a locally connected IRC operator. */
+#define MyOper(x)       (MyConnect(x) && IsOper(x))
+/** Return protocol version used by a server. */
+#define Protocol(x)     ((cli_serv(x))->prot)
+
+/*
+ * flags macros
+ */
+/** Set a flag in a client's flags. */
+#define SetFlag(cli, flag)  FlagSet(&cli_flags(cli), flag)
+/** Clear a flag from a client's flags. */
+#define ClrFlag(cli, flag)  FlagClr(&cli_flags(cli), flag)
+/** Return non-zero if a flag is set in a client's flags. */
+#define HasFlag(cli, flag)  FlagHas(&cli_flags(cli), flag)
+
+/** Return non-zero if the client is an IRC operator (global or local). */
+#define IsAnOper(x)             (IsOper(x) || IsLocOp(x))
+/** Return non-zero if the client's connection is blocked. */
+#define IsBlocked(x)            HasFlag(x, FLAG_BLOCKED)
+/** Return non-zero if the client's connection is still being burst. */
+#define IsBurst(x)              HasFlag(x, FLAG_BURST)
+/** Return non-zero if we have received the peer's entire burst but
+ * not their EOB ack. */
+#define IsBurstAck(x)           HasFlag(x, FLAG_BURST_ACK)
+/** Return non-zero if we are still bursting to the client. */
+#define IsBurstOrBurstAck(x)    (HasFlag(x, FLAG_BURST) || HasFlag(x, FLAG_BURST_ACK))
+/** Return non-zero if the client has set mode +k (channel service). */
+#define IsChannelService(x)     HasFlag(x, FLAG_CHSERV)
+/** Return non-zero if the client's socket is disconnected. */
+#define IsDead(x)               HasFlag(x, FLAG_DEADSOCKET)
+/** Return non-zero if the client has set mode +d (deaf). */
+#define IsDeaf(x)               HasFlag(x, FLAG_DEAF)
+/** Return non-zero if the client has been IP-checked for clones. */
+#define IsIPChecked(x)          HasFlag(x, FLAG_IPCHECK)
+/** Return non-zero if we have received an ident response for the client. */
+#define IsIdented(x)            HasFlag(x, FLAG_GOTID)
+/** Return non-zero if the client has set mode +i (invisible). */
+#define IsInvisible(x)          HasFlag(x, FLAG_INVISIBLE)
+/** Return non-zero if the client caused a net.burst. */
+#define IsJunction(x)           HasFlag(x, FLAG_JUNCTION)
+/** Return non-zero if the client has set mode +O (local operator) locally. */
+#define IsLocOp(x)              (MyUser(x) && HasFlag(x, FLAG_LOCOP))
+/** Return non-zero if the client has set mode +o (global operator). */
+#define IsOper(x)               HasFlag(x, FLAG_OPER)
+/** Return non-zero if the client has an active UDP ping request. */
+#define IsUPing(x)              HasFlag(x, FLAG_UPING)
+/** Return non-zero if the client has no '\n' in its buffer. */
+#define NoNewLine(x)            HasFlag(x, FLAG_NONL)
+/** Return non-zero if the client has set mode +g (debugging). */
+#define SendDebug(x)            HasFlag(x, FLAG_DEBUG)
+/** Return non-zero if the client has set mode +s (server notices). */
+#define SendServNotice(x)       HasFlag(x, FLAG_SERVNOTICE)
+/** Return non-zero if the client has set mode +w (wallops). */
+#define SendWallops(x)          HasFlag(x, FLAG_WALLOP)
+/** Return non-zero if the client claims to be a hub. */
+#define IsHub(x)                HasFlag(x, FLAG_HUB)
+/** Return non-zero if the client understands IPv6 addresses in P10. */
+#define IsIPv6(x)               HasFlag(x, FLAG_IPV6)
+/** Return non-zero if the client claims to be a services server. */
+#define IsService(x)            HasFlag(x, FLAG_SERVICE)
+/** Return non-zero if the client claims to be a master server. */
+#define IsMaster(x)            HasFlag(x, FLAG_MASTER)
+/** Return non-zero if the client has an account stamp. */
+#define IsAccount(x)            HasFlag(x, FLAG_ACCOUNT)
+/** Return non-zero if the client has set mode +x (hidden host). */
+#define IsHiddenHost(x)         HasFlag(x, FLAG_HIDDENHOST)
+/** Return non-zero if the client has an active PING request. */
+#define IsPingSent(x)           HasFlag(x, FLAG_PINGSENT)
+/** Return non-zero if the client's channels are hidden. */
+#define IsNoChan(x)             HasFlag(x, FLAG_NOCHAN)
+/** Return non-zero if the client's idle time is hidden. */
+#define IsNoIdle(x)             HasFlag(x, FLAG_NOIDLE)
+/** Return non-zero if the client is an extra op. */
+#define IsXtraOp(x)             HasFlag(x, FLAG_XTRAOP)
+/** Return non-zero if the client is a network service. */
+#define IsNetServ(x)            HasFlag(x, FLAG_NETSERV)
+/** Return non-zero if the client is an hidden oper. */
+#define IsHiddenOper(x)         HasFlag(x, FLAG_HIDDENOPER)
+/** Return non-zero if the client has set umode +c. */
+#define IsOverrideCC(x)         HasFlag(x, FLAG_OVERRIDECC)
+/** Return non-zero if the client is connected via SSL. */
+#define IsSSL(x)                HasFlag(x, FLAG_SSL)
+/** Return non-zero if the client is an WebIRC user with spoofed host/ip. */
+#define IsWebIRC(x)             HasFlag(x, FLAG_WEBIRC)
+/** Return non-zero if the client can see idletime of +I users. */
+#define IsSeeIdletime(x)        HasFlag(x, FLAG_SEE_IDLETIME)
+#define IsSecurityServ(x)        HasFlag(x, FLAG_SECURITY_SERV)
+/** Return non-zero if the client has a fakehost. */
+#define IsFakeHost(x)           HasFlag(x, FLAG_FAKEHOST)
+
+/** Return non-zero if the client has operator or server privileges. */
+#define IsPrivileged(x)         (IsAnOper(x) || IsServer(x))
+/** Return non-zero if the client's host is hidden. */
+#define HasHiddenHost(x)        (IsHiddenHost(x) && (IsAccount(x) || IsFakeHost(x)))
+
+/** Mark a client as having an in-progress net.burst. */
+#define SetBurst(x)             SetFlag(x, FLAG_BURST)
+/** Mark a client as being between EOB and EOB ACK. */
+#define SetBurstAck(x)          SetFlag(x, FLAG_BURST_ACK)
+/** Mark a client as having mode +k (channel service). */
+#define SetChannelService(x)    SetFlag(x, FLAG_CHSERV)
+/** Mark a client as having mode +d (deaf). */
+#define SetDeaf(x)              SetFlag(x, FLAG_DEAF)
+/** Mark a client as having mode +g (debugging). */
+#define SetDebug(x)             SetFlag(x, FLAG_DEBUG)
+/** Mark a client as having ident looked up. */
+#define SetGotId(x)             SetFlag(x, FLAG_GOTID)
+/** Mark a client as being IP-checked. */
+#define SetIPChecked(x)         SetFlag(x, FLAG_IPCHECK)
+/** Mark a client as having mode +i (invisible). */
+#define SetInvisible(x)         SetFlag(x, FLAG_INVISIBLE)
+/** Mark a client as causing a net.join. */
+#define SetJunction(x)          SetFlag(x, FLAG_JUNCTION)
+/** Mark a client as having mode +O (local operator). */
+#define SetLocOp(x)             SetFlag(x, FLAG_LOCOP)
+/** Mark a client as having mode +o (global operator). */
+#define SetOper(x)              SetFlag(x, FLAG_OPER)
+/** Mark a client as having a pending UDP ping. */
+#define SetUPing(x)             SetFlag(x, FLAG_UPING)
+/** Mark a client as having mode +w (wallops). */
+#define SetWallops(x)           SetFlag(x, FLAG_WALLOP)
+/** Mark a client as having mode +s (server notices). */
+#define SetServNotice(x)        SetFlag(x, FLAG_SERVNOTICE)
+/** Mark a client as being a hub server. */
+#define SetHub(x)               SetFlag(x, FLAG_HUB)
+/** Mark a client as being an IPv6-grokking server. */
+#define SetIPv6(x)              SetFlag(x, FLAG_IPV6)
+/** Mark a client as being a services server. */
+#define SetService(x)           SetFlag(x, FLAG_SERVICE)
+/** Mark a client as being a master server. */
+#define SetMaster(x)           SetFlag(x, FLAG_MASTER)
+/** Mark a client as having an account stamp. */
+#define SetAccount(x)           SetFlag(x, FLAG_ACCOUNT)
+/** Mark a client as having mode +x (hidden host). */
+#define SetHiddenHost(x)        SetFlag(x, FLAG_HIDDENHOST)
+/** Mark a client as having a fakehost. */
+#define SetFakeHost(x)          SetFlag(x, FLAG_FAKEHOST)
+/** Mark a client as having a pending PING. */
+#define SetPingSent(x)          SetFlag(x, FLAG_PINGSENT)
+/** Mark a client as having mode +n. */
+#define SetNoChan(x)            SetFlag(x, FLAG_NOCHAN)
+/** Mark a client as having mode +I. */
+#define SetNoIdle(x)            SetFlag(x, FLAG_NOIDLE)
+/** Mark a client as having mode +X. */
+#define SetXtraOp(x)            SetFlag(x, FLAG_XTRAOP)
+/** Mark a client as having mode +S. */
+#define SetNetServ(x)           SetFlag(x, FLAG_NETSERV)
+/** Mark a client as having mode +H. */
+#define SetHiddenOper(x)        SetFlag(x, FLAG_HIDDENOPER)
+/** Mark a client as having umode +c. */
+#define SetOverrideCC(x)        SetFlag(x, FLAG_OVERRIDECC)
+/** Mark a client as being connected via SSL. */
+#define SetSSL(x)               SetFlag(x, FLAG_SSL)
+/** Mark a client as being an WebIRC user with spoofed host/ip. */
+#define SetWebIRC(x)            SetFlag(x, FLAG_WEBIRC)
+/** Mark a client as being able to see idletime of +I users. */
+#define SetSeeIdletime(x)       SetFlag(x, FLAG_SEE_IDLETIME)
+#define SetSecurityServ(x)      SetFlag(x, FLAG_SECURITY_SERV)
+
+/** Return non-zero if \a sptr sees \a acptr as an operator. */
+#define SeeOper(sptr,acptr) ((IsAnOper(acptr) && \
+                            (sptr == acptr || HasPriv(acptr, PRIV_DISPLAY) || HasPriv(sptr, PRIV_SEE_OPERS)) && \
+                            (!IsHiddenOper(acptr) || IsAnOper(sptr))))
+
+/** Clear the client's net.burst in-progress flag. */
+#define ClearBurst(x)           ClrFlag(x, FLAG_BURST)
+/** Clear the client's between EOB and EOB ACK flag. */
+#define ClearBurstAck(x)        ClrFlag(x, FLAG_BURST_ACK)
+/** Remove mode +k (channel service) from the client. */
+#define ClearChannelService(x)  ClrFlag(x, FLAG_CHSERV)
+/** Remove mode +d (deaf) from the client. */
+#define ClearDeaf(x)            ClrFlag(x, FLAG_DEAF)
+/** Remove mode +g (debugging) from the client. */
+#define ClearDebug(x)           ClrFlag(x, FLAG_DEBUG)
+/** Remove the client's IP-checked flag. */
+#define ClearIPChecked(x)       ClrFlag(x, FLAG_IPCHECK)
+/** Remove mode +i (invisible) from the client. */
+#define ClearInvisible(x)       ClrFlag(x, FLAG_INVISIBLE)
+/** Remove mode +O (local operator) from the client. */
+#define ClearLocOp(x)           ClrFlag(x, FLAG_LOCOP)
+/** Remove mode +o (global operator) from the client. */
+#define ClearOper(x)            ClrFlag(x, FLAG_OPER)
+/** Clear the client's pending UDP ping flag. */
+#define ClearUPing(x)           ClrFlag(x, FLAG_UPING)
+/** Remove mode +w (wallops) from the client. */
+#define ClearWallops(x)         ClrFlag(x, FLAG_WALLOP)
+/** Remove mode +s (server notices) from the client. */
+#define ClearServNotice(x)      ClrFlag(x, FLAG_SERVNOTICE)
+/** Remove mode +x (hidden host) from the client. */
+#define ClearHiddenHost(x)      ClrFlag(x, FLAG_HIDDENHOST)
+/** Remove fakehost flag from the flient. */
+#define ClearFakeHost(x)        ClrFlag(x, FLAG_FAKEHOST)
+/** Clear the client's pending PING flag. */
+#define ClearPingSent(x)        ClrFlag(x, FLAG_PINGSENT)
+/** Clear the client's HUB flag. */
+#define ClearHub(x)             ClrFlag(x, FLAG_HUB)
+/** Remove mode +n from the client. */
+#define ClearNoChan(x)          ClrFlag(x, FLAG_NOCHAN)
+/** Remove mode +I from the client. */
+#define ClearNoIdle(x)          ClrFlag(x, FLAG_NOIDLE)
+/** Remove mode +X from the client. */
+#define ClearXtraOp(x)          ClrFlag(x, FLAG_XTRAOP)
+/** Remove mode +S from the client. */
+#define ClearNetServ(x)         ClrFlag(x, FLAG_NETSERV)
+/** Remove mode +H from the client. */
+#define ClearHiddenOper(x)      ClrFlag(x, FLAG_HIDDENOPER)
+/** Remove mode +c from the client. */
+#define ClearOverrideCC(x)      ClrFlag(x, FLAG_OVERRIDECC)
+/** Remove ssl mode from the client. */
+#define ClearSSL(x)             ClrFlag(x, FLAG_SSL)
+/** Remove mode +W (WebIRC user with spoofed host/ip) from the client. */
+#define ClearWebIRC(x)          ClrFlag(x, FLAG_WEBIRC)
+/** Make client no longer being able to see idletime of +I users. */
+#define ClearSeeIdletime(x)     ClrFlag(x, FLAG_SEE_IDLETIME)
+#define ClearSecurityServ(x)    ClrFlag(x, FLAG_SECURITY_SERV)
+
+/* free flags */
+#define FREEFLAG_SOCKET        0x0001  /**< socket needs to be freed */
+#define FREEFLAG_TIMER 0x0002  /**< timer needs to be freed */
+
+/* server notice stuff */
+
+#define SNO_ADD         1       /**< Perform "or" on server notice mask. */
+#define SNO_DEL         2       /**< Perform "and ~x" on server notice mask. */
+#define SNO_SET         3       /**< Set server notice mask. */
+                                /* DON'T CHANGE THESE VALUES ! */
+                                /* THE CLIENTS DEPEND ON IT  ! */
+#define SNO_OLDSNO      0x1     /**< unsorted old messages */
+#define SNO_SERVKILL    0x2     /**< server kills (nick collisions) */
+#define SNO_OPERKILL    0x4     /**< oper kills */
+#define SNO_HACK2       0x8     /**< desyncs */
+#define SNO_HACK3       0x10    /**< temporary desyncs */
+#define SNO_UNAUTH      0x20    /**< unauthorized connections */
+#define SNO_TCPCOMMON   0x40    /**< common TCP or socket errors */
+#define SNO_TOOMANY     0x80    /**< too many connections */
+#define SNO_HACK4       0x100   /**< Uworld actions on channels */
+#define SNO_GLINE       0x200   /**< glines */
+#define SNO_NETWORK     0x400   /**< net join/break, etc */
+#define SNO_IPMISMATCH  0x800   /**< IP mismatches */
+#define SNO_THROTTLE    0x1000  /**< host throttle add/remove notices */
+#define SNO_OLDREALOP   0x2000  /**< old oper-only messages */
+#define SNO_CONNEXIT    0x4000  /**< client connect/exit (ugh) */
+#define SNO_AUTO        0x8000  /**< AUTO G-Lines */
+#define SNO_DEBUG       0x10000 /**< debugging messages (DEBUGMODE only) */
+#define SNO_AUTH        0x20000 /**< IAuth notices */
+
+/** Bitmask of all valid server notice bits. */
+#ifdef DEBUGMODE
+# define SNO_ALL        0x3ffff
+#else
+# define SNO_ALL        0x2ffff
+#endif
+
+/** Server notice bits allowed to normal users. */
+#define SNO_USER        (SNO_ALL & ~SNO_OPER)
+
+/** Server notice bits enabled by default for normal users. */
+#define SNO_DEFAULT (SNO_NETWORK|SNO_OPERKILL|SNO_GLINE)
+/** Server notice bits enabled by default for IRC operators. */
+#define SNO_OPERDEFAULT (SNO_DEFAULT|SNO_HACK2|SNO_HACK4|SNO_THROTTLE|SNO_OLDSNO)
+/** Server notice bits reserved to IRC operators. */
+#define SNO_OPER (SNO_CONNEXIT|SNO_OLDREALOP|SNO_AUTH)
+/** Noisy server notice bits that cause other bits to be cleared during connect. */
+#define SNO_NOISY (SNO_SERVKILL|SNO_UNAUTH)
+
+/** Test whether a privilege has been granted to a client. */
+#define HasPriv(cli, priv)  FlagHas(cli_privs(cli), priv)
+/** Grant a privilege to a client. */
+#define SetPriv(cli, priv)  FlagSet(cli_privs(cli), priv)
+/** Revoke a privilege from a client. */
+#define ClrPriv(cli, priv)  FlagClr(cli_privs(cli), priv)
+
+/** Test whether a client has a capability */
+#define HasCap(cli, cap)    CapHas(cli_capab(cli), (cap))
+/** Test whether a client has the capability active */
+#define CapActive(cli, cap) CapHas(cli_active(cli), (cap))
+
+/** Returns 1 if cptr can see the idletime of acptr. */
+#define HasNoIdlePriv(cptr) (MyUser(cptr) && HasPriv(cptr, PRIV_HIDE_IDLETIME))
+#define CanSeeIdletime(cptr, acptr) ( \
+  (sptr == acptr) || \
+  IsAnOper(cptr) || \
+  (!feature_bool(FEAT_HIS_WHOIS_IDLETIME) && ( \
+    (!IsNoIdle(acptr) || !IsAnOper(acptr)) && \
+    (!IsNoIdle(acptr) || (IsSeeIdletime(cptr) && (!HasNoIdlePriv(acptr) || HasNoIdlePriv(cptr)))) \
+  )))
+
+#define HIDE_IP 0 /**< Do not show IP address in get_client_name() */
+#define SHOW_IP 1 /**< Show ident and IP address in get_client_name() */
+
+extern const char* get_client_name(const struct Client* sptr, int showip);
+extern const char* client_get_default_umode(const struct Client* sptr);
+extern int client_get_ping(const struct Client* local_client);
+extern void client_drop_sendq(struct Connection* con);
+extern void client_add_sendq(struct Connection* con,
+                            struct Connection** con_p);
+extern void client_set_privs(struct Client *client, struct ConfItem *oper);
+extern void client_set_uprivs(struct Client *client, struct ConfItem *aconf);
+extern int client_report_privs(struct Client* to, struct Client* client);
+
+#endif /* INCLUDED_client_h */
+
diff --git a/include/crule.h b/include/crule.h
new file mode 100644 (file)
index 0000000..c61ccdc
--- /dev/null
@@ -0,0 +1,21 @@
+/** @file crule.h
+ * @brief Interfaces and declarations for connection rule checking.
+ * @version $Id: crule.h 1231 2004-10-05 04:21:37Z entrope $
+ */
+#ifndef INCLUDED_crule_h
+#define INCLUDED_crule_h
+
+/*
+ * Proto types
+ */
+
+/*
+ * opaque node pointer
+ */
+struct CRuleNode;
+
+extern void crule_free(struct CRuleNode** elem);
+extern int crule_eval(struct CRuleNode* rule);
+extern struct CRuleNode* crule_parse(const char* rule);
+
+#endif /* INCLUDED_crule_h */
diff --git a/include/dbuf.h b/include/dbuf.h
new file mode 100644 (file)
index 0000000..76b8070
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ * IRC - Internet Relay Chat, include/dbuf.h
+ * Copyright (C) 1990 Markku Savela
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+/** @file
+ * @brief Interfaces and declarations for dealing with data buffers.
+ * @version $Id: dbuf.h 1216 2004-10-05 00:51:56Z entrope $
+ */
+#ifndef INCLUDED_dbuf_h
+#define INCLUDED_dbuf_h
+#ifndef INCLUDED_sys_types_h
+#include <sys/types.h>          /* size_t */
+#define INCLUDED_sys_types_h
+#endif
+
+/*
+ * These two globals should be considered read only
+ */
+extern int DBufAllocCount;
+extern int DBufUsedCount;
+
+struct DBufBuffer;
+
+/** Queue of data chunks. */
+struct DBuf {
+  unsigned int length;          /**< Current number of bytes stored */
+  struct DBufBuffer *head;      /**< First data buffer, if length > 0 */
+  struct DBufBuffer *tail;      /**< Last data buffer, if length > 0 */
+};
+
+/** Return number of bytes in a DBuf. */
+#define DBufLength(dyn) ((dyn)->length)
+
+/** Release the entire content of a DBuf. */
+#define DBufClear(dyn) dbuf_delete((dyn), DBufLength(dyn))
+
+/*
+ * Prototypes
+ */
+extern void dbuf_delete(struct DBuf *dyn, unsigned int length);
+extern int dbuf_put(struct DBuf *dyn, const char *buf, unsigned int length);
+extern const char *dbuf_map(const struct DBuf *dyn, unsigned int *length);
+extern unsigned int dbuf_get(struct DBuf *dyn, char *buf, unsigned int length);
+extern unsigned int dbuf_getmsg(struct DBuf *dyn, char *buf, unsigned int length);
+extern void dbuf_count_memory(size_t *allocated, size_t *used);
+
+
+#endif /* INCLUDED_dbuf_h */
diff --git a/include/destruct_event.h b/include/destruct_event.h
new file mode 100644 (file)
index 0000000..9f7c5ea
--- /dev/null
@@ -0,0 +1,38 @@
+#ifndef INCLUDED_destruct_event_h
+#define INCLUDED_destruct_event_h
+/*
+ * IRC - Internet Relay Chat, include/destruct_event.h
+ * Copyright (C) 2002 Carlo Wood <carlo@alinoe.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+/** @file
+ * @brief Functions for handling timed channel destruction events.
+ * @version $Id: destruct_event.h 1231 2004-10-05 04:21:37Z entrope $
+ */
+
+#ifndef INCLUDED_config_h
+#include "config.h"
+#endif
+#ifndef INCLUDED_channel_h
+#include "channel.h"
+#endif
+
+extern void schedule_destruct_event_1m(struct Channel* chptr);
+extern void schedule_destruct_event_48h(struct Channel* chptr);
+extern void remove_destruct_event(struct Channel* chptr);
+extern void exec_expired_destruct_events(struct Event* ev);
+
+#endif /* INCLUDED_destruct_event_h */
diff --git a/include/fileio.h b/include/fileio.h
new file mode 100644 (file)
index 0000000..b6dee29
--- /dev/null
@@ -0,0 +1,56 @@
+/** @file fileio.h
+ * @brief ANSI FILE* clone API declarations.
+ * @version $Id: fileio.h 1219 2004-10-05 01:45:24Z entrope $
+ */
+#ifndef INCLUDED_fileio_h
+#define INCLUDED_fileio_h
+
+#ifndef INCLUDED_sys_types_h
+#include <sys/types.h>          /* size_t */
+#define INCLUDED_sys_types_h
+#endif
+
+struct stat;
+
+/** A mirror of the ANSI FILE struct, but it works for any
+ * file descriptor. FileBufs are allocated when a file is opened with
+ * fbopen, and they are freed when the file is closed using fbclose.
+ * (Some OSes limit the range of file descriptors in a FILE*, for
+ * example to fit in "char".)
+ */
+typedef struct FileBuf FBFILE;
+
+/*
+ * open a file and return a FBFILE*, see fopen(3)
+ */
+extern FBFILE *fbopen(const char *filename, const char *mode);
+/*
+ * associate a file descriptor with a FBFILE*
+ * if a FBFILE* is associated here it MUST be closed using fbclose
+ * see fdopen(3)
+ */
+extern FBFILE *fdbopen(int fd, const char *mode);
+/*
+ * close a file opened with fbopen, see fclose(3)
+ */
+extern void fbclose(FBFILE * fb);
+/*
+ * return the next character from the file, EOF on end of file
+ * see fgetc(3)
+ */
+extern int fbgetc(FBFILE * fb);
+/*
+ * return next string in a file up to and including the newline character
+ * see fgets(3)
+ */
+extern char *fbgets(char *buf, size_t len, FBFILE * fb);
+/*
+ * write a null terminated string to a file, see fputs(3)
+ */
+extern int fbputs(const char *str, FBFILE * fb);
+/*
+ * return the status of the file associated with fb, see fstat(3)
+ */
+extern int fbstat(struct stat *sb, FBFILE * fb);
+
+#endif /* INCLUDED_fileio_h */
diff --git a/include/gline.h b/include/gline.h
new file mode 100644 (file)
index 0000000..6903ee2
--- /dev/null
@@ -0,0 +1,147 @@
+#ifndef INCLUDED_gline_h
+#define INCLUDED_gline_h
+/*
+ * IRC - Internet Relay Chat, include/gline.h
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ *                    University of Oulu, Computing Center
+ * Copyright (C) 1996 -1997 Carlo Wood
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+/** @file
+ * @brief Structures and APIs for G-line manipulation.
+ * @version $Id: gline.h 1904 2009-02-09 00:03:34Z entrope $
+ */
+#ifndef INCLUDED_sys_types_h
+#include <sys/types.h>
+#define INCLUDED_sys_types_h
+#endif
+
+#ifndef INCLUDED_res_h
+#include "res.h"
+#endif
+
+struct Client;
+struct StatDesc;
+
+#define GLINE_MAX_EXPIRE 31536000 /**< max expire: 1 year */
+
+/** Local state of a G-line. */
+enum GlineLocalState {
+  GLOCAL_GLOBAL,               /**< G-line state unmodified locally. */
+  GLOCAL_ACTIVATED,            /**< G-line state locally activated. */
+  GLOCAL_DEACTIVATED           /**< G-line state locally deactivated. */
+};
+
+/** Description of a G-line. */
+struct Gline {
+  struct Gline *gl_next;       /**< Next G-line in linked list. */
+  struct Gline**gl_prev_p;     /**< Previous pointer to this G-line. */
+  char        *gl_user;        /**< Username mask (or channel/realname mask). */
+  char        *gl_host;        /**< Host portion of mask. */
+  char        *gl_reason;      /**< Reason for G-line. */
+  time_t       gl_expire;      /**< Expiration timestamp. */
+  time_t       gl_lastmod;     /**< Last modification timestamp. */
+  time_t       gl_lifetime;    /**< Record expiration timestamp. */
+  struct irc_in_addr gl_addr;  /**< IP address (for IP-based G-lines). */
+  unsigned char gl_bits;       /**< Bits in gl_addr used in the mask. */
+  unsigned int gl_flags;       /**< G-line status flags. */
+  enum GlineLocalState gl_state;/**< G-line local state. */
+};
+
+/** Action to perform on a G-line. */
+enum GlineAction {
+  GLINE_ACTIVATE,              /**< G-line should be activated. */
+  GLINE_DEACTIVATE,            /**< G-line should be deactivated. */
+  GLINE_LOCAL_ACTIVATE,                /**< G-line should be locally activated. */
+  GLINE_LOCAL_DEACTIVATE,      /**< G-line should be locally deactivated. */
+  GLINE_MODIFY                 /**< G-line should be modified. */
+};
+
+#define GLINE_ACTIVE   0x0001  /**< G-line is active. */
+#define GLINE_IPMASK   0x0002  /**< gl_addr and gl_bits fields are valid. */
+#define GLINE_BADCHAN  0x0004  /**< G-line prohibits users from joining a channel. */
+#define GLINE_LOCAL    0x0008  /**< G-line only applies to this server. */
+#define GLINE_ANY      0x0010  /**< Search flag: Find any G-line. */
+#define GLINE_FORCE    0x0020  /**< Override normal limits on G-lines. */
+#define GLINE_EXACT    0x0040  /**< Exact match only (no wildcards). */
+#define GLINE_LDEACT   0x0080  /**< Locally deactivated. */
+#define GLINE_GLOBAL   0x0100  /**< Find only global G-lines. */
+#define GLINE_LASTMOD  0x0200  /**< Find only G-lines with non-zero lastmod. */
+#define GLINE_OPERFORCE        0x0400  /**< Oper forcing G-line to be set. */
+#define GLINE_REALNAME  0x0800  /**< G-line matches only the realname field. */
+
+#define GLINE_EXPIRE   0x1000  /**< Expiration time update */
+#define GLINE_LIFETIME 0x2000  /**< Record lifetime update */
+#define GLINE_REASON   0x4000  /**< Reason update */
+
+/** Controllable flags that can be set on an actual G-line. */
+#define GLINE_MASK     (GLINE_ACTIVE | GLINE_BADCHAN | GLINE_LOCAL | GLINE_REALNAME)
+/** Mask for G-line activity flags. */
+#define GLINE_ACTMASK  (GLINE_ACTIVE | GLINE_LDEACT)
+
+/** Mask for G-line update flags. */
+#define GLINE_UPDATE   (GLINE_EXPIRE | GLINE_LIFETIME | GLINE_REASON)
+
+/** Test whether \a g is active. */
+#define GlineIsActive(g)       ((((g)->gl_flags & GLINE_ACTIVE) &&       \
+                                 (g)->gl_state != GLOCAL_DEACTIVATED) || \
+                                (g)->gl_state == GLOCAL_ACTIVATED)
+/** Test whether \a g is remotely (globally) active. */
+#define GlineIsRemActive(g)    ((g)->gl_flags & GLINE_ACTIVE)
+/** Test whether \a g is an IP-based G-line. */
+#define GlineIsIpMask(g)       ((g)->gl_flags & GLINE_IPMASK)
+/** Test whether \a g is a realname-based G-line. */
+#define GlineIsRealName(g)      ((g)->gl_flags & GLINE_REALNAME)
+/** Test whether \a g is a BADCHAN. */
+#define GlineIsBadChan(g)      ((g)->gl_flags & GLINE_BADCHAN)
+/** Test whether \a g is local to this server. */
+#define GlineIsLocal(g)                ((g)->gl_flags & GLINE_LOCAL)
+
+/** Return user mask of a G-line. */
+#define GlineUser(g)           ((g)->gl_user)
+/** Return host mask of a G-line. */
+#define GlineHost(g)           ((g)->gl_host)
+/** Return reason/message of a G-line. */
+#define GlineReason(g)         ((g)->gl_reason)
+/** Return last modification time of a G-line. */
+#define GlineLastMod(g)                ((g)->gl_lastmod)
+
+extern int gline_add(struct Client *cptr, struct Client *sptr, char *userhost,
+                    char *reason, time_t expire, time_t lastmod,
+                    time_t lifetime, unsigned int flags);
+extern int gline_activate(struct Client *cptr, struct Client *sptr,
+                         struct Gline *gline, time_t lastmod,
+                         unsigned int flags);
+extern int gline_deactivate(struct Client *cptr, struct Client *sptr,
+                           struct Gline *gline, time_t lastmod,
+                           unsigned int flags);
+extern int gline_modify(struct Client *cptr, struct Client *sptr,
+                       struct Gline *gline, enum GlineAction action,
+                       char *reason, time_t expire, time_t lastmod,
+                       time_t lifetime, unsigned int flags);
+extern int gline_destroy(struct Client *cptr, struct Client *sptr,
+                        struct Gline *gline);
+extern struct Gline *gline_find(char *userhost, unsigned int flags);
+extern struct Gline *gline_lookup(struct Client *cptr, unsigned int flags);
+extern void gline_free(struct Gline *gline);
+extern void gline_burst(struct Client *cptr);
+extern int gline_resend(struct Client *cptr, struct Gline *gline);
+extern int gline_list(struct Client *sptr, char *userhost);
+extern void gline_stats(struct Client *sptr, const struct StatDesc *sd,
+                        char *param);
+extern int gline_memory_count(size_t *gl_size);
+
+#endif /* INCLUDED_gline_h */
diff --git a/include/handlers.h b/include/handlers.h
new file mode 100644 (file)
index 0000000..8d52215
--- /dev/null
@@ -0,0 +1,245 @@
+/*
+ * IRC - Internet Relay Chat, include/handlers.h
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ *                    University of Oulu, Computing Center
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+/** @file
+ * @brief Declarations for all protocol message handler functions.
+ * @version $Id: handlers.h 1347 2005-04-02 02:50:15Z entrope $
+ */
+#ifndef INCLUDED_handlers_h
+#define INCLUDED_handlers_h
+
+/** @page m_functions Protocol Message Handlers
+ *
+ * m_functions execute protocol messages on this server:
+ * int m_func(struct Client* cptr, struct Client* sptr, int parc, char* parv[]);
+ *
+ *    cptr    is always NON-NULL, pointing to a *LOCAL* client
+ *            structure (with an open socket connected!). This
+ *            identifies the physical socket where the message
+ *            originated (or which caused the m_function to be
+ *            executed--some m_functions may call others...).
+ *
+ *    sptr    is the source of the message, defined by the
+ *            prefix part of the message if present. If not
+ *            or prefix not found, then sptr==cptr.
+ *
+ *            (!IsServer(cptr)) => (cptr == sptr), because
+ *            prefixes are taken *only* from servers...
+ *
+ *            (IsServer(cptr))
+ *                    (sptr == cptr) => the message didn't
+ *                    have the prefix.
+ *
+ *                    (sptr != cptr && IsServer(sptr) means
+ *                    the prefix specified servername. (?)
+ *
+ *                    (sptr != cptr && !IsServer(sptr) means
+ *                    that message originated from a remote
+ *                    user (not local).
+ *
+ *
+ *            combining
+ *
+ *            (!IsServer(sptr)) means that, sptr can safely
+ *            taken as defining the target structure of the
+ *            message in this server.
+ *
+ *    *Always* true (if 'parse' and others are working correct):
+ *
+ *    1)      sptr->from == cptr  (note: cptr->from == cptr)
+ *
+ *    2)      MyConnect(sptr) <=> sptr == cptr (e.g. sptr
+ *            *cannot* be a local connection, unless it's
+ *            actually cptr!). [MyConnect(x) should probably
+ *            be defined as (x == x->from) --msa ]
+ *
+ *    parc    number of variable parameter strings (if zero,
+ *            parv is allowed to be NULL)
+ *
+ *    parv    a NULL terminated list of parameter pointers,
+ *
+ *                    parv[0], sender (prefix string), if not present
+ *                            this points to an empty string.
+ *                    parv[1]...parv[parc-1]
+ *                            pointers to additional parameters
+ *                    parv[parc] == NULL, *always*
+ *
+ *            note:   it is guaranteed that parv[0]..parv[parc-1] are all
+ *                    non-NULL pointers.
+ */
+
+struct Client;
+
+extern int m_admin(struct Client*, struct Client*, int, char*[]);
+extern int m_away(struct Client*, struct Client*, int, char*[]);
+extern int m_cap(struct Client*, struct Client*, int, char*[]);
+extern int m_cnotice(struct Client*, struct Client*, int, char*[]);
+extern int m_cprivmsg(struct Client*, struct Client*, int, char*[]);
+extern int m_fakehost(struct Client*, struct Client*, int, char*[]);
+extern int m_gline(struct Client*, struct Client*, int, char*[]);
+extern int m_help(struct Client*, struct Client*, int, char*[]);
+extern int m_ignore(struct Client*, struct Client*, int, char*[]);
+extern int m_info(struct Client*, struct Client*, int, char*[]);
+extern int m_invite(struct Client*, struct Client*, int, char*[]);
+extern int m_ison(struct Client*, struct Client*, int, char*[]);
+extern int m_join(struct Client*, struct Client*, int, char*[]);
+extern int m_jupe(struct Client*, struct Client*, int, char*[]);
+extern int m_kick(struct Client*, struct Client*, int, char*[]);
+extern int m_links(struct Client*, struct Client*, int, char*[]);
+extern int m_links_redirect(struct Client*, struct Client*, int, char*[]);
+extern int m_list(struct Client*, struct Client*, int, char*[]);
+extern int m_lusers(struct Client*, struct Client*, int, char*[]);
+extern int m_map(struct Client*, struct Client*, int, char*[]);
+extern int m_map_redirect(struct Client*, struct Client*, int, char*[]);
+extern int m_mode(struct Client*, struct Client*, int, char*[]);
+extern int m_motd(struct Client*, struct Client*, int, char*[]);
+extern int m_names(struct Client*, struct Client*, int, char*[]);
+extern int m_nick(struct Client*, struct Client*, int, char*[]);
+extern int m_not_oper(struct Client*, struct Client*, int, char*[]);
+extern int m_notice(struct Client*, struct Client*, int, char*[]);
+extern int m_notice(struct Client*, struct Client*, int, char*[]);
+extern int m_oper(struct Client*, struct Client*, int, char*[]);
+extern int m_part(struct Client*, struct Client*, int, char*[]);
+extern int mr_pass(struct Client*, struct Client*, int, char*[]);
+extern int m_ping(struct Client*, struct Client*, int, char*[]);
+extern int m_pong(struct Client*, struct Client*, int, char*[]);
+extern int m_private(struct Client*, struct Client*, int, char*[]);
+extern int m_privmsg(struct Client*, struct Client*, int, char*[]);
+extern int m_privs(struct Client*, struct Client*, int, char*[]);
+extern int m_proto(struct Client*, struct Client*, int, char*[]);
+extern int m_pseudo(struct Client*, struct Client*, int, char*[]);
+extern int m_quit(struct Client*, struct Client*, int, char*[]);
+extern int m_registered(struct Client*, struct Client*, int, char*[]);
+extern int m_silence(struct Client*, struct Client*, int, char*[]);
+extern int m_stats(struct Client*, struct Client*, int, char*[]);
+extern int m_svsnick(struct Client*, struct Client*, int, char*[]);
+extern int m_svsmode(struct Client*, struct Client*, int, char*[]);
+extern int m_svsjoin(struct Client*, struct Client*, int, char*[]);
+extern int m_time(struct Client*, struct Client*, int, char*[]);
+extern int m_topic(struct Client*, struct Client*, int, char*[]);
+extern int m_trace(struct Client*, struct Client*, int, char*[]);
+extern int m_unregistered(struct Client*, struct Client*, int, char*[]);
+extern int m_unsupported(struct Client*, struct Client*, int, char*[]);
+extern int m_user(struct Client*, struct Client*, int, char*[]);
+extern int m_userhost(struct Client*, struct Client*, int, char*[]);
+extern int m_userip(struct Client*, struct Client*, int, char*[]);
+extern int m_version(struct Client*, struct Client*, int, char*[]);
+extern int m_wallchops(struct Client*, struct Client*, int, char*[]);
+extern int m_wallvoices(struct Client*, struct Client*, int, char*[]);
+extern int m_webirc(struct Client*, struct Client*, int, char*[]);
+extern int m_who(struct Client*, struct Client*, int, char*[]);
+extern int m_whois(struct Client*, struct Client*, int, char*[]);
+extern int m_whowas(struct Client*, struct Client*, int, char*[]);
+extern int mo_admin(struct Client*, struct Client*, int, char*[]);
+extern int mo_asll(struct Client*, struct Client*, int, char*[]);
+extern int mo_check(struct Client *, struct Client *, int, char*[]);
+extern int mo_clearmode(struct Client*, struct Client*, int, char*[]);
+extern int mo_close(struct Client*, struct Client*, int, char*[]);
+extern int mo_connect(struct Client*, struct Client*, int, char*[]);
+extern int mo_die(struct Client*, struct Client*, int, char*[]);
+extern int mo_get(struct Client*, struct Client*, int, char*[]);
+extern int mo_gline(struct Client*, struct Client*, int, char*[]);
+extern int mo_info(struct Client*, struct Client*, int, char*[]);
+extern int mo_jupe(struct Client*, struct Client*, int, char*[]);
+extern int mo_kill(struct Client*, struct Client*, int, char*[]);
+extern int mo_notice(struct Client*, struct Client*, int, char*[]);
+extern int mo_oper(struct Client*, struct Client*, int, char*[]);
+extern int mo_opmode(struct Client*, struct Client*, int, char*[]);
+extern int mo_ping(struct Client*, struct Client*, int, char*[]);
+extern int mo_privmsg(struct Client*, struct Client*, int, char*[]);
+extern int mo_rehash(struct Client*, struct Client*, int, char*[]);
+extern int mo_reset(struct Client*, struct Client*, int, char*[]);
+extern int mo_restart(struct Client*, struct Client*, int, char*[]);
+extern int mo_rping(struct Client*, struct Client*, int, char*[]);
+extern int mo_set(struct Client*, struct Client*, int, char*[]);
+extern int mo_settime(struct Client*, struct Client*, int, char*[]);
+extern int mo_squit(struct Client*, struct Client*, int, char*[]);
+extern int mo_stats(struct Client*, struct Client*, int, char*[]);
+extern int mo_trace(struct Client*, struct Client*, int, char*[]);
+extern int mo_uping(struct Client*, struct Client*, int, char*[]);
+extern int mo_version(struct Client*, struct Client*, int, char*[]);
+extern int mo_wallops(struct Client*, struct Client*, int, char*[]);
+extern int mo_wallusers(struct Client*, struct Client*, int, char*[]);
+extern int mr_error(struct Client*, struct Client*, int, char*[]);
+extern int mr_error(struct Client*, struct Client*, int, char*[]);
+extern int mr_pong(struct Client*, struct Client*, int, char*[]);
+extern int mr_server(struct Client*, struct Client*, int, char*[]);
+extern int ms_account(struct Client*, struct Client*, int, char*[]);
+extern int ms_admin(struct Client*, struct Client*, int, char*[]);
+extern int ms_asll(struct Client*, struct Client*, int, char*[]);
+extern int ms_away(struct Client*, struct Client*, int, char*[]);
+extern int ms_burst(struct Client*, struct Client*, int, char*[]);
+extern int ms_clearmode(struct Client*, struct Client*, int, char*[]);
+extern int ms_connect(struct Client*, struct Client*, int, char*[]);
+extern int ms_create(struct Client*, struct Client*, int, char*[]);
+extern int ms_destruct(struct Client*, struct Client*, int, char*[]);
+extern int ms_desynch(struct Client*, struct Client*, int, char*[]);
+extern int ms_end_of_burst(struct Client*, struct Client*, int, char*[]);
+extern int ms_end_of_burst_ack(struct Client*, struct Client*, int, char*[]);
+extern int ms_error(struct Client*, struct Client*, int, char*[]);
+extern int ms_fakehost(struct Client*, struct Client*, int, char*[]);
+extern int ms_fakehost_old(struct Client*, struct Client*, int, char*[]);
+extern int ms_gline(struct Client*, struct Client*, int, char*[]);
+extern int ms_hidehost(struct Client*, struct Client*, int, char*[]);
+extern int ms_info(struct Client*, struct Client*, int, char*[]);
+extern int ms_invite(struct Client*, struct Client*, int, char*[]);
+extern int ms_join(struct Client*, struct Client*, int, char*[]);
+extern int ms_jupe(struct Client*, struct Client*, int, char*[]);
+extern int ms_kick(struct Client*, struct Client*, int, char*[]);
+extern int ms_kill(struct Client*, struct Client*, int, char*[]);
+extern int ms_links(struct Client*, struct Client*, int, char*[]);
+extern int ms_lusers(struct Client*, struct Client*, int, char*[]);
+extern int ms_mode(struct Client*, struct Client*, int, char*[]);
+extern int ms_motd(struct Client*, struct Client*, int, char*[]);
+extern int ms_names(struct Client*, struct Client*, int, char*[]);
+extern int ms_nick(struct Client*, struct Client*, int, char*[]);
+extern int ms_notice(struct Client*, struct Client*, int, char*[]);
+extern int ms_oper(struct Client*, struct Client*, int, char*[]);
+extern int ms_opmode(struct Client*, struct Client*, int, char*[]);
+extern int ms_part(struct Client*, struct Client*, int, char*[]);
+extern int ms_ping(struct Client*, struct Client*, int, char*[]);
+extern int ms_pong(struct Client*, struct Client*, int, char*[]);
+extern int ms_privmsg(struct Client*, struct Client*, int, char*[]);
+extern int ms_privs(struct Client*, struct Client*, int, char*[]);
+extern int ms_quit(struct Client*, struct Client*, int, char*[]);
+extern int ms_rehash(struct Client*, struct Client*, int, char*[]);
+extern int ms_relay(struct Client*, struct Client*, int, char*[]);
+extern int ms_rping(struct Client*, struct Client*, int, char*[]);
+extern int ms_rpong(struct Client*, struct Client*, int, char*[]);
+extern int ms_server(struct Client*, struct Client*, int, char*[]);
+extern int ms_settime(struct Client*, struct Client*, int, char*[]);
+extern int ms_silence(struct Client*, struct Client*, int, char*[]);
+extern int ms_squit(struct Client*, struct Client*, int, char*[]);
+extern int ms_stats(struct Client*, struct Client*, int, char*[]);
+extern int ms_svsmode(struct Client*, struct Client*, int, char*[]);
+extern int ms_svsnick(struct Client*, struct Client*, int, char*[]);
+extern int ms_svsnick_old(struct Client*, struct Client*, int, char*[]);
+extern int ms_svsjoin(struct Client*, struct Client*, int, char*[]);
+extern int ms_topic(struct Client*, struct Client*, int, char*[]);
+extern int ms_trace(struct Client*, struct Client*, int, char*[]);
+extern int ms_uping(struct Client*, struct Client*, int, char*[]);
+extern int ms_version(struct Client*, struct Client*, int, char*[]);
+extern int ms_wallchops(struct Client*, struct Client*, int, char*[]);
+extern int ms_wallops(struct Client*, struct Client*, int, char*[]);
+extern int ms_wallusers(struct Client*, struct Client*, int, char*[]);
+extern int ms_wallvoices(struct Client*, struct Client*, int, char*[]);
+extern int ms_whois(struct Client*, struct Client*, int, char*[]);
+
+#endif /* INCLUDED_handlers_h */
+
diff --git a/include/hash.h b/include/hash.h
new file mode 100644 (file)
index 0000000..987fc78
--- /dev/null
@@ -0,0 +1,95 @@
+/*
+ * IRC - Internet Relay Chat, include/hash.h 
+ * Copyright (C) 1998 by Andrea "Nemesi" Cocito
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+/** @file
+ * @brief Hash table management APIs.
+ * @version $Id: hash.h 1343 2005-03-30 03:48:22Z entrope $
+ */
+
+#ifndef INCLUDED_hash_h
+#define INCLUDED_hash_h
+
+struct Client;
+struct Channel;
+struct StatDesc;
+
+/*
+ * general defines
+ */
+
+/** Size of client and channel hash tables.
+ * Both must be of the same size.
+ */
+#define HASHSIZE                32000
+
+/*
+ * Structures
+ */
+
+/*
+ * Macros for internal use
+ */
+
+/*
+ * Externally visible pseudofunctions (macro interface to internal functions)
+ */
+
+/* Raw calls, expect a core if you pass a NULL or zero-length name */
+/** Search for a channel by name. */
+#define SeekChannel(name)       hSeekChannel((name))
+/** Search for any client by name. */
+#define SeekClient(name)        hSeekClient((name), ~0)
+/** Search for a registered user by name. */
+#define SeekUser(name)          hSeekClient((name), (STAT_USER))
+/** Search for a server by name. */
+#define SeekServer(name)        hSeekClient((name), (STAT_ME | STAT_SERVER))
+
+/* Safer macros with sanity check on name, WARNING: these are _macros_,
+   no side effects allowed on <name> ! */
+/** Search for a channel by name. */
+#define FindChannel(name)       (BadPtr((name)) ? 0 : SeekChannel(name))
+/** Search for any client by name. */
+#define FindClient(name)        (BadPtr((name)) ? 0 : SeekClient(name))
+/** Search for a registered user by name. */
+#define FindUser(name)          (BadPtr((name)) ? 0 : SeekUser(name))
+/** Search for a server by name. */
+#define FindServer(name)        (BadPtr((name)) ? 0 : SeekServer(name))
+
+/*
+ * Proto types
+ */
+
+extern void init_hash(void);    /* Call me on startup */
+extern int hAddClient(struct Client *cptr);
+extern int hAddChannel(struct Channel *chptr);
+extern int hRemClient(struct Client *cptr);
+extern int hChangeClient(struct Client *cptr, const char *newname);
+extern int hRemChannel(struct Channel *chptr);
+extern struct Client *hSeekClient(const char *name, int TMask);
+extern struct Channel *hSeekChannel(const char *name);
+
+extern int m_hash(struct Client *cptr, struct Client *sptr, int parc, char *parv[]);
+
+extern int isNickJuped(const char *nick);
+extern int addNickJupes(const char *nicks);
+extern void clearNickJupes(void);
+extern void stats_nickjupes(struct Client* to, const struct StatDesc* sd,
+                           char* param);
+extern void list_next_channels(struct Client *cptr);
+
+#endif /* INCLUDED_hash_h */
diff --git a/include/ircd.h b/include/ircd.h
new file mode 100644 (file)
index 0000000..261a1be
--- /dev/null
@@ -0,0 +1,64 @@
+/** @file ircd.h
+ * @brief Global data for the daemon.
+ * @version $Id: ircd.h 1229 2004-10-05 04:14:44Z entrope $
+ */
+#ifndef INCLUDED_ircd_h
+#define INCLUDED_ircd_h
+#ifndef INCLUDED_struct_h
+#include "struct.h"           /* struct Client */
+#endif
+#ifndef INCLUDED_sys_types_h
+#include <sys/types.h>        /* size_t, time_t */
+#endif
+
+/* special unrestricted server */
+// #define UNRESTRICTED_SERV
+
+
+/** Describes status for a daemon. */
+struct Daemon
+{
+  int          argc;        /**< Number of command-line arguments. */
+  char**       argv;        /**< Array of command-line arguments. */
+  pid_t        pid;         /**< %Daemon's process id. */
+  uid_t        uid;         /**< %Daemon's user id. */
+  uid_t        euid;        /**< %Daemon's effective user id. */
+  unsigned int bootopt;     /**< Boot option flags. */
+  int          pid_fd;      /**< File descriptor for process id file. */
+};
+
+/*
+ * Macros
+ */
+#define TStime() (CurrentTime + TSoffset) /**< Current network time*/
+#define OLDEST_TS 780000000    /**< Any TS older than this is bogus */
+#define BadPtr(x) (!(x) || (*(x) == '\0')) /**< Is \a x a bad string? */
+
+/* Miscellaneous defines */
+
+#define UDP_PORT        "7007"  /**< Default port for server-to-server pings. */
+#define MINOR_PROTOCOL  "09"    /**< Minimum protocol version supported. */
+#define MAJOR_PROTOCOL  "10"    /**< Current protocol version. */
+#define BASE_VERSION    "u2.10" /**< Base name of IRC daemon version. */
+
+/*
+ * Proto types
+ */
+extern void server_die(const char* message);
+extern void server_panic(const char* message);
+extern void server_restart(const char* message);
+
+extern struct Client  me;
+extern time_t         CurrentTime;
+extern struct Client* GlobalClientList;
+extern time_t         TSoffset;
+extern int            GlobalRehashFlag;      /* 1 if SIGHUP is received */
+extern int            GlobalRestartFlag;     /* 1 if SIGINT is received */
+extern char*          configfile;
+extern int            debuglevel;
+extern char*          debugmode;
+extern int           running;
+extern char*          dpath;
+
+#endif /* INCLUDED_ircd_h */
+
diff --git a/include/ircd_alloc.h b/include/ircd_alloc.h
new file mode 100644 (file)
index 0000000..125a7d0
--- /dev/null
@@ -0,0 +1,81 @@
+/*
+ * IRC - Internet Relay Chat, include/ircd_alloc.h
+ * Copyright (C) 1999 Thomas Helvey <tomh@inxpress.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Commentary by Bleep (Thomas Helvey)
+ */
+/** @file
+ * @brief IRC daemon memory allocation functions.
+ * @version $Id: ircd_alloc.h 1306 2005-01-27 04:07:46Z entrope $
+ */
+#ifndef INCLUDED_ircd_alloc_h
+#define INCLUDED_ircd_alloc_h
+
+/*
+ * memory resource allocation and test functions
+ */
+/** Type of handler for out-of-memory conditions. */
+typedef void (*OutOfMemoryHandler)(void);
+extern void set_nomem_handler(OutOfMemoryHandler handler);
+
+/* The mappings for the My* functions... */
+/** Helper macro for standard allocations. */
+#define MyMalloc(size) \
+  DoMalloc(size, "malloc", __FILE__, __LINE__)
+
+/** Helper macro for zero-initialized allocations. */
+#define MyCalloc(nelem, size) \
+  DoMallocZero((size) * (nelem), "calloc", __FILE__, __LINE__)
+
+/** Helper macro for freeing memory. */
+#define MyFree(p) \
+  if (p) \
+    DoFree(p, __FILE__, __LINE__)
+
+/** Helper macro for reallocating memory. */
+#define MyRealloc(p, size) \
+  DoRealloc(p, size, __FILE__, __LINE__)
+
+/* First version: fast non-debugging macros... */
+#ifndef MDEBUG
+#ifndef INCLUDED_stdlib_h
+#include <stdlib.h> /* free */
+#define INCLUDED_stdlib_h
+#endif
+
+/** Implementation macro for freeing memory. */
+#define DoFree(x, file, line) do { free((x)); (x) = 0; } while(0)
+extern void* DoMalloc(size_t len, const char*, const char*, int);
+extern void* DoMallocZero(size_t len, const char*, const char*, int);
+extern void *DoRealloc(void *, size_t, const char*, int);
+
+/* Second version: slower debugging versions... */
+#else /* defined(MDEBUG) */
+#include <sys/types.h>
+#include "memdebug.h"
+
+#define DoMalloc(size, type, file, line) \
+  dbg_malloc(size, type, file, line)
+#define DoMallocZero(size, type, file, line) \
+  dbg_malloc_zero(size, type, file, line)
+#define DoFree(p, file, line) \
+  do { dbg_free(p, file, line); (p) = 0; } while (0)
+#define DoRealloc(p, size, file, line) \
+  dbg_realloc(p, size, file, line)
+#endif /* defined(MDEBUG) */
+
+#endif /* INCLUDED_ircd_alloc_h */
diff --git a/include/ircd_chattr.h b/include/ircd_chattr.h
new file mode 100644 (file)
index 0000000..802672e
--- /dev/null
@@ -0,0 +1,130 @@
+/*
+ * IRC - Internet Relay Chat, include/ircd_chattr.h
+ * Copyright (C) 1998 Andrea Cocito
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/** @file
+ * @brief Character attribute definitions and arrays.
+ * @version $Id: ircd_chattr.h 1221 2004-10-05 02:10:00Z entrope $
+ *
+ * This character set code is adapted from Nemesi's Tools Library,
+ * which gives us the prefix NTL_ on these macros.
+ */
+
+#ifndef INCLUDED_ircd_chattr_h
+#define INCLUDED_ircd_chattr_h
+#ifndef INCLUDED_limits_h
+#include <limits.h>
+#define INCLUDED_limits_h
+#endif
+#ifndef INCLUDED_sys_types_h
+#include <sys/types.h>
+#define INCLUDED_sys_types_h
+#endif
+
+/*
+ * Character attribute macros
+ */
+#define NTL_ALNUM   0x0001  /**< (NTL_ALPHA | NTL_DIGIT)             */
+#define NTL_ALPHA   0x0002  /**< (NTL_LOWER | NTL_UPPER)             */
+#define NTL_CNTRL   0x0004  /**< \\000 - \\037 == 0x00 - 0x1F        */
+#define NTL_DIGIT   0x0008  /**< 0123456789                          */
+#define NTL_GRAPH   0x0010  /**< (NTL_ALNUM | NTL_PUNCT)             */
+#define NTL_LOWER   0x0020  /**< abcdefghijklmnopqrstuvwxyz{|}~      */
+#define NTL_PRINT   0x0040  /**< (NTL_GRAPH | ' ')                   */
+#define NTL_PUNCT   0x0080  /**< !"#$%&'()*+,-./:;<=>?\@_`           */
+#define NTL_SPACE   0x0100  /**< \\011\\012\\013\\014\\015\\040      */
+#define NTL_UPPER   0x0200  /**< ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^     */
+#define NTL_IRCCH   0x0400  /**< Channel's names charset             */
+#define NTL_IRCCL   0x0800  /**< Force toLower() in ch-name          */
+#define NTL_IRCNK   0x1000  /**< Nick names charset, aka isvalid()   */
+#define NTL_IRCUI   0x2000  /**< UserIDs charset, IRCHN plus tilde   */
+#define NTL_IRCHN   0x4000  /**< Hostnames charset (weak, RFC 1033)  */
+#define NTL_IRCIP   0x8000  /**< Numeric IPs charset (DIGIT and .)   */
+#define NTL_EOL    0x10000  /**< \\r\\n                              */
+#define NTL_KTIME  0x20000  /**< Valid character for a k:line time   */
+#define NTL_CHPFX  0x40000  /**< channel prefix char # & +           */
+#define NTL_IRCIP6 0x80000  /**< Numeric IPv6 character (hex or colon) */
+
+/*
+ * Tables used for translation and classification macros
+ */
+/** Array mapping characters to RFC 1459 lower-case versions.
+ * Yes, the variable name lies about the encoding.
+ */
+extern const char ToLowerTab_8859_1[];
+/** Array mapping characters to RFC 1459 upper-case versions.
+ * Yes, the variable name lies about the encoding.
+ */
+extern const char ToUpperTab_8859_1[];
+/** Array mapping characters to attribute bitmasks. */
+extern const unsigned int  IRCD_CharAttrTab[];
+
+/*
+ * Translation macros for channel name case translation
+ * NOTE: Channel names are supposed to be lower case insensitive for
+ * ISO 8859-1 character sets.
+ */
+/** Convert a character to its lower-case equivalent. */
+#define ToLower(c)        (ToLowerTab_8859_1[(c) - CHAR_MIN])
+/** Convert a character to its upper-case equivalent. */
+#define ToUpper(c)        (ToUpperTab_8859_1[(c) - CHAR_MIN])
+
+/*
+ * Character classification macros
+ * NOTE: The IsUpper and IsLower macros do not apply to the complete
+ * ISO 8859-1 character set, unlike the ToUpper and ToLower macros above.
+ * IsUpper and IsLower only apply for comparisons of the US ASCII subset.
+ */
+/** Test whether a character is alphanumeric. */
+#define IsAlnum(c)         (IRCD_CharAttrTab[(c) - CHAR_MIN] & NTL_ALNUM)
+/** Test whether a character is alphabetic. */
+#define IsAlpha(c)         (IRCD_CharAttrTab[(c) - CHAR_MIN] & NTL_ALPHA)
+/** Test whether a character is a digit. */
+#define IsDigit(c)         (IRCD_CharAttrTab[(c) - CHAR_MIN] & NTL_DIGIT)
+/** Test whether a character is lower case. */
+#define IsLower(c)         (IRCD_CharAttrTab[(c) - CHAR_MIN] & NTL_LOWER)
+/** Test whether a character is whitespace. */
+#define IsSpace(c)         (IRCD_CharAttrTab[(c) - CHAR_MIN] & NTL_SPACE)
+/** Test whether a character is upper case. */
+#define IsUpper(c)         (IRCD_CharAttrTab[(c) - CHAR_MIN] & NTL_UPPER)
+/** Test whether a character is a control character. */
+#define IsCntrl(c)         (IRCD_CharAttrTab[(c) - CHAR_MIN] & NTL_CNTRL)
+
+/** Test whether a character is valid in a channel name. */
+#define IsChannelChar(c)   (IRCD_CharAttrTab[(c) - CHAR_MIN] & NTL_IRCCH)
+/** Test whether a character is a lower-case channel name character. */
+#define IsChannelLower(c)  (IRCD_CharAttrTab[(c) - CHAR_MIN] & NTL_IRCCL)
+/** Test whether a character is a channel prefix. */
+#define IsChannelPrefix(c) (IRCD_CharAttrTab[(c) - CHAR_MIN] & NTL_CHPFX)
+/** Test whether a character is valid in a nickname. */
+#define IsNickChar(c)      (IRCD_CharAttrTab[(c) - CHAR_MIN] & NTL_IRCNK)
+/** Test whether a character is valid in a userid. */
+#define IsUserChar(c)      (IRCD_CharAttrTab[(c) - CHAR_MIN] & NTL_IRCUI)
+/** Test whether a character is valid in a hostname. */
+#define IsHostChar(c)      (IRCD_CharAttrTab[(c) - CHAR_MIN] & NTL_IRCHN)
+/** Test whether a character is valid in an IPv4 address. */
+#define IsIPChar(c)        (IRCD_CharAttrTab[(c) - CHAR_MIN] & NTL_IRCIP)
+/** Test whether a character is valid in an IPv6 address. */
+#define IsIP6Char(c)       (IRCD_CharAttrTab[(c) - CHAR_MIN] & NTL_IRCIP6)
+/** Test whether a character is an end-of-line character. */
+#define IsEol(c)           (IRCD_CharAttrTab[(c) - CHAR_MIN] & NTL_EOL)
+/** Test whether a character is valid in a K: line expiration string. */
+#define IsKTimeChar(c)     (IRCD_CharAttrTab[(c) - CHAR_MIN] & NTL_KTIME)
+
+
+#endif /* INCLUDED_ircd_chattr_h */
diff --git a/include/ircd_crypt.h b/include/ircd_crypt.h
new file mode 100644 (file)
index 0000000..1d1b205
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+ * IRC - Internet Relay Chat, include/ircd_crypt.h
+ * Copyright (C) 2002 hikari
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+/** @file
+ * @brief Core password encryption and hashing APIs.
+ * @version $Id: ircd_crypt.h 1264 2004-11-07 21:04:59Z entrope $
+ */
+#ifndef INCLUDED_ircd_crypt_h
+#define INCLUDED_ircd_crypt_h
+
+/* forward planning for modularisation */
+struct crypt_mech_s {
+ char* mechname;     /* name of the mechanism */
+ char* shortname;    /* short name of the module */
+ char* description;  /* description of the mechanism */
+
+ const char* (*crypt_function)(const char *, const char *); 
+                     /* pointer to the crypt function */
+
+ char* crypt_token;  /* what identifies a password string 
+                        as belonging to this mechanism */
+
+ int crypt_token_size; /* how long is the token */
+};
+
+typedef struct crypt_mech_s crypt_mech_t;
+
+struct crypt_mechs_s;
+typedef struct crypt_mechs_s crypt_mechs_t;
+
+struct crypt_mechs_s {
+ crypt_mech_t* mech;
+ crypt_mechs_t* next;
+ crypt_mechs_t* prev;
+};
+
+/* access macros */
+#define MechName(x) x->mechname
+#define ShortName(x) x->shortname
+#define Description(x) x->description
+#define CryptFunc(x) x->crypt_function
+#define CryptTok(x) x->crypt_token
+#define CryptTokSize(x) x->crypt_token_size
+
+/* exported functions */
+extern void ircd_crypt_init(void);
+extern char* ircd_crypt(const char* key, const char* salt);
+extern int ircd_crypt_register_mech(crypt_mech_t* mechanism);
+extern int ircd_crypt_unregister_mech(crypt_mech_t* mechanism);
+
+/* exported variables */
+extern crypt_mechs_t* crypt_mechs_root;
+
+#endif /* INCLUDED_ircd_crypt_h */
+
diff --git a/include/ircd_crypt_native.h b/include/ircd_crypt_native.h
new file mode 100644 (file)
index 0000000..58924e4
--- /dev/null
@@ -0,0 +1,12 @@
+/** @file
+ * @brief Native crypt() function declarations.
+ * @version $Id: ircd_crypt_native.h 1231 2004-10-05 04:21:37Z entrope $
+ */
+#ifndef INCLUDED_ircd_crypt_native_h
+#define INCLUDED_ircd_crypt_native_h
+
+extern const char* ircd_crypt_native(const char* key, const char* salt);
+extern void ircd_register_crypt_native(void);
+
+#endif /* INCLUDED_ircd_crypt_native_h */
+
diff --git a/include/ircd_crypt_plain.h b/include/ircd_crypt_plain.h
new file mode 100644 (file)
index 0000000..f63fd4d
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * IRC - Internet Relay Chat, include/ircd_crypt_plain.h
+ * Copyright (C) 2002 hikari
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+/** @file
+ * @brief Declarations for plaintext password "crypting".
+ * @version $Id: ircd_crypt_plain.h 1231 2004-10-05 04:21:37Z entrope $
+ */
+#ifndef INCLUDED_ircd_crypt_plain_h
+#define INCLUDED_ircd_crypt_plain_h
+
+extern const char* ircd_crypt_plain(const char* key, const char* salt);
+extern void ircd_register_crypt_plain(void);
+
+
+#endif /* INCLUDED_ircd_crypt_plain_h */
+
diff --git a/include/ircd_crypt_smd5.h b/include/ircd_crypt_smd5.h
new file mode 100644 (file)
index 0000000..2112faa
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ * IRC - Internet Relay Chat, include/ircd_crypt_smd5.h
+ * Copyright (C) 2002 hikari
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+/** @file
+ * @brief Declarations for salted MD5 password crypting.
+ * @version $Id: ircd_crypt_smd5.h 1231 2004-10-05 04:21:37Z entrope $
+ */
+#ifndef INCLUDED_ircd_crypt_smd5_h
+#define INCLUDED_ircd_crypt_smd5_h
+
+extern void ircd_register_crypt_smd5(void);
+
+#endif /* INCLUDED_ircd_crypt_smd5_h */
+
diff --git a/include/ircd_defs.h b/include/ircd_defs.h
new file mode 100644 (file)
index 0000000..f2909f4
--- /dev/null
@@ -0,0 +1,102 @@
+/*
+ * IRC - Internet Relay Chat, include/ircd_defs.h
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ *                    University of Oulu, Computing Center
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Commentary by Bleep (Thomas Helvey)
+ */
+#ifndef INCLUDED_ircd_defs_h
+#define INCLUDED_ircd_defs_h
+/** @file
+ * @brief Definitions used everywhere in the server.
+ *
+ * NOTE: Changing any of these definitions (except for the
+ * target-related ones at the bottom) is equivalent to a protocol
+ * revision. Every server on a given network must use the same values.
+ * @version $Id: ircd_defs.h 1222 2004-10-05 02:21:08Z entrope $
+ */
+
+/** Maximum length allowed for a nickname.
+ * Because certain networks are very helpful in finding bugs, the below
+ * is a default that can easily be overridden in CFLAGS.  Just add
+ * -DNICKLEN=15 to CFLAGS during configure, and you can forget about
+ * it.  Thanks for helping debug guys.
+ * See also F:NICKLEN in ircd.conf.
+ */
+#ifndef NICKLEN
+#define NICKLEN         30
+#endif
+/** Maximum length allowed of a user name, including an optional
+ * leading '~' if the user name has not been authenticated by an auth (RFC 931)
+ * server query.
+ */
+#define USERLEN         10
+/** Exactly long enough to hold one (1) segment of FQDN or hostname.
+ * This is due to an historical misinterpretation of RFC 1034.
+ * 3.1. Name space specifications and terminology
+ *
+ * The domain name space is a tree structure.  Each node and leaf on the
+ * tree corresponds to a resource set (which may be empty).  The domain
+ * system makes no distinctions between the uses of the interior nodes and
+ * leaves, and this memo uses the term "node" to refer to both.
+ *
+ * Each node has a label, which is zero to 63 octets in length.  Brother
+ * nodes may not have the same label, although the same label can be used
+ * for nodes which are not brothers.  One label is reserved, and that is
+ * the null (i.e., zero length) label used for the root.
+ *
+ * This has proven not to be a problem in the past as connections with FQDN's
+ * of greater than 63 characters are rejected by the server, and most FQDN's
+ * are shorter. It is possible to have a valid FQDN longer than 63 characters.
+ */
+#define HOSTLEN         63
+/** Maximum length for the account name, which can be set
+ * with the ACCOUNT (AC) command.  This is used for keeping track of who's
+ * logged into which account, for the benefit of irc services.
+ */
+#define ACCOUNTLEN      30
+/** Maximum length for user supplied information about a client
+ * connection (gcos). This information is set at client/server registration
+ * time.
+ */
+#define REALLEN         50
+/** Maximum length for a password used for connecting servers and clients.
+ */
+#define PASSWDLEN       40
+/** Maximum length of a numeric IP (v4 or v6) address.
+ * "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255"
+ */
+#define SOCKIPLEN 45
+/** Maximum length for channel topics and kill comments.
+ */
+#define TOPICLEN        500
+/** Maximum length for away messages.
+ */
+#define AWAYLEN                300
+/** Exactly long enough to hold one protocol message (RFC 1459)
+ * including the line termination (\\r\\n).  DO NOT CHANGE THIS!!!!
+ */
+#define BUFSIZE         512
+
+/** Maximum available targets for a user. */
+#define MAXTARGETS      20
+/** Starting free targets for a user. */
+#define STARTTARGETS    20
+/** Target number to start assigning new targets. */
+#define RESERVEDTARGETS 12
+
+#endif /* INCLUDED_ircd_defs_h */
diff --git a/include/ircd_events.h b/include/ircd_events.h
new file mode 100644 (file)
index 0000000..c498bbb
--- /dev/null
@@ -0,0 +1,314 @@
+#ifndef INCLUDED_ircd_events_h
+#define INCLUDED_ircd_events_h
+/*
+ * IRC - Internet Relay Chat, include/ircd_events.h
+ * Copyright (C) 2001 Kevin L. Mitchell <klmitch@mit.edu>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+/** @file
+ * @brief Interface and public definitions for event loop.
+ * @version $Id: ircd_events.h 1794 2007-04-01 02:11:41Z entrope $
+ */
+
+#ifndef INCLUDED_config_h
+#include "config.h"
+#endif
+#ifndef INCLUDED_sys_types_h
+#include <sys/types.h> /* time_t */
+#define INCLUDED_sys_types_h
+#endif
+
+#include "ssl.h"
+
+struct Event;
+
+/** Generic callback for event activity. */
+typedef void (*EventCallBack)(struct Event*);
+
+/** State of a Socket structure. */
+enum SocketState {
+  SS_CONNECTING,       /**< Connection in progress on socket */
+  SS_LISTENING,                /**< Socket is a listening socket */
+  SS_CONNECTED,                /**< Socket is a connected socket */
+  SS_DATAGRAM,         /**< Socket is a datagram socket */
+  SS_CONNECTDG,                /**< Socket is a connected datagram socket */
+  SS_NOTSOCK           /**< Socket isn't a socket at all */
+};
+
+/** Type of a Timer (how its expiration is measured). */
+enum TimerType {
+  TT_ABSOLUTE,         /**< timer that runs at a specific time */
+  TT_RELATIVE,         /**< timer that runs so many seconds in the future */
+  TT_PERIODIC          /**< timer that runs periodically */
+};
+
+/** Type of event that generated a callback. */
+enum EventType {
+  ET_READ,             /**< Readable event detected */
+  ET_WRITE,            /**< Writable event detected */
+  ET_ACCEPT,           /**< Connection can be accepted */
+  ET_CONNECT,          /**< Connection completed */
+  ET_EOF,              /**< End-of-file on connection */
+  ET_ERROR,            /**< Error condition detected */
+  ET_SIGNAL,           /**< A signal was received */
+  ET_EXPIRE,           /**< A timer expired */
+  ET_DESTROY           /**< The generator is being destroyed */
+};
+
+/** Common header for event generators. */
+struct GenHeader {
+  struct GenHeader*  gh_next;  /**< linked list of generators */
+  struct GenHeader** gh_prev_p; /**< previous pointer to this generator */
+#ifdef IRCD_THREADED
+  struct GenHeader*  gh_qnext; /**< linked list of generators in queue */
+  struct GenHeader** gh_qprev_p; /**< previous pointer to this generator */
+  struct Event*             gh_head;   /**< head of event queue */
+  struct Event*             gh_tail;   /**< tail of event queue */
+#endif
+  unsigned int      gh_flags;  /**< generator flags */
+  unsigned int      gh_ref;    /**< reference count */
+  EventCallBack             gh_call;   /**< generator callback function */
+  void*                     gh_data;   /**< extra data */
+  union {
+    void*           ed_ptr;    /**< engine data as pointer */
+    int                     ed_int;    /**< engine data as integer */
+  }                 gh_engdata;/**< engine data */
+};
+
+#define GEN_DESTROY    0x0001  /**< generator is to be destroyed */
+#define GEN_MARKED     0x0002  /**< generator is marked for destruction */
+#define GEN_ACTIVE     0x0004  /**< generator is active */
+#define GEN_READD      0x0008  /**< generator (timer) must be re-added */
+#define GEN_ERROR      0x0010  /**< an error occurred on the generator */
+
+/** Socket event generator.
+ * Note: The socket state overrides the socket event mask; that is, if
+ * it's an SS_CONNECTING socket, the engine selects its own definition
+ * of what that looks like and ignores s_events.  s_events is meaningful
+ * only for SS_CONNECTED, SS_DATAGRAM, and SS_CONNECTDG, but may be set
+ * prior to the state transition, if desired.
+ */
+struct Socket {
+  struct GenHeader s_header;   /**< generator information */
+  enum SocketState s_state;    /**< state socket's in */
+  unsigned int    s_events;    /**< events socket is interested in */
+  int             s_fd;        /**< file descriptor for socket */
+  ssl_session_t *ssl; /**< if not NULL it points to the ssl session */
+};
+
+#define SOCK_EVENT_READABLE    0x0001  /**< interested in readable */
+#define SOCK_EVENT_WRITABLE    0x0002  /**< interested in writable */
+
+/** Bitmask of possible event interests for a socket. */
+#define SOCK_EVENT_MASK                (SOCK_EVENT_READABLE | SOCK_EVENT_WRITABLE)
+
+#define SOCK_ACTION_SET                0x0000  /**< set interest set as follows */
+#define SOCK_ACTION_ADD                0x1000  /**< add to interest set */
+#define SOCK_ACTION_DEL                0x2000  /**< remove from interest set */
+
+#define SOCK_ACTION_MASK       0x3000  /**< mask out the actions */
+
+/** Retrieve state of the Socket \a sock. */
+#define s_state(sock)  ((sock)->s_state)
+/** Retrieve interest mask of the Socket \a sock. */
+#define s_events(sock) ((sock)->s_events)
+/** Retrieve file descriptor of the Socket \a sock. */
+#define s_fd(sock)     ((sock)->s_fd)
+/** Retrieve user data pointer of the Socket \a sock. */
+#define s_data(sock)   ((sock)->s_header.gh_data)
+/** Retrieve engine data integer of the Socket \a sock. */
+#define s_ed_int(sock) ((sock)->s_header.gh_engdata.ed_int)
+/** Retrieve engine data pointer of the Socket \a sock. */
+#define s_ed_ptr(sock) ((sock)->s_header.gh_engdata.ed_ptr)
+/** Retrieve whether the Socket \a sock is active. */
+#define s_active(sock) ((sock)->s_header.gh_flags & GEN_ACTIVE)
+
+/** Signal event generator. */
+struct Signal {
+  struct GenHeader sig_header; /**< generator information */
+  int             sig_signal;  /**< signal number */
+};
+
+/** Retrieve signal number of the Signal \a sig. */
+#define sig_signal(sig)        ((sig)->sig_signal)
+/** Retrieve user data pointer of the Signal \a sig. */
+#define sig_data(sig)  ((sig)->sig_header.gh_data)
+/** Retrieve engine data integer of the Signal \a sig. */
+#define sig_ed_int(sig)        ((sig)->sig_header.gh_engdata.ed_int)
+/** Retrieve engine data pointer of the Signal \a sig. */
+#define sig_ed_ptr(sig)        ((sig)->sig_header.gh_engdata.ed_ptr)
+/** Retrieve whether the Signal \a sig is active. */
+#define sig_active(sig)        ((sig)->sig_header.gh_flags & GEN_ACTIVE)
+
+/** Timer event generator. */
+struct Timer {
+  struct GenHeader t_header;   /**< generator information */
+  enum TimerType   t_type;     /**< what type of timer this is */
+  time_t          t_value;     /**< value timer was added with */
+  time_t          t_expire;    /**< time at which timer expires */
+};
+
+/** Retrieve type of the Timer \a tim. */
+#define t_type(tim)    ((tim)->t_type)
+/** Retrieve interval of the Timer \a tim. */
+#define t_value(tim)   ((tim)->t_value)
+/** Retrieve expiration time of the Timer \a tim. */
+#define t_expire(tim)  ((tim)->t_expire)
+/** Retrieve user data pointer of the Timer \a tim. */
+#define t_data(tim)    ((tim)->t_header.gh_data)
+/** Retrieve engine data integer of the Timer \a tim. */
+#define t_ed_int(tim)  ((tim)->t_header.gh_engdata.ed_int)
+/** Retrieve engine data pointer of the Timer \a tim. */
+#define t_ed_ptr(tim)  ((tim)->t_header.gh_engdata.ed_ptr)
+/** Retrieve whether the Timer \a tim is active. */
+#define t_active(tim)  ((tim)->t_header.gh_flags & GEN_ACTIVE)
+/** Retrieve whether the Timer \a tim is enqueued. */
+#define t_onqueue(tim) ((tim)->t_header.gh_prev_p)
+
+/** Event activity descriptor. */
+struct Event {
+  struct Event*         ev_next;       /**< linked list of events on queue */
+  struct Event** ev_prev_p;     /**< previous pointer to this event */
+  enum EventType ev_type;      /**< Event type */
+  int           ev_data;       /**< extra data, like errno value */
+  union {
+    struct GenHeader* gen_header;      /**< Generator header */
+    struct Socket*    gen_socket;      /**< Socket generating event */
+    struct Signal*    gen_signal;      /**< Signal generating event */
+    struct Timer*     gen_timer;       /**< Timer generating event */
+  }             ev_gen;        /**< object generating event */
+};
+
+/** Retrieve the type of the Event \a ev. */
+#define ev_type(ev)    ((ev)->ev_type)
+/** Retrieve the extra data of the Event \a ev. */
+#define ev_data(ev)    ((ev)->ev_data)
+/** Retrieve the Socket that generated the Event \a ev. */
+#define ev_socket(ev)  ((ev)->ev_gen.gen_socket)
+/** Retrieve the Signal that generated the Event \a ev. */
+#define ev_signal(ev)  ((ev)->ev_gen.gen_signal)
+/** Retrieve the Timer that generated the Event \a ev. */
+#define ev_timer(ev)   ((ev)->ev_gen.gen_timer)
+
+/** List of all event generators. */
+struct Generators {
+  struct GenHeader* g_socket;  /**< list of socket generators */
+  struct GenHeader* g_signal;  /**< list of signal generators */
+  struct GenHeader* g_timer;   /**< list of timer generators */
+};
+
+/** Returns 1 if successfully initialized, 0 if not.
+ * @param[in] max_sockets Number of sockets to support.
+ */
+typedef int (*EngineInit)(int max_sockets);
+
+/** Tell engine about new signal.
+ * @param[in] sig Signal event generator to add.
+ */
+typedef void (*EngineSignal)(struct Signal* sig);
+
+/** Tell engine about new socket.
+ * @param[in] sock Socket event generator to add.
+ */
+typedef int (*EngineAdd)(struct Socket* sock);
+
+/** Tell engine about socket's new_state.
+ * @param[in] sock Socket whose state is changing.
+ * @param[in] new_state New state for socket.
+ */
+typedef void (*EngineState)(struct Socket* sock, enum SocketState new_state);
+
+/** Tell engine about socket's new event interests.
+ * @param[in] sock Socket whose interest mask is changing.
+ * @param[in] new_events New event mask to set (not SOCK_ACTION_ADD or SOCK_ACTION_DEL).
+ */
+typedef void (*EngineEvents)(struct Socket* sock, unsigned int new_events);
+
+/** Tell engine a socket is going away.
+ * @param[in] sock Socket being destroyed.
+ */
+typedef void (*EngineDelete)(struct Socket* sock);
+
+/** The actual event loop.
+ * @param[in] gens List of event generators.
+ */
+typedef void (*EngineLoop)(struct Generators* gens);
+
+/** Structure for an event engine to describe itself. */
+struct Engine {
+  const char*  eng_name;       /**< a name for the engine */
+  EngineInit   eng_init;       /**< initialize engine */
+  EngineSignal eng_signal;     /**< express interest in a signal (may be NULL) */
+  EngineAdd    eng_add;        /**< express interest in a socket */
+  EngineState  eng_state;      /**< mention a change in state to engine */
+  EngineEvents eng_events;     /**< express interest in socket events */
+  EngineDelete eng_closing;    /**< socket is being closed */
+  EngineLoop   eng_loop;       /**< actual event loop */
+};
+
+/** Increment the reference count of \a gen. */
+#define gen_ref_inc(gen)       (((struct GenHeader*) (gen))->gh_ref++)
+/** Decrement the reference count of \a gen. */
+#define gen_ref_dec(gen)                                                     \
+do {                                                                         \
+  struct GenHeader* _gen = (struct GenHeader*) (gen);                        \
+  if (!--_gen->gh_ref && (_gen->gh_flags & GEN_DESTROY)) {                   \
+    gen_dequeue(_gen);                                                       \
+    event_generate(ET_DESTROY, _gen, 0);                                     \
+  }                                                                          \
+} while (0)
+/** Clear the error flag for \a gen. */
+#define gen_clear_error(gen)                                                 \
+       (((struct GenHeader*) (gen))->gh_flags &= ~GEN_ERROR)
+
+void gen_dequeue(void* arg);
+
+void event_init(int max_sockets);
+void event_loop(void);
+void event_generate(enum EventType type, void* arg, int data);
+
+struct Timer* timer_init(struct Timer* timer);
+void timer_add(struct Timer* timer, EventCallBack call, void* data,
+              enum TimerType type, time_t value);
+void timer_del(struct Timer* timer);
+void timer_chg(struct Timer* timer, enum TimerType type, time_t value);
+void timer_run(void);
+/** Retrieve the next timer's expiration time from Generators \a gen. */
+#define timer_next(gen)        ((gen)->g_timer ? ((struct Timer*)(gen)->g_timer)->t_expire : 0)
+
+void signal_add(struct Signal* signal, EventCallBack call, void* data,
+               int sig);
+
+int socket_add(struct Socket* sock, EventCallBack call, void* data,
+              enum SocketState state, unsigned int events, int fd);
+void socket_del(struct Socket* sock);
+void socket_state(struct Socket* sock, enum SocketState state);
+void socket_events(struct Socket* sock, unsigned int events);
+
+const char* engine_name(void);
+
+#ifdef DEBUGMODE
+/* These routines pretty-print names for states and types for debug printing */
+
+const char* state_to_name(enum SocketState state);
+const char* timer_to_name(enum TimerType type);
+const char* event_to_name(enum EventType type);
+const char* gen_flags(unsigned int flags);
+const char* sock_flags(unsigned int flags);
+
+#endif /* DEBUGMODE */
+
+#endif /* INCLUDED_ircd_events_h */
diff --git a/include/ircd_features.h b/include/ircd_features.h
new file mode 100644 (file)
index 0000000..2a0332f
--- /dev/null
@@ -0,0 +1,197 @@
+#ifndef INCLUDED_features_h
+#define INCLUDED_features_h
+/*
+ * IRC - Internet Relay Chat, include/features.h
+ * Copyright (C) 2000 Kevin L. Mitchell <klmitch@mit.edu>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+/** @file
+ * @brief Public interfaces and declarations for dealing with configurable features.
+ * @version $Id: ircd_features.h 1774 2007-03-17 03:48:49Z klmitch $
+ */
+
+struct Client;
+struct StatDesc;
+
+extern struct Client his;
+
+/** Contains all feature settings for ircu.
+ * For documentation of each, see doc/readme.features.
+ */
+enum Feature {
+  /* Misc. features */
+  FEAT_LOG,
+  FEAT_DOMAINNAME,
+  FEAT_RELIABLE_CLOCK,
+  FEAT_BUFFERPOOL,
+  FEAT_HAS_FERGUSON_FLUSHER,
+  FEAT_CLIENT_FLOOD,
+  FEAT_SERVER_PORT,
+  FEAT_NODEFAULTMOTD,
+  FEAT_MOTD_BANNER,
+  FEAT_PROVIDER,
+  FEAT_KILL_IPMISMATCH,
+  FEAT_IDLE_FROM_MSG,
+  FEAT_HUB,
+  FEAT_WALLOPS_OPER_ONLY,
+  FEAT_NODNS,
+  FEAT_RANDOM_SEED,
+  FEAT_DEFAULT_LIST_PARAM,
+  FEAT_NICKNAMEHISTORYLENGTH,
+  FEAT_HOST_HIDING,
+  FEAT_HIDDEN_HOST,
+  FEAT_HIDDEN_IP,
+  FEAT_CONNEXIT_NOTICES,
+  FEAT_OPLEVELS,
+  FEAT_ZANNELS,
+  FEAT_LOCAL_CHANNELS,
+  FEAT_TOPIC_BURST,
+  FEAT_AWAY_BURST,
+  FEAT_DISABLE_GLINES,
+  FEAT_FAKE_WEBIRC,
+  FEAT_WEBIRC_UMODE,
+  FEAT_WEBIRC_REJECT,
+  FEAT_LOC_ENABLE,
+  FEAT_LOC_TARGET,
+  FEAT_EXCEPT_ENABLE,
+  FEAT_NOAMSG_TIME,
+  FEAT_NOAMSG_NUM,
+
+  /* features that probably should not be touched */
+  FEAT_KILLCHASETIMELIMIT,
+  FEAT_MAXCHANNELSPERUSER,
+  FEAT_NICKLEN,
+  FEAT_AVBANLEN,
+  FEAT_MAXBANS,
+  FEAT_MAXSILES,
+  FEAT_HANGONGOODLINK,
+  FEAT_HANGONRETRYDELAY,
+  FEAT_CONNECTTIMEOUT,
+  FEAT_MAXIMUM_LINKS,
+  FEAT_PINGFREQUENCY,
+  FEAT_CONNECTFREQUENCY,
+  FEAT_DEFAULTMAXSENDQLENGTH,
+  FEAT_GLINEMAXUSERCOUNT,
+  FEAT_SOCKSENDBUF,
+  FEAT_SOCKRECVBUF,
+  FEAT_IPCHECK_CLONE_LIMIT,
+  FEAT_IPCHECK_CLONE_PERIOD,
+  FEAT_IPCHECK_CLONE_DELAY,
+  FEAT_CHANNELLEN,
+
+  /* Some misc. default paths */
+  FEAT_MPATH,
+  FEAT_RPATH,
+  FEAT_PPATH,
+
+  /* Networking features */
+  FEAT_TOS_SERVER,
+  FEAT_TOS_CLIENT,
+  FEAT_POLLS_PER_LOOP,
+  FEAT_IRCD_RES_RETRIES,
+  FEAT_IRCD_RES_TIMEOUT,
+  FEAT_AUTH_TIMEOUT,
+  FEAT_ANNOUNCE_INVITES,
+
+  /* features that affect all operators */
+  FEAT_CONFIG_OPERCMDS,
+
+  /* HEAD_IN_SAND Features */
+  FEAT_HIS_SNOTICES,
+  FEAT_HIS_SNOTICES_OPER_ONLY,
+  FEAT_HIS_DEBUG_OPER_ONLY,
+  FEAT_HIS_WALLOPS,
+  FEAT_HIS_MAP,
+  FEAT_HIS_LINKS,
+  FEAT_HIS_TRACE,
+  FEAT_HIS_STATS_a,
+  FEAT_HIS_STATS_c,
+  FEAT_HIS_STATS_d,
+  FEAT_HIS_STATS_e,
+  FEAT_HIS_STATS_f,
+  FEAT_HIS_STATS_g,
+  FEAT_HIS_STATS_i,
+  FEAT_HIS_STATS_j,
+  FEAT_HIS_STATS_J,
+  FEAT_HIS_STATS_k,
+  FEAT_HIS_STATS_l,
+  FEAT_HIS_STATS_L,
+  FEAT_HIS_STATS_M,
+  FEAT_HIS_STATS_m,
+  FEAT_HIS_STATS_o,
+  FEAT_HIS_STATS_p,
+  FEAT_HIS_STATS_q,
+  FEAT_HIS_STATS_R,
+  FEAT_HIS_STATS_r,
+  FEAT_HIS_STATS_t,
+  FEAT_HIS_STATS_T,
+  FEAT_HIS_STATS_u,
+  FEAT_HIS_STATS_U,
+  FEAT_HIS_STATS_v,
+  FEAT_HIS_STATS_w,
+  FEAT_HIS_STATS_x,
+  FEAT_HIS_STATS_y,
+  FEAT_HIS_STATS_z,
+  FEAT_HIS_STATS_IAUTH,
+  FEAT_HIS_WHOIS_SERVERNAME,
+  FEAT_HIS_WHOIS_IDLETIME,
+  FEAT_HIS_WHOIS_LOCALCHAN,
+  FEAT_HIS_WHO_SERVERNAME,
+  FEAT_HIS_WHO_HOPCOUNT,
+  FEAT_HIS_MODEWHO,
+  FEAT_HIS_BANWHO,
+  FEAT_HIS_KILLWHO,
+  FEAT_HIS_REWRITE,
+  FEAT_HIS_REMOTE,
+  FEAT_HIS_NETSPLIT,
+  FEAT_HIS_SERVERNAME,
+  FEAT_HIS_SERVERINFO,
+  FEAT_HIS_URLSERVERS,
+
+  /* Misc. random stuff */
+  FEAT_NETWORK,
+  FEAT_URL_CLIENTS,
+  FEAT_URLREG,
+  
+  FEAT_UNKNOWN_CMD_ENABLE,
+  FEAT_UNKNOWN_CMD_TARGET,
+  FEAT_CHMODE_A_ENABLE,
+  FEAT_CHMODE_A_TARGET,
+  FEAT_CHMODE_F_ENABLE,
+  
+  FEAT_LAST_F
+};
+
+extern void feature_init(void);
+
+extern int feature_set(struct Client* from, const char* const* fields,
+                      int count);
+extern int feature_reset(struct Client* from, const char* const* fields,
+                        int count);
+extern int feature_get(struct Client* from, const char* const* fields,
+                      int count);
+
+extern void feature_unmark(void);
+extern void feature_mark(void);
+
+extern void feature_report(struct Client* to, const struct StatDesc* sd,
+                           char* param);
+
+extern int feature_int(enum Feature feat);
+extern int feature_bool(enum Feature feat);
+extern const char *feature_str(enum Feature feat);
+
+#endif /* INCLUDED_features_h */
diff --git a/include/ircd_handler.h b/include/ircd_handler.h
new file mode 100644 (file)
index 0000000..047718d
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * IRC - Internet Relay Chat, include/ircd_handler.h
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ *                    University of Oulu, Computing Center
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+/** @file
+ * @brief Message handler types and definitions.
+ * @version $Id: ircd_handler.h 1228 2004-10-05 04:11:36Z entrope $
+ */
+#ifndef INCLUDED_ircd_handler_h
+#define INCLUDED_ircd_handler_h
+
+struct Client;
+
+/*
+ * MessageHandler
+ */
+/** Enumerated type for client message handlers. */
+typedef enum HandlerType {
+  UNREGISTERED_HANDLER, /**< Used for unregistered clients. */
+  CLIENT_HANDLER,       /**< Used for local users. */
+  SERVER_HANDLER,       /**< Used for server conections. */
+  OPER_HANDLER,         /**< Used for IRC operators. */
+  SERVICE_HANDLER,      /**< Used for services connections. */
+  LAST_HANDLER_TYPE     /**< NUmber of handler types. */
+} HandlerType;
+
+/**
+ * MessageHandler function.
+ * @param[in] cptr Client that sent us the message.
+ * @param[in] sptr Original source of message.
+ * @param[in] parc Number of arguments.
+ * @param[in] parv Argument vector.
+ */
+typedef int (*MessageHandler)(struct Client* cptr, struct Client* sptr, int parc, char*parv[]);
+
+
+#endif /* INCLUDED_ircd_handler_h */
+
diff --git a/include/ircd_log.h b/include/ircd_log.h
new file mode 100644 (file)
index 0000000..914cd20
--- /dev/null
@@ -0,0 +1,157 @@
+/* - Internet Relay Chat, include/ircd_log.h
+ *   Copyright (C) 1999 Thomas Helvey
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 1, or (at your option)
+ *   any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+/** @file
+ * @brief IRC logging interface.
+ * @version $Id: ircd_log.h 1392 2005-05-01 16:11:01Z entrope $
+ */
+#ifndef INCLUDED_ircd_log_h
+#define INCLUDED_ircd_log_h
+
+#ifndef INCLUDED_stdarg_h
+#include <stdarg.h>        /* va_list */
+#define INCLUDED_stdarg_h
+#endif
+#ifndef INCLUDED_stdlib_h
+#include <stdlib.h> /* abort */
+#define INCLUDED_stdlib_h
+#endif
+
+struct Client;
+
+/* WARNING WARNING WARNING -- Order is important; these enums are
+ * used as indexes into arrays.
+ */
+/** Level of a log message. */
+enum LogLevel {
+  L_CRIT,      /**< Critical failure. */
+  L_ERROR,     /**< Serious error. */
+  L_WARNING,   /**< Recoverable warning. */
+  L_NOTICE,    /**< Important status messages. */
+  L_TRACE,     /**< Client exit and kill logging. */
+  L_INFO,      /**< Logging of other operator commands. */
+  L_DEBUG,     /**< Debug message output. */
+  L_LAST_LEVEL /**< Count of valid LogLevel values. */
+};
+
+/** Log systems. */
+enum LogSys {
+  LS_SYSTEM,     /**< Operational status changes. */
+  LS_CONFIG,     /**< Configuration errors and warnings. */
+  LS_OPERMODE,   /**< Uses of OPMODE, CLEARMODE< etc. */
+  LS_GLINE,      /**< Adding, (de-)activating or removing GLINEs. */
+  LS_JUPE,       /**< Adding, (de-)activating or removing JUPEs. */
+  LS_WHO,        /**< Use of extended WHO privileges. */
+  LS_NETWORK,    /**< New server connections. */
+  LS_OPERKILL,   /**< Kills by IRC operators. */
+  LS_SERVKILL,   /**< Kills by servers. */
+  LS_USER,       /**< User exits. */
+  LS_OPER,       /**< Users becoming operators. */
+  LS_RESOLVER,   /**< DNS resolver errors. */
+  LS_SOCKET,     /**< Unexpected socket operation errors. */
+  LS_IAUTH,      /**< IAuth status. */
+  LS_DEBUG,      /**< Debug messages. */
+  LS_LAST_SYSTEM /**< Count of valid LogSys values. */
+};
+
+extern void log_debug_init(int usetty);
+extern void log_init(const char *process_name);
+extern void log_reopen(void);
+extern void log_close(void);
+
+extern void log_write(enum LogSys subsys, enum LogLevel severity,
+                     unsigned int flags, const char *fmt, ...);
+extern void log_vwrite(enum LogSys subsys, enum LogLevel severity,
+                      unsigned int flags, const char *fmt, va_list vl);
+
+extern void log_write_kill(const struct Client *victim,
+                          const struct Client *killer,
+                          const char          *inpath,
+                          const char          *path,
+                          const char          *msg);
+
+#define LOG_NOSYSLOG   0x01 /**< Do not send message to syslog. */
+#define LOG_NOFILELOG  0x02 /**< Do not send message to a log file. */
+#define LOG_NOSNOTICE  0x04 /**< Do not send message via server notice. */
+/** Bitmask of suppression flags for log_write() and log_vwrite(). */
+#define LOG_NOMASK     (LOG_NOSYSLOG | LOG_NOFILELOG | LOG_NOSNOTICE)
+
+extern char *log_canon(const char *subsys);
+
+extern int log_set_file(const char *subsys, const char *filename);
+extern char *log_get_file(const char *subsys);
+
+extern int log_set_facility(const char *subsys, const char *facility);
+extern char *log_get_facility(const char *subsys);
+
+extern int log_set_snomask(const char *subsys, const char *facility);
+extern char *log_get_snomask(const char *subsys);
+
+extern int log_set_level(const char *subsys, const char *level);
+extern char *log_get_level(const char *subsys);
+
+extern int log_set_default(const char *facility);
+extern char *log_get_default(void);
+
+extern void log_feature_unmark(void);
+extern int log_feature_mark(int flag);
+extern void log_feature_report(struct Client *to, int flag);
+
+extern int log_inassert;
+
+#endif /* INCLUDED_ircd_log_h */
+
+/* The rest of this file implements our own custom version of assert.
+ * This version will log the assertion failure using the LS_SYSTEM log
+ * stream, thus putting the assertion failure message into a useful
+ * place, rather than elsewhere, as is currently the case...
+ */
+
+/* We've been included twice; clean up before creating assert() again */
+#ifdef _ircd_log_assert
+# undef _ircd_log_assert
+# undef assert
+#endif
+
+/* gcc has a nice way of hinting that an expression is expected to
+ * produce a specific result, which can improve optimization.
+ * Unfortunately, all the world's not gcc (at least, not yet), and not
+ * all gcc's support it.  I don't know exactly when it appeared, but
+ * it does appear to be in all versions from 3 and up.  So, we'll
+ * create a dummy define if (we think) this version of gcc doesn't
+ * have it...
+ */
+#ifndef _log_builtin_expect
+# define _log_builtin_expect
+# if __GNUC__ < 3
+#  define __builtin_expect(expr, expect)       (expr)
+# endif
+#endif
+
+/* let's try not to clash with the system assert()... */
+#ifndef assert
+# ifdef NDEBUG
+#  define assert(expr) ((void)0)
+# else
+#  define assert(expr)                                                       \
+  ((void)(__builtin_expect(!!(expr), 1) ? 0 :                                \
+         (__builtin_expect(log_inassert, 0) ? (abort(), 0) :                 \
+          ((log_inassert = 1), /* inhibit looping in assert() */             \
+           log_write(LS_SYSTEM, L_CRIT, 0, "Assertion failure at %s:%d: "    \
+                     "\"%s\"", __FILE__, __LINE__, #expr), abort(), 0))))
+# endif
+#endif
diff --git a/include/ircd_md5.h b/include/ircd_md5.h
new file mode 100644 (file)
index 0000000..bf64a67
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ * IRC - Internet Relay Chat, include/ircd_md5.h
+ *
+ * This code implements the MD5 message-digest algorithm.
+ * The algorithm is due to Ron Rivest.  This code was
+ * written by Colin Plumb in 1993, no copyright is claimed.
+ * This code is in the public domain; do with it what you wish.
+ *
+ * Equivalent code is available from RSA Data Security, Inc.
+ * This code has been tested against that, and is equivalent,
+ * except that you don't need to include two pages of legalese
+ * with every copy.
+ *
+ * ircuified 2002 by hikari
+ */
+/** @file
+ * @brief MD5 implementation for ircu.
+ * @version $Id: ircd_md5.h 1234 2004-10-05 22:51:47Z entrope $
+ */
+#ifndef ircd_md5_h
+#define ircd_md5_h
+
+/** Typedef for an unsigned 32-bit integer. */
+typedef unsigned int uint32;
+
+/** MD5 context structure. */
+struct MD5Context {
+       uint32 buf[4];        /**< Current digest state/value. */
+       uint32 bits[2];       /**< Number of bits hashed so far. */
+       unsigned char in[64]; /**< Residual input buffer. */
+};
+
+void MD5Init(struct MD5Context *);
+void MD5Update(struct MD5Context *, unsigned const char *, unsigned);
+void MD5Final(unsigned char digest[16], struct MD5Context *);
+void MD5Transform(uint32 buf[4], uint32 const in[16]);
+
+char *crypt_md5(const char *pw, const char *salt);
+
+/** Helper typedef for the MD5 context structure. */
+typedef struct MD5Context MD5_CTX;
+
+#endif /* ircd_md5_h */
diff --git a/include/ircd_osdep.h b/include/ircd_osdep.h
new file mode 100644 (file)
index 0000000..7c780c7
--- /dev/null
@@ -0,0 +1,59 @@
+/** @file ircd_osdep.h
+ * @brief Public definitions and APIs for OS-dependent operations.
+ * @version $Id: ircd_osdep.h 1626 2006-03-14 03:45:52Z entrope $
+ */
+#ifndef INCLUDED_ircd_osdep_h
+#define INCLUDED_ircd_osdep_h
+
+struct Client;
+struct irc_sockaddr;
+struct MsgQ;
+
+/** Result of an input/output operation. */
+typedef enum IOResult {
+  IO_FAILURE = -1, /**< Serious I/O error (not due to blocking). */
+  IO_BLOCKED = 0,  /**< I/O could not start because it would block. */
+  IO_SUCCESS = 1   /**< I/O succeeded. */
+} IOResult;
+
+/*
+ * NOTE: osdep.c files should never need to know the actual size of a
+ * Client struct. When passed as a parameter, the pointer just needs
+ * to be forwarded to the enumeration function.
+ */
+/** Callback function to show rusage information.
+ * @param cptr Client to receive the message.
+ * @param msg Text message to send to user.
+ */
+typedef void (*EnumFn)(struct Client* cptr, const char* msg);
+
+extern int os_disable_options(int fd);
+extern int os_get_rusage(struct Client* cptr, int uptime, EnumFn enumerator);
+extern int os_get_sockerr(int fd);
+extern int os_get_sockname(int fd, struct irc_sockaddr* sin_out);
+extern int os_get_peername(int fd, struct irc_sockaddr* sin_out);
+extern int os_socket(const struct irc_sockaddr* local, int type, const char* port_name, int family);
+extern int os_accept(int fd, struct irc_sockaddr* peer);
+extern IOResult os_sendto_nonb(int fd, const char* buf, unsigned int length,
+                               unsigned int* length_out, unsigned int flags,
+                               const struct irc_sockaddr* peer);
+extern IOResult os_recv_nonb(int fd, char* buf, unsigned int length,
+                        unsigned int* length_out);
+extern IOResult os_send_nonb(int fd, const char* buf, unsigned int length,
+                        unsigned int* length_out);
+extern IOResult os_sendv_nonb(int fd, struct MsgQ* buf,
+                             unsigned int* len_in, unsigned int* len_out);
+extern IOResult os_recvfrom_nonb(int fd, char* buf, unsigned int len,
+                                 unsigned int* length_out,
+                                 struct irc_sockaddr* from_out);
+extern IOResult os_connect_nonb(int fd, const struct irc_sockaddr* sin);
+extern int os_set_fdlimit(unsigned int max_descriptors);
+extern int os_set_listen(int fd, int backlog);
+extern int os_set_nonblocking(int fd);
+extern int os_set_reuseaddr(int fd);
+extern int os_set_sockbufs(int fd, unsigned int ssize, unsigned int rsize);
+extern int os_set_tos(int fd,int tos);
+extern int os_socketpair(int sv[2]);
+
+#endif /* INCLUDED_ircd_osdep_h */
+
diff --git a/include/ircd_relay.h b/include/ircd_relay.h
new file mode 100644 (file)
index 0000000..7ca6737
--- /dev/null
@@ -0,0 +1,49 @@
+#ifndef INCLUDED_IRCD_RELAY_H
+#define INCLUDED_IRCD_RELAY_H
+/*
+ * IRC - Internet Relay Chat, include/ircd_relay.h
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ *                    University of Oulu, Computing Center
+ *
+ * See file AUTHORS in IRC package for additional names of
+ * the programmers.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+/** @file
+ * @brief Interface to functions for relaying messages.
+ * @version $Id: ircd_relay.h 1231 2004-10-05 04:21:37Z entrope $
+ */
+
+struct Client;
+
+extern void relay_channel_message(struct Client* sptr, const char* name, const char* text, const int ccount);
+extern void relay_channel_notice(struct Client* sptr, const char* name, const char* text, const int ccount);
+extern int relay_directed_account_server_message(struct Client* sptr, char* name, char* server, const char* text);
+extern void relay_directed_message(struct Client* sptr, char* name, char* server, const char* text);
+extern void relay_directed_notice(struct Client* sptr, char* name, char* server, const char* text);
+extern void relay_masked_message(struct Client* sptr, const char* mask, const char* text);
+extern void relay_masked_notice(struct Client* sptr, const char* mask, const char* text);
+extern void relay_private_message(struct Client* sptr, const char* name, const char* text);
+extern void relay_private_notice(struct Client* sptr, const char* name, const char* text);
+
+extern void server_relay_channel_message(struct Client* sptr, const char* name, const char* text);
+extern void server_relay_channel_notice(struct Client* sptr, const char* name, const char* text);
+extern void server_relay_masked_message(struct Client* sptr, const char* mask, const char* text);
+extern void server_relay_masked_notice(struct Client* sptr, const char* mask, const char* text);
+extern void server_relay_private_message(struct Client* sptr, const char* name, const char* text);
+extern void server_relay_private_notice(struct Client* sptr, const char* name, const char* text);
+
+#endif /* INCLUDED_IRCD_RELAY_H */
diff --git a/include/ircd_reply.h b/include/ircd_reply.h
new file mode 100644 (file)
index 0000000..69636cf
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * IRC - Internet Relay Chat, include/ircd_reply.h
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ *                    University of Oulu, Computing Center
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+/** @file
+ * @brief Interfaces for sending common replies to users.
+ * @version $Id: ircd_reply.h 1224 2004-10-05 02:39:38Z entrope $
+ */
+#ifndef INCLUDED_ircd_reply_h
+#define INCLUDED_ircd_reply_h
+
+struct Client;
+
+extern int protocol_violation(struct Client* cptr, const char* pattern, ...);
+extern int need_more_params(struct Client* cptr, const char* cmd);
+extern int send_reply(struct Client* to, int reply, ...);
+
+#define SND_EXPLICIT   0x40000000      /**< first arg is a pattern to use */
+
+#endif /* INCLUDED_ircd_reply_h */
+
diff --git a/include/ircd_reslib.h b/include/ircd_reslib.h
new file mode 100644 (file)
index 0000000..63bec77
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ * include/ircd_reslib.h
+ * (C)opyright 1992 Darren Reed.
+ */
+/** @file
+ * @brief Interface from ircd resolver to its support functions.
+ * @version $Id: ircd_reslib.h 1231 2004-10-05 04:21:37Z entrope $
+ */
+#ifndef INCLUDED_ircdreslib_h
+#define INCLUDED_ircdreslib_h
+
+#include <netdb.h>
+
+/*
+ * Inline versions of get/put short/long.  Pointer is advanced.
+ */
+/** Get a 16-bit network endian value from \a cp and assign to \a s. */
+#define IRC_NS_GET16(s, cp) { \
+       const unsigned char *t_cp = (const unsigned char *)(cp); \
+       (s) = ((uint16_t)t_cp[0] << 8) \
+           | ((uint16_t)t_cp[1]) \
+           ; \
+       (cp) += NS_INT16SZ; \
+}
+
+/** Get a 32-bit network endian value from \a cp and assign to \a s. */
+#define IRC_NS_GET32(l, cp) { \
+       const unsigned char *t_cp = (const unsigned char *)(cp); \
+       (l) = ((uint32_t)t_cp[0] << 24) \
+           | ((uint32_t)t_cp[1] << 16) \
+           | ((uint32_t)t_cp[2] << 8) \
+           | ((uint32_t)t_cp[3]) \
+           ; \
+       (cp) += NS_INT32SZ; \
+}
+
+/** Put \a s at \a cp as a 16-bit network endian value. */
+#define IRC_NS_PUT16(s, cp) { \
+       uint16_t t_s = (uint16_t)(s); \
+       unsigned char *t_cp = (unsigned char *)(cp); \
+       *t_cp++ = t_s >> 8; \
+       *t_cp   = t_s; \
+       (cp) += NS_INT16SZ; \
+}
+
+/** Put \a s at \a cp as a 32-bit network endian value. */
+#define IRC_NS_PUT32(l, cp) { \
+       uint32_t t_l = (uint32_t)(l); \
+       unsigned char *t_cp = (unsigned char *)(cp); \
+       *t_cp++ = t_l >> 24; \
+       *t_cp++ = t_l >> 16; \
+       *t_cp++ = t_l >> 8; \
+       *t_cp   = t_l; \
+       (cp) += NS_INT32SZ; \
+}
+
+/** Maximum number of nameservers to bother with. */
+#define IRCD_MAXNS 8
+
+int irc_res_init(void);
+int irc_dn_expand(const unsigned char *msg, const unsigned char *eom, const unsigned char *src, char *dst, int dstsiz);
+int irc_ns_name_uncompress(const unsigned char *msg, const unsigned char *eom, const unsigned char *src, char *dst, size_t dstsiz);
+int irc_ns_name_unpack(const unsigned char *msg, const unsigned char *eom, const unsigned char *src, unsigned char *dst, size_t dstsiz);
+int irc_ns_name_ntop(const char *src, char *dst, size_t dstsiz);
+int irc_dn_comp(const char *src, unsigned char *dst, int dstsiz, unsigned char **dnptrs, unsigned char **lastdnptr);
+int irc_dn_skipname(const unsigned char *ptr, const unsigned char *eom);
+int irc_ns_name_skip(const unsigned char **ptrptr, const unsigned char *eom);
+unsigned int irc_ns_get16(const unsigned char *src);
+unsigned long irc_ns_get32(const unsigned char *src);
+void irc_ns_put16(unsigned int src, unsigned char *dst);
+void irc_ns_put32(unsigned long src, unsigned char *dst);
+int irc_ns_name_pton(const char *src, unsigned char *dst, size_t dstsiz);
+int irc_ns_name_pack(const unsigned char *src, unsigned char *dst, int dstsiz, const unsigned char **dnptrs, const unsigned char **lastdnptr);
+int irc_res_mkquery(const char *dname, int class, int type, unsigned char *buf, int buflen);
+#endif /* INCLUDED_res_h */
diff --git a/include/ircd_signal.h b/include/ircd_signal.h
new file mode 100644 (file)
index 0000000..9e292a1
--- /dev/null
@@ -0,0 +1,16 @@
+/** @file ircd_signal.h
+ * @brief Interface to signal handler subsystem.
+ * @version $Id: ircd_signal.h 1618 2006-02-16 03:27:41Z entrope $
+ */
+#ifndef INCLUDED_ircd_signal_h
+#define INCLUDED_ircd_signal_h
+
+typedef void (*SigChldCallBack)(pid_t child_pid, void *datum, int status);
+
+extern void setup_signals(void);
+extern void register_child(pid_t child, SigChldCallBack call, void *datum);
+extern void unregister_child(pid_t child);
+extern void reap_children(void);
+
+#endif /* INCLUDED_ircd_signal_h */
+
diff --git a/include/ircd_snprintf.h b/include/ircd_snprintf.h
new file mode 100644 (file)
index 0000000..873a556
--- /dev/null
@@ -0,0 +1,321 @@
+#ifndef INCLUDED_ircd_snprintf_h
+#define INCLUDED_ircd_snprintf_h
+/*
+ * IRC - Internet Relay Chat, include/ircd_snprintf.h
+ * Copyright (C) 2000 Kevin L. Mitchell <klmitch@mit.edu>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+/** @file
+ * @brief IRC-specific printf() clone interface.
+ * @version $Id: ircd_snprintf.h 1231 2004-10-05 04:21:37Z entrope $
+ */
+#ifndef INCLUDED_sys_types_h
+#include <sys/types.h>
+#define INCLUDED_sys_types_h
+#endif
+#ifndef INCLUDED_stdarg_h
+#include <stdarg.h>
+#define INCLUDED_stdarg_h
+#endif
+
+struct Client;
+
+/** structure passed as argument for %v conversion */
+struct VarData {
+  size_t       vd_chars;       /**< number of characters inserted */
+  size_t       vd_overflow;    /**< number of characters that couldn't be */
+  const char   *vd_format;     /**< format string */
+  va_list      vd_args;        /**< arguments for %v */
+};
+
+#ifndef HAVE_VA_COPY
+#if HAVE___VA_COPY
+#define va_copy(DEST, SRC) __va_copy(DEST, SRC)
+#else
+/** Fallback macro to copy to \a DEST from \a SRC. */
+#define va_copy(DEST, SRC) memcpy(&(DEST), &(SRC), sizeof(DEST))
+#endif
+#endif
+
+extern int ircd_snprintf(struct Client *dest, char *buf, size_t buf_len,
+                        const char *format, ...);
+extern int ircd_vsnprintf(struct Client *dest, char *buf, size_t buf_len,
+                         const char *format, va_list args);
+
+/** @fn int ircd_snprintf(struct Client *dest, char *buf, size_t
+                        buf_len, const char *format, ...)
+**
+**   These functions are intended to be a complete replacement for
+** sprintf and sprintf_irc.  They are a (nearly) complete
+** reimplementation, and of course they're snprintf clones, making it
+** more difficult for accidental buffer overflows to crop up.
+**
+**   First off, what's missing?  These functions support all ANSI C
+** conversion specifiers and selected ones from ISO 9x, with the
+** exception of all floating-point conversions.  The floating-point
+** conversions are tricky, and will likely be dependent on the
+** representation of a floating-point number on a particular
+** architecture.  While that representation is likely to conform to
+** some standard, it is not currently used in ircu, so seemed like a
+** good thing to omit, given the difficulty of implementing it.
+**
+**   There are two more things missing from this implementation that
+** would be required by ANSI; the first is support for multibyte
+** character strings, and the second is support for locales, neither
+** of which have any relevance for ircu, so again omission seemed to
+** be a good policy.  Additionally, %#x always causes '0x' (or '0X')
+** to be printed, even if the number is zero.
+**
+**   These functions also have some extensions not seen in a
+** standards-compliant implementation; technically, the ISO 9x
+** extensions fall into this category, for instance.  The ISO 9x
+** extensions supported are type extensions--%ju, %tu, and %zu, for
+** instance; %qu and %hhu are also supported.  The extensions added
+** for use in ircu are %Tu, which takes a time_t, and the new %C
+** conversion, which inserts either a numeric or a nick, dependant on
+** the &lt;dest> parameter.  The GNU %m extension, which inserts the
+** strerror() string corresponding to the current value of errno, is
+** also supported, as is a special %v extension, which essentially
+** does a recursive call to ircd_snprintf.
+**
+**   The following description is descended from the Linux manpage for
+** the printf family of functions.
+**
+**   The format string is composed of zero or more directives:
+** ordinary characters (not %), which are copied unchanged to the
+** output stream; and conversion specifications, each of which results
+** in fetching zero or more subsequent arguments.  Each conversion
+** specification is introduced by the character %.  The arguments must
+** correspond properly (after type promotion) with the conversion
+** specifier.  After the %, the following appear in sequence:
+**
+** <ul><li>Zero or more of the following flags:<dl>
+**
+** <dt>#</dt>
+**      <dd>specifying that the value should be converted to an
+**     "alternate form."  For c, d, i, n, p, s, and u conversions,
+**     this option has no effect.  For o conversions, the precision
+**     of the number is increased to force the first character of the
+**     output string to a zero (except if a zero value is printed
+**     with an explicit precision of zero).  For x and X conversions,
+**     the string '0x' (or '0X' for X conversions) is prepended to
+**     it.  For e, E, f, g, and G conversions, the result will always
+**     contain a decimal point, even if no digits follow it
+**     (normally, a decimal point appears in the results of those
+**     conversions only if a digit follows).  For g and G
+**     conversions, trailing zeros are not removed from the result as
+**     they would otherwise be.  For C conversions, if the
+**     destination is local and the origin is a user, the
+**     nick!user\@host form is used.</dd>
+**
+** <dt>0</dt>
+**      <dd> specifying zero padding.  For all conversions except n, the
+**     converted value is padded on the left with zeros rather than
+**     blanks.  If a precision is given with a numeric conversion (d,
+**     i, o, u, i, x, and X), the 0 flag is ignored.</dd>
+**
+** <dt>-</dt>
+**      <dd>(a negative field width flag) indicates the converted value is
+**     to be left adjusted on the field boundary.  Except for n
+**     conversions, the converted value is padded on the right with
+**     blanks, rather than on the left with blanks or zeros.  A -
+**     overrides a 0 if both are given.</dd>
+**
+** <dt>' ' (a space)</dt>
+**      <dd>specifying that a blank should be left before a
+**     positive number produced by a signed conversion (d, e, E, f,
+**     g, G, or i).</dd>
+**
+** <dt>+</dt>
+**      <dd>specifying that a sign always be placed before a number
+**     produced by a signed conversion.  A + overrides a space if
+**     both are used.</dd>
+**
+** <dt>:</dt>
+**      <dd>specifying that a struct Client name should be preceded by a
+**     ':' character if the destination is a user.</dd>
+** </dl></li>
+**
+** <li>An optional decimal digit string specifying a minimum field
+**   width.  If the converted value has fewer characters than the
+**   field width, it will be padded with spaces on the left (or right,
+**   if the left-adjustment flag has been given) to fill out the field
+**   width.</li>
+**
+** <li>An optional precision, in the form of a period (`.') followed by
+**   an optional digit string.  If  the digit string is omitted, the
+**   precision is taken as zero.  This gives the minimum number of
+**   digits to appear for d, i, o, u, x, and X conversions, the number
+**   of digits to appear after the decimal-point for e, E, and f
+**   conversions, the maximum number of significant digits for g and G
+**   conversions, or the maximum number of characters to be printed
+**   from a string for s conversions.</li>
+**
+** <li>The optional character h, specifying that a following d, i, o, u,
+**   x, or X conversion corresponds to a short int or unsigned short
+**   int argument, or that a following n conversion corresponds to a
+**   pointer to a short int argument.  If the h character is given
+**   again, char is used instead of short int.</li>
+**
+** <li>The optional character l (ell) specifying that a following d, i,
+**   o, u, x, or X conversion applies to a pointer to a long int or
+**   unsigned long int argument, or that a following n conversion
+**   corresponds to a pointer to a long int argument.</li>
+**
+** <li>The character L specifying that a following e, E, f, g, or G
+**   conversion corresponds to a long double argument, or a following
+**   d, i, o, u, x, or X conversion corresponds to a long long
+**   argument.  Note that long long is not specified in ANSI C and
+**   therefore not portable to all architectures.</li>
+**
+** <li>The optional character q.  This is equivalent to L.</li>
+**
+** <li>A j character specifying that the following integer (d, i, o, u,
+**   x, or X) conversion corresponds to an intmax_t argument.</li>
+**
+** <li>A t character specifying that the following integer (d, i, o, u,
+**   x, or X) conversion corresponds to a ptrdiff_t argument.</li>
+**
+** <li>A z character specifying that the following integer (d, i, o, u,
+**   x, or X) conversion corresponds to a size_t argument.</li>
+**
+** <li>A T character specifying that the following integer (d, i, o, u,
+**   x, or X) conversion corresponds to a time_t argument.</li>
+**
+** <li>A character that specifies the type of conversion to be applied.</li>
+** </ul>
+**
+**   A field width or precision, or both, may be indicated by an
+** asterisk `*' instead of a digit string.  In this case, an int
+** argument supplies the field width or precision.  A negative field
+** width is treated as a left adjustment flag followed by a positive
+** field width; a negative precision is treated as though it were
+** missing.
+**
+** The conversion specifiers and their meanings are:
+**
+** <dl>
+** <dt>diouxX</dt>
+**             <dd>The int (or appropriate variant) argument is converted
+**             to signed decimal (d and i), unsigned octal (o),
+**             unsigned decimal (u), or unsigned hexadecimal (x and
+**             X) notation.  The letters abcdef are used for x
+**             conversions; the letters ABCDEF are used for X
+**             conversions.  The precision, if any, gives the minimum
+**             number of digits that must appear; if the converted
+**             value requires fewer digits, it is padded on the left
+**             with zeros.</dd>
+**
+** <dt>eE [NOT IMPLEMENTED]</dt>
+**             <dd>The double argument is rounded and
+**             converted in the style [-]d.dddedd where there is one
+**             digit before the decimal-point character and the
+**             number of digits after it is equal to the precision;
+**             if the precision is missing, it is taken as 6; if the
+**             precision is zero, no decimal-point character appears.
+**             An E conversion uses the letter E (rather than e) to
+**             introduce the exponent.  The exponent always contains
+**             at least two digits; if the value is zero, the
+**             exponent is 00.</dd>
+**
+** <dt>f [NOT IMPLEMENTED]</dt>
+**             <dd>The double argument is rounded and
+**             converted to  decimal notation in the style
+**             [-]ddd.ddd, where the number of digits after the
+**             decimal-point character is equal to the precision
+**             specification.  If the precision is missing, it is
+**             taken as 6; if the precision is explicitly zero, no
+**             decimal-point character appears.  If a decimal point
+**             appears, at least one digit appears before it.</dd>
+**
+** <dt>g [NOT IMPLEMENTED]</dt>
+**             <dd>The double argument is converted in
+**             style f or e (or E for G conversions).  The precision
+**             specifies the number of significant digits.  If the
+**             precision is missing, 6 digits are given; if the
+**             precision is zero, it is treated as 1.  Style e is
+**             used if the exponent from its conversion is less than
+**             -4 or greater than or equal to the precision.
+**             Trailing zeros are removed from the fractional part of
+**             the result; a decimal point appears only if it is
+**             followed by at least one digit.</dd>
+**
+** <dt>c</dt>
+**             <dd>The int argument is converted to an unsigned char, and
+**             the resulting character is written.</dd>
+**
+** <dt>s</dt>
+**             <dd>The "char *" argument is expected to be a pointer to
+**             an array of character type (pointer to a string).
+**             Characters from the array are written up to (but not
+**             including) a terminating NUL character; if a precision
+**             is specified, no more than the number specified are
+**             written.  If a precision is given, no null character
+**             need be present; if the precision is not specified, or
+**             is greater than the size of the array, the array must
+**             contain a terminating NUL character.</dd>
+**
+** <dt>p</dt>
+**             <dd>The "void *" pointer argument is printed in
+**             hexadecimal (as if by %#x or %#lx).</dd>
+**
+** <dt>n</dt>
+**             <dd>The number of characters written so far is stored into
+**             the integer indicated by the ``int *'' (or variant)
+**             pointer argument.  No argument is converted.</dd>
+**
+** <dt>m</dt>
+**             <dd>The error message associated with the current value of
+**             errno is printed as if by %s.</dd>
+**
+** <dt>C</dt>
+**             <dd>The client argument identifier is printed under the
+**             control of the &lt;dest> argument; if &lt;dest> is NULL or
+**             is a user, the client's name (nickname or server name)
+**             is printed; otherwise, the client's network numeric is
+**             printed.</dd>
+**
+** <dt>H</dt>
+**             <dd>The channel argument identifier (channel name) is
+**             printed.</dd>
+**
+** <dt>v</dt>
+**             <dd>The argument given must be a pointer to a struct
+**             VarData with vd_format and vd_args must be initialized
+**             appropriately.  On return, vd_chars will contain the
+**             number of characters added to the buffer, and
+**             vd_overflow will contain the number of characters that
+**             could not be added due to buffer overflow or due to a
+**             precision.</dd>
+**
+** <dt>%<dt>
+**             <dd>A `%' is written.  No argument is converted.  The
+**             complete conversion specification is `%%'.</dd>
+** </dl>
+**
+**   In no case does a non-existent or small field width cause
+** truncation of a field; if the result of a conversion is wider than
+** the field width, the field is expanded to contain the conversion
+** result.
+**
+** @param[in] dest Client receiving of message.
+** @param[out] buf Output buffer for formatted message.
+** @param[in] buf_len Number of bytes that can be written to \a buf.
+** @param[in] format Format string for message.
+** @return Number of bytes that would be written to \a buf without truncation.
+*/
+
+#endif /* INCLUDED_ircd_snprintf_h */
diff --git a/include/ircd_string.h b/include/ircd_string.h
new file mode 100644 (file)
index 0000000..abfcf48
--- /dev/null
@@ -0,0 +1,117 @@
+/** @file ircd_string.h
+ * @brief Public declarations and APIs for string operations.
+ * @version $Id: ircd_string.h 1478 2005-09-12 03:40:17Z entrope $
+ */
+#ifndef INCLUDED_ircd_string_h
+#define INCLUDED_ircd_string_h
+
+#include <string.h> /* for DupString()'s strcpy, strlen */
+
+#ifndef INCLUDED_ircd_chattr_h
+#include "ircd_chattr.h"
+#endif
+
+struct irc_in_addr;
+
+/*
+ * Macros
+ */
+/** Check whether \a x is a NULL or empty string. */
+#define EmptyString(x) (!(x) || !(*x))
+
+extern int string_has_wildcards(const char* str);
+extern char*       ircd_strncpy(char* dest, const char* src, size_t len);
+extern int         ircd_strcmp(const char *a, const char *b);
+extern int         ircd_strncmp(const char *a, const char *b, size_t n);
+extern int         unique_name_vector(char* names, char token,
+                                      char** vector, int size);
+extern int         token_vector(char* names, char token,
+                                char** vector, int size);
+extern const char* ircd_ntoa(const struct irc_in_addr* addr);
+extern const char* ircd_ntoa_r(char* buf, const struct irc_in_addr* addr);
+#define ircd_aton(ADDR, STR) ipmask_parse((STR), (ADDR), NULL)
+extern int ipmask_parse(const char *in, struct irc_in_addr *mask, unsigned char *bits_ptr);
+extern char*       host_from_uh(char* buf, const char* userhost, size_t len);
+extern char*       ircd_strtok(char** save, char* str, char* fs);
+
+extern char*       canonize(char* buf);
+
+/** Make \a y a duplicate \a x, a la strdup(). */
+#define DupString(x, y)  (strcpy((x = (char*) MyMalloc(strlen(y) + 1)), y))
+
+
+/* String classification pseudo-functions, when others are needed add them,
+   strIsXxxxx(s) is true when IsXxxxx(c) is true for every char in s */
+
+/** Test whether all characters in \a s are alphanumeric. */
+#define strIsAlnum(s)     (strChattr(s) & NTL_ALNUM)
+/** Test whether all characters in \a s are alphabetic. */
+#define strIsAlpha(s)     (strChattr(s) & NTL_ALPHA)
+/** Test whether all characters in \a s are digits. */
+#define strIsDigit(s)     (strChattr(s) & NTL_DIGIT)
+/** Test whether all characters in \a s are lower case. */
+#define strIsLower(s)     (strChattr(s) & NTL_LOWER)
+/** Test whether all characters in \a s are whitespace. */
+#define strIsSpace(s)     (strChattr(s) & NTL_SPACE)
+/** Test whether all characters in \a s are upper case. */
+#define strIsUpper(s)     (strChattr(s) & NTL_UPPER)
+
+/** Test whether all characters in \a s are channel name characters. */
+#define strIsIrcCh(s)     (strChattr(s) & NTL_IRCCH)
+/** Test whether all characters in \a s are forced to lower-case in channel names. */
+#define strIsIrcCl(s)     (strChattr(s) & NTL_IRCCL)
+/** Test whether all characters in \a s are valid in nicknames. */
+#define strIsIrcNk(s)     (strChattr(s) & NTL_IRCNK)
+/** Test whether all characters in \a s are valid in a user field. */
+#define strIsIrcUi(s)     (strChattr(s) & NTL_IRCUI)
+/** Test whether all characters in \a s are valid in host names. */
+#define strIsIrcHn(s)     (strChattr(s) & NTL_IRCHN)
+/** Test whether all characters in \a s are valid in IP addresses. */
+#define strIsIrcIp(s)     (strChattr(s) & NTL_IRCIP)
+
+/*
+ * Critical small functions to inline even in separate compilation
+ * when FORCEINLINE is defined (provided you have a compiler that supports
+ * `inline').
+ */
+
+/** Declaration for strChattr(). */
+#define NTL_HDR_strChattr   unsigned int strChattr(const char *s)
+
+/** Body for strChattr(). */
+#define NTL_SRC_strChattr   const char *rs = s; \
+                            unsigned int x = ~0; \
+                            while(*rs) \
+                              x &= IRCD_CharAttrTab[*rs++ - CHAR_MIN]; \
+                            return x;
+
+/*
+ * XXX - bleah should return 1 if different 0 if the same
+ */
+/** Declaration for strCasediff(). */
+#define NTL_HDR_strCasediff int strCasediff(const char *a, const char *b)
+
+/** Body for strCasediff(). */
+#define NTL_SRC_strCasediff const char *ra = a; \
+                            const char *rb = b; \
+                            while(ToLower(*ra) == ToLower(*rb++)) \
+                              if(!*ra++) \
+                                return 0; \
+                            return 1;
+
+#ifndef FORCEINLINE
+extern NTL_HDR_strChattr;
+extern NTL_HDR_strCasediff;
+
+#else /* FORCEINLINE */
+#ifdef __cplusplus
+inline NTL_HDR_strChattr { NTL_SRC_strChattr }
+inline NTL_HDR_strCasediff { NTL_SRC_strCasediff }
+#else
+static __inline__ NTL_HDR_strChattr { NTL_SRC_strChattr }
+static __inline__ NTL_HDR_strCasediff { NTL_SRC_strCasediff }
+#endif
+#endif /* FORCEINLINE */
+
+#endif /* INCLUDED_ircd_string_h */
+
diff --git a/include/jupe.h b/include/jupe.h
new file mode 100644 (file)
index 0000000..b282c19
--- /dev/null
@@ -0,0 +1,87 @@
+#ifndef INCLUDED_jupe_h
+#define INCLUDED_jupe_h
+/*
+ * IRC - Internet Relay Chat, include/jupe.h
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ *                    University of Oulu, Computing Center
+ * Copyright (C) 2000 Kevin L. Mitchell <klmitch@mit.edu>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+/** @file
+ * @brief  Interface and declarations for juped server handling.
+ * @version $Id: jupe.h 1208 2004-10-03 14:12:35Z entrope $
+ */
+#ifndef INCLUDED_sys_types_h
+#include <sys/types.h>
+#define INCLUDED_sys_types_h
+#endif
+
+
+struct Client;
+
+#define JUPE_MAX_EXPIRE        604800  /**< Maximum jupe expiration time (7 days). */
+
+/** Describes a juped server.
+ * A hub will not accept new connections from a juped server.
+ */
+struct Jupe {
+  struct Jupe*   ju_next;    /**< Pointer to next Jupe. */
+  struct Jupe**  ju_prev_p;  /**< Pointer to previous next pointer. */
+  char*          ju_server;  /**< Name of server to jupe. */
+  char*          ju_reason;  /**< Reason for the jupe. */
+  time_t         ju_expire;  /**< Expiration time of the jupe. */
+  time_t         ju_lastmod; /**< Last modification time (if any) for the jupe. */
+  unsigned int   ju_flags;   /**< Status flags for the jupe. */
+};
+
+#define JUPE_ACTIVE    0x0001  /**< Jupe is globally active. */
+#define JUPE_LOCAL     0x0002  /**< Jupe only applies to this server. */
+#define JUPE_LDEACT    0x0004  /**< Jupe is locally deactivated */
+
+#define JUPE_MASK      (JUPE_ACTIVE | JUPE_LOCAL)
+#define JUPE_ACTMASK   (JUPE_ACTIVE | JUPE_LDEACT)
+
+/** Test whether \a j is active. */
+#define JupeIsActive(j)                (((j)->ju_flags & JUPE_ACTMASK) == JUPE_ACTIVE)
+/** Test whether \a j is globally (remotely) active. */
+#define JupeIsRemActive(j)     ((j)->ju_flags & JUPE_ACTIVE)
+/** Test whether \a j is local. */
+#define JupeIsLocal(j)         ((j)->ju_flags & JUPE_LOCAL)
+
+/** Get the server name for \a j. */
+#define JupeServer(j)          ((j)->ju_server)
+/** Get the reason fro \a j. */
+#define JupeReason(j)          ((j)->ju_reason)
+/** Get the last modification time for \a j. */
+#define JupeLastMod(j)         ((j)->ju_lastmod)
+
+extern int jupe_add(struct Client *cptr, struct Client *sptr, char *server,
+                   char *reason, time_t expire, time_t lastmod,
+                   unsigned int flags);
+extern int jupe_activate(struct Client *cptr, struct Client *sptr,
+                        struct Jupe *jupe, time_t lastmod,
+                        unsigned int flags);
+extern int jupe_deactivate(struct Client *cptr, struct Client *sptr,
+                          struct Jupe *jupe, time_t lastmod,
+                          unsigned int flags);
+extern struct Jupe* jupe_find(char *server);
+extern void jupe_free(struct Jupe *jupe);
+extern void jupe_burst(struct Client *cptr);
+extern int jupe_resend(struct Client *cptr, struct Jupe *jupe);
+extern int jupe_list(struct Client *sptr, char *server);
+extern int jupe_memory_count(size_t *ju_size);
+
+#endif /* INCLUDED_jupe_h */
diff --git a/include/list.h b/include/list.h
new file mode 100644 (file)
index 0000000..4f6c563
--- /dev/null
@@ -0,0 +1,63 @@
+/** @file list.h
+ * @brief Singly and doubly linked list manipulation interface.
+ * @version $Id: list.h 1417 2005-05-30 21:07:33Z entrope $
+ */
+#ifndef INCLUDED_list_h
+#define INCLUDED_list_h
+#ifndef INCLUDED_sys_types_h
+#include <sys/types.h>         /* time_t, size_t */
+#define INCLUDED_sys_types_h
+#endif
+
+struct Client;
+struct Connection;
+struct Channel;
+struct ConfItem;
+
+/*
+ * Structures
+ */
+
+/** Node in a singly linked list. */
+struct SLink {
+  struct SLink *next; /**< Next element in list. */
+  union {
+    struct Client *cptr;    /**< List element as a client. */
+    struct Channel *chptr;  /**< List element as a channel. */
+    struct ConfItem *aconf; /**< List element as a configuration item. */
+    char *cp;               /**< List element as a string. */
+  } value;                  /**< Value of list element. */
+  unsigned int flags;       /**< Modifier flags for list element. */
+};
+
+/** Node in a doubly linked list. */
+struct DLink {
+  struct DLink*  next;      /**< Next element in list. */
+  struct DLink*  prev;      /**< Previous element in list. */
+  union {
+    struct Client*  cptr;   /**< List element as a client. */
+    struct Channel* chptr;  /**< List element as a channel. */
+    char*           ch;     /**< List element as a string. */
+  } value;                  /**< Value of list element. */
+};
+
+/*
+ * Proto types
+ */
+
+extern void free_link(struct SLink *lp);
+extern struct SLink *make_link(void);
+extern void init_list(void);
+extern struct Client *make_client(struct Client *from, int status);
+extern void free_connection(struct Connection *con);
+extern void free_client(struct Client *cptr);
+extern struct Server *make_server(struct Client *cptr);
+extern void remove_client_from_list(struct Client *cptr);
+extern void add_client_to_list(struct Client *cptr);
+extern struct DLink *add_dlink(struct DLink **lpp, struct Client *cp);
+extern void remove_dlink(struct DLink **lpp, struct DLink *lp);
+extern struct ConfItem *make_conf(int type);
+extern void free_conf(struct ConfItem *aconf);
+extern void send_listinfo(struct Client *cptr, char *name);
+
+#endif /* INCLUDED_list_h */
diff --git a/include/listener.h b/include/listener.h
new file mode 100644 (file)
index 0000000..495bac0
--- /dev/null
@@ -0,0 +1,96 @@
+/* - Internet Relay Chat, include/listener.h
+ *   Copyright (C) 1999 Thomas Helvey <tomh@inxpress.net>
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 1, or (at your option)
+ *   any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+/** @file
+ * @brief Interface and declarations for handling listening sockets.
+ * @version $Id: listener.h 1732 2006-12-07 05:14:51Z entrope $
+ */
+#ifndef INCLUDED_listener_h
+#define INCLUDED_listener_h
+#ifndef INCLUDED_ircd_defs_h
+#include "ircd_defs.h"       /* HOSTLEN */
+#endif
+#ifndef INCLUDED_ircd_events_h
+#include "ircd_events.h"
+#endif
+#ifndef INCLUDED_res_h
+#include "res.h"
+#endif
+#ifndef INCLUDED_client_h
+#include "client.h" /* flagset stuff.  oh well. */
+#endif
+#ifndef INCLUDED_sys_types_h
+#include <sys/types.h>       /* size_t, broken BSD system headers */
+#define INCLUDED_sys_types_h
+#endif
+
+struct Client;
+struct StatDesc;
+
+enum ListenerFlag {
+  /** Port is currently accepting connections. */
+  LISTEN_ACTIVE,
+  /** Port is hidden from /STATS P output. */
+  LISTEN_HIDDEN,
+  /** Port accepts only server connections. */
+  LISTEN_SERVER,
+  /** Port listens for IPv4 connections. */
+  LISTEN_IPV4,
+  /** Port listens for IPv6 connections. */
+  LISTEN_IPV6,
+  /** Port listens for SSL connections. */
+  LISTEN_SSL,
+  /** Sentinel for counting listener flags. */
+  LISTEN_LAST_FLAG
+};
+
+DECLARE_FLAGSET(ListenerFlags, LISTEN_LAST_FLAG);
+
+/** Describes a single listening port. */
+struct Listener {
+  struct Listener* next;               /**< list node pointer */
+  struct ListenerFlags flags;          /**< on-off flags for listener */
+  int              fd_v4;              /**< file descriptor for IPv4 */
+  int              fd_v6;              /**< file descriptor for IPv6 */
+  int              ref_count;          /**< number of connection references */
+  unsigned char    mask_bits;          /**< number of bits in mask address */
+  int              index;              /**< index into poll array */
+  time_t           last_accept;        /**< last time listener accepted */
+  struct irc_sockaddr addr;            /**< virtual address and port */
+  struct irc_in_addr mask;             /**< listener hostmask */
+  struct Socket    socket_v4;          /**< describe IPv4 socket to event system */
+  struct Socket    socket_v6;          /**< describe IPv6 socket to event system */
+};
+
+#define listener_server(LISTENER) FlagHas(&(LISTENER)->flags, LISTEN_SERVER)
+#define listener_active(LISTENER) FlagHas(&(LISTENER)->flags, LISTEN_ACTIVE)
+#define listener_secure(LISTENER) FlagHas(&(LISTENER)->flags, LISTEN_SSL)
+
+extern void        add_listener(int port, const char* vaddr_ip, 
+                                const char* mask,
+                                const struct ListenerFlags *flags);
+extern void        close_listener(struct Listener* listener);
+extern void        close_listeners(void);
+extern void        count_listener_memory(int* count_out, size_t* size_out);
+extern const char* get_listener_name(const struct Listener* listener);
+extern void        mark_listeners_closing(void);
+extern void show_ports(struct Client* client, const struct StatDesc* sd,
+                       char* param);
+extern void        release_listener(struct Listener* listener);
+
+#endif /* INCLUDED_listener_h */
+
diff --git a/include/match.h b/include/match.h
new file mode 100644 (file)
index 0000000..7cf494b
--- /dev/null
@@ -0,0 +1,34 @@
+/** @file match.h
+ * @brief Interface for matching strings to IRC masks.
+ * @version $Id: match.h 1478 2005-09-12 03:40:17Z entrope $
+ */
+#ifndef INCLUDED_match_h
+#define INCLUDED_match_h
+#ifndef INCLUDED_sys_types_h
+#include <sys/types.h>         /* XXX - broken BSD system headers */
+#define INCLUDED_sys_types_h
+#endif
+#ifndef INCLUDED_res_h
+#include "res.h"
+#endif
+
+/*
+ * Prototypes
+ */
+
+/*
+ * XXX - match returns 0 if a match is found. Smelly interface
+ * needs to be fixed. --Bleep
+ */
+extern int mmatch(const char *old_mask, const char *new_mask);
+extern int match(const char *ma, const char *na);
+extern char *collapse(char *pattern);
+
+extern int matchcomp(char *cmask, int *minlen, int *charset, const char *mask);
+extern int matchexec(const char *string, const char *cmask, int minlen);
+extern int matchdecomp(char *mask, const char *cmask);
+extern int mmexec(const char *wcm, int wminlen, const char *rcm, int rminlen);
+
+extern int ipmask_check(const struct irc_in_addr *addr, const struct irc_in_addr *mask, unsigned char bits);
+
+#endif /* INCLUDED_match_h */
diff --git a/include/memdebug.h b/include/memdebug.h
new file mode 100644 (file)
index 0000000..1c92d95
--- /dev/null
@@ -0,0 +1,8 @@
+/* This file should only ever be included from ircd_alloc.h */
+
+void *dbg_malloc(size_t size, const char *type, const char *file, int line);
+void *dbg_malloc_zero(size_t size, const char *type, const char *file, int line);
+void *dbg_realloc(void *ptr, size_t size, const char *file, int line);
+void dbg_free(void *ptr, const char *file, int line);
+size_t fda_get_byte_count(void);
+size_t fda_get_block_count(void);
diff --git a/include/motd.h b/include/motd.h
new file mode 100644 (file)
index 0000000..1bc1431
--- /dev/null
@@ -0,0 +1,110 @@
+#ifndef INCLUDED_motd_h
+#define INCLUDED_motd_h
+/*
+ * IRC - Internet Relay Chat, include/motd.h
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ *                    University of Oulu, Computing Center
+ * Copyright (C) 2000 Kevin L. Mitchell <klmitch@mit.edu>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+/** @file
+ * @brief Message-of-the-day manipulation interface and declarations.
+ * @version $Id: motd.h 1248 2004-10-17 01:58:17Z entrope $
+ */
+
+#ifndef INCLUDED_time_h
+#include <time.h>              /* struct tm */
+#define INCLUDED_time_h
+#endif
+#ifndef INCLUDED_sys_types_h
+#include <sys/types.h>
+#define INCLUDED_sys_types_h
+#endif
+#ifndef INCLUDED_res_H
+#include "res.h"
+#endif
+
+struct Client;
+struct TRecord;
+struct StatDesc;
+
+/** Type of MOTD. */
+enum MotdType {
+    MOTD_UNIVERSAL, /**< MOTD for all users */
+    MOTD_HOSTMASK,  /**< MOTD selected by hostmask */
+    MOTD_IPMASK,    /**< MOTD selected by IP mask */
+    MOTD_CLASS      /**< MOTD selected by connection class */
+};
+
+/** Entry for a single Message Of The Day (MOTD). */
+struct Motd {
+  struct Motd*         next;     /**< Next MOTD in the linked list. */
+  enum MotdType                type;     /**< Type of MOTD. */
+  char*                        hostmask; /**< Hostmask if type==MOTD_HOSTMASK,
+                                     class name if type==MOTD_CLASS,
+                                     text IP mask if type==MOTD_IPMASK. */
+  struct irc_in_addr    address;  /**< Address if type==MOTD_IPMASK. */
+  unsigned char         addrbits; /**< Number of bits checked in Motd::address. */
+  char*                        path;     /**< Pathname of MOTD file. */
+  int                  maxcount; /**< Number of lines for MOTD. */
+  struct MotdCache*    cache;    /**< MOTD cache entry. */
+};
+
+/** Length of one MOTD line(80 chars + '\\0'). */
+#define MOTD_LINESIZE  81
+/** Maximum number of lines for local MOTD */
+#define MOTD_MAXLINES  100
+/** Maximum number of lines for remote MOTD */
+#define MOTD_MAXREMOTE 3
+
+/** Cache entry for the contents of a MOTD file. */
+struct MotdCache {
+  struct MotdCache*    next;     /**< Next MotdCache in list. */
+  struct MotdCache**   prev_p;   /**< Pointer to previous node's next pointer. */
+  int                  ref;      /**< Number of references to this entry. */
+  char*                        path;     /**< Pathname of file. */
+  int                  maxcount; /**< Number of lines allocated for message. */
+  struct tm            modtime;  /**< Last modification time from file. */
+  int                  count;    /**< Actual number of lines used in message. */
+  char                 motd[1][MOTD_LINESIZE]; /**< Message body. */
+};
+
+/* motd_send sends a MOTD off to a user */
+int motd_send(struct Client* cptr);
+
+/* motd_signon sends a MOTD off to a newly-registered user */
+void motd_signon(struct Client* cptr);
+
+/* motd_recache causes all the MOTD caches to be cleared */
+void motd_recache(void);
+
+/* motd_init initializes the MOTD routines, including reading the
+ * ircd.motd and remote.motd files into cache
+ */
+void motd_init(void);
+
+/* This routine adds a MOTD */
+void motd_add(const char *hostmask, const char *path);
+
+/* This routine clears the list of MOTDs */
+void motd_clear(void);
+
+/* This is called to report T-lines */
+void motd_report(struct Client *to, const struct StatDesc *sd,
+                 char *param);
+void motd_memory_count(struct Client *cptr);
+
+#endif /* INCLUDED_motd_h */
diff --git a/include/msg.h b/include/msg.h
new file mode 100644 (file)
index 0000000..a7448d6
--- /dev/null
@@ -0,0 +1,443 @@
+/*
+ * IRC - Internet Relay Chat, include/msg.h
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ *                    University of Oulu, Computing Center
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+/** @file
+ * @brief Command and token declarations and structures.
+ * @version $Id: msg.h 1347 2005-04-02 02:50:15Z entrope $
+ */
+#ifndef INCLUDED_msg_h
+#define INCLUDED_msg_h
+#ifndef INCLUDED_ircd_handler_h
+#include "ircd_handler.h"
+#endif
+
+struct Client;
+
+/*
+ * General defines
+ */
+
+#define MAXPARA    15
+
+/*-----------------------------------------------------------------------------
+ * Macros
+ */
+
+/*
+ * Tokenization:
+ * Each command must have a TOK_COMMAND and MSG_COMMAND definition.
+ * If you don't want one or the other, make them the same.
+ * Also each command has a "msgclass" used for debugging purposes.
+ */
+
+/* *INDENT-OFF* */
+
+#define MSG_PRIVATE             "PRIVMSG"       /* PRIV */
+#define TOK_PRIVATE             "P"
+#define CMD_PRIVATE            MSG_PRIVATE, TOK_PRIVATE
+
+#define MSG_WHO                 "WHO"           /* WHO  -> WHOC */
+#define TOK_WHO                 "H"
+#define CMD_WHO                        MSG_WHO, TOK_WHO
+
+#define MSG_WHOIS               "WHOIS"         /* WHOI */
+#define TOK_WHOIS               "W"
+#define CMD_WHOIS              MSG_WHOIS, TOK_WHOIS
+
+#define MSG_WHOWAS              "WHOWAS"        /* WHOW */
+#define TOK_WHOWAS              "X"
+#define CMD_WHOWAS             MSG_WHOWAS, TOK_WHOWAS
+
+#define MSG_USER                "USER"          /* USER */
+#define TOK_USER                "USER"
+#define CMD_USER               MSG_USER, TOK_USER
+
+#define MSG_NICK                "NICK"          /* NICK */
+#define TOK_NICK                "N"
+#define CMD_NICK               MSG_NICK, TOK_NICK
+
+#define MSG_SERVER              "SERVER"        /* SERV */
+#define TOK_SERVER              "S"
+#define CMD_SERVER             MSG_SERVER, TOK_SERVER
+
+#define MSG_LIST                "LIST"          /* LIST */
+#define TOK_LIST                "LIST"
+#define CMD_LIST               MSG_LIST, TOK_LIST
+
+#define MSG_TOPIC               "TOPIC"         /* TOPI */
+#define TOK_TOPIC               "T"
+#define CMD_TOPIC              MSG_TOPIC, TOK_TOPIC
+
+#define MSG_INVITE              "INVITE"        /* INVI */
+#define TOK_INVITE              "I"
+#define CMD_INVITE             MSG_INVITE, TOK_INVITE
+
+#define MSG_VERSION             "VERSION"       /* VERS */
+#define TOK_VERSION             "V"
+#define CMD_VERSION            MSG_VERSION, TOK_VERSION
+
+#define MSG_QUIT                "QUIT"          /* QUIT */
+#define TOK_QUIT                "Q"
+#define CMD_QUIT               MSG_QUIT, TOK_QUIT
+
+#define MSG_SQUIT               "SQUIT"         /* SQUI */
+#define TOK_SQUIT               "SQ"
+#define CMD_SQUIT              MSG_SQUIT, TOK_SQUIT
+
+#define MSG_KILL                "KILL"          /* KILL */
+#define TOK_KILL                "D"
+#define CMD_KILL               MSG_KILL, TOK_KILL
+
+#define MSG_INFO                "INFO"          /* INFO */
+#define TOK_INFO                "F"
+#define CMD_INFO               MSG_INFO, TOK_INFO
+
+#define MSG_LINKS               "LINKS"         /* LINK */
+#define TOK_LINKS               "LI"
+#define CMD_LINKS              MSG_LINKS, TOK_LINKS
+
+#define MSG_STATS               "STATS"         /* STAT */
+#define TOK_STATS               "R"
+#define CMD_STATS              MSG_STATS, TOK_STATS
+
+#define MSG_HELP                "HELP"          /* HELP */
+#define TOK_HELP                "HELP"
+#define CMD_HELP               MSG_HELP, TOK_HELP
+
+#define MSG_ERROR               "ERROR"         /* ERRO */
+#define TOK_ERROR               "Y"
+#define CMD_ERROR              MSG_ERROR, TOK_ERROR
+
+#define MSG_AWAY                "AWAY"          /* AWAY */
+#define TOK_AWAY                "A"
+#define CMD_AWAY               MSG_AWAY, TOK_AWAY
+
+#define MSG_CONNECT             "CONNECT"       /* CONN */
+#define TOK_CONNECT             "CO"
+#define CMD_CONNECT            MSG_CONNECT, TOK_CONNECT
+
+#define MSG_MAP                 "MAP"           /* MAP  */
+#define TOK_MAP                 "MAP"
+#define CMD_MAP                        MSG_MAP, TOK_MAP
+
+#define MSG_PING                "PING"          /* PING */
+#define TOK_PING                "G"
+#define CMD_PING               MSG_PING, TOK_PING
+
+#define MSG_PONG                "PONG"          /* PONG */
+#define TOK_PONG                "Z"
+#define CMD_PONG               MSG_PONG, TOK_PONG
+
+#define MSG_OPER                "OPER"          /* OPER */
+#define TOK_OPER                "OPER"
+#define CMD_OPER               MSG_OPER, TOK_OPER
+
+#define MSG_PASS                "PASS"          /* PASS */
+#define TOK_PASS                "PA"
+#define CMD_PASS               MSG_PASS, TOK_PASS
+
+#define MSG_WALLOPS             "WALLOPS"       /* WALL */
+#define TOK_WALLOPS             "WA"
+#define CMD_WALLOPS            MSG_WALLOPS, TOK_WALLOPS
+
+#define MSG_WALLUSERS           "WALLUSERS"     /* WALL */
+#define TOK_WALLUSERS           "WU"
+#define CMD_WALLUSERS          MSG_WALLUSERS, TOK_WALLUSERS
+
+#define MSG_DESYNCH             "DESYNCH"       /* DESY */
+#define TOK_DESYNCH             "DS"
+#define CMD_DESYNCH            MSG_DESYNCH, TOK_DESYNCH
+
+#define MSG_TIME                "TIME"          /* TIME */
+#define TOK_TIME                "TI"
+#define CMD_TIME               MSG_TIME, TOK_TIME
+
+#define MSG_SETTIME             "SETTIME"       /* SETT */
+#define TOK_SETTIME             "SE"
+#define CMD_SETTIME            MSG_SETTIME, TOK_SETTIME
+
+#define MSG_RPING               "RPING"         /* RPIN */
+#define TOK_RPING               "RI"
+#define CMD_RPING              MSG_RPING, TOK_RPING
+
+#define MSG_RPONG               "RPONG"         /* RPON */
+#define TOK_RPONG               "RO"
+#define CMD_RPONG              MSG_RPONG, TOK_RPONG
+
+#define MSG_NAMES               "NAMES"         /* NAME */
+#define TOK_NAMES               "E"
+#define CMD_NAMES              MSG_NAMES, TOK_NAMES
+
+#define MSG_ADMIN               "ADMIN"         /* ADMI */
+#define TOK_ADMIN               "AD"
+#define CMD_ADMIN              MSG_ADMIN, TOK_ADMIN
+
+#define MSG_TRACE               "TRACE"         /* TRAC */
+#define TOK_TRACE               "TR"
+#define CMD_TRACE              MSG_TRACE, TOK_TRACE
+
+#define MSG_NOTICE              "NOTICE"        /* NOTI */
+#define TOK_NOTICE              "O"
+#define CMD_NOTICE             MSG_NOTICE, TOK_NOTICE
+
+#define MSG_WALLCHOPS           "WALLCHOPS"     /* WC */
+#define TOK_WALLCHOPS           "WC"
+#define CMD_WALLCHOPS          MSG_WALLCHOPS, TOK_WALLCHOPS
+
+#define MSG_WALLVOICES           "WALLVOICES"     /* WV */
+#define TOK_WALLVOICES           "WV"
+#define CMD_WALLVOICES         MSG_WALLVOICES, TOK_WALLVOICES
+
+#define MSG_CPRIVMSG            "CPRIVMSG"      /* CPRI */
+#define TOK_CPRIVMSG            "CP"
+#define CMD_CPRIVMSG           MSG_CPRIVMSG, TOK_CPRIVMSG
+
+#define MSG_CNOTICE             "CNOTICE"       /* CNOT */
+#define TOK_CNOTICE             "CN"
+#define CMD_CNOTICE            MSG_CNOTICE, TOK_CNOTICE
+
+#define MSG_JOIN                "JOIN"          /* JOIN */
+#define TOK_JOIN                "J"
+#define CMD_JOIN               MSG_JOIN, TOK_JOIN
+
+#define MSG_PART                "PART"          /* PART */
+#define TOK_PART                "L"
+#define CMD_PART               MSG_PART, TOK_PART
+
+#define MSG_LUSERS              "LUSERS"        /* LUSE */
+#define TOK_LUSERS              "LU"
+#define CMD_LUSERS             MSG_LUSERS, TOK_LUSERS
+
+#define MSG_MOTD                "MOTD"          /* MOTD */
+#define TOK_MOTD                "MO"
+#define CMD_MOTD               MSG_MOTD, TOK_MOTD
+
+#define MSG_MODE                "MODE"          /* MODE */
+#define TOK_MODE                "M"
+#define CMD_MODE               MSG_MODE, TOK_MODE
+
+#define MSG_KICK                "KICK"          /* KICK */
+#define TOK_KICK                "K"
+#define CMD_KICK               MSG_KICK, TOK_KICK
+
+#define MSG_USERHOST            "USERHOST"      /* USER -> USRH */
+#define TOK_USERHOST            "USERHOST"
+#define CMD_USERHOST           MSG_USERHOST, TOK_USERHOST
+
+#define MSG_USERIP              "USERIP"        /* USER -> USIP */
+#define TOK_USERIP              "USERIP"
+#define CMD_USERIP             MSG_USERIP, TOK_USERIP
+
+#define MSG_ISON                "ISON"          /* ISON */
+#define TOK_ISON                "ISON"
+#define CMD_ISON               MSG_ISON, TOK_ISON
+
+#define MSG_SQUERY              "SQUERY"        /* SQUE */
+#define TOK_SQUERY              "SQUERY"
+#define CMD_SQUERY             MSG_SQUERY, TOK_SQUERY
+
+#define MSG_SERVLIST            "SERVLIST"      /* SERV -> SLIS */
+#define TOK_SERVLIST            "SERVSET"
+#define CMD_SERVLIST           MSG_SERVLIST, TOK_SERVLIST
+
+#define MSG_SERVSET             "SERVSET"       /* SERV -> SSET */
+#define TOK_SERVSET             "SERVSET"
+#define CMD_SERVSET            MSG_SERVSET, TOK_SERVSET
+
+#define MSG_REHASH              "REHASH"        /* REHA */
+#define TOK_REHASH              "RE"
+#define CMD_REHASH             MSG_REHASH, TOK_REHASH
+
+#define MSG_RESTART             "RESTART"       /* REST */
+#define TOK_RESTART             "RESTART"
+#define CMD_RESTART            MSG_RESTART, TOK_RESTART
+
+#define MSG_CLOSE               "CLOSE"         /* CLOS */
+#define TOK_CLOSE               "CLOSE"
+#define CMD_CLOSE              MSG_CLOSE, TOK_CLOSE
+
+#define MSG_DIE                 "DIE"           /* DIE  */
+#define TOK_DIE                 "DIE"
+#define CMD_DIE                        MSG_DIE, TOK_DIE
+
+#define MSG_HASH                "HASH"          /* HASH */
+#define TOK_HASH                "HASH"
+#define CMD_HASH               MSG_HASH, TOK_HASH
+
+#define MSG_DNS                 "DNS"           /* DNS  -> DNSS */
+#define TOK_DNS                 "DNS"
+#define CMD_DNS                        MSG_DNS, TOK_DNS
+
+#define MSG_SILENCE             "SILENCE"       /* SILE */
+#define TOK_SILENCE             "U"
+#define CMD_SILENCE            MSG_SILENCE, TOK_SILENCE
+
+#define MSG_GLINE               "GLINE"         /* GLIN */
+#define TOK_GLINE               "GL"
+#define CMD_GLINE              MSG_GLINE, TOK_GLINE
+
+#define MSG_BURST               "BURST"         /* BURS */
+#define TOK_BURST               "B"
+#define CMD_BURST              MSG_BURST, TOK_BURST
+
+#define MSG_UPING               "UPING"         /* UPIN */
+#define TOK_UPING               "UP"
+#define CMD_UPING              MSG_UPING, TOK_UPING
+
+#define MSG_CREATE              "CREATE"        /* CREA */
+#define TOK_CREATE              "C"
+#define CMD_CREATE             MSG_CREATE, TOK_CREATE
+
+#define MSG_DESTRUCT            "DESTRUCT"      /* DEST */
+#define TOK_DESTRUCT            "DE"
+#define CMD_DESTRUCT           MSG_DESTRUCT, TOK_DESTRUCT
+
+#define MSG_END_OF_BURST        "END_OF_BURST"  /* END_ */
+#define TOK_END_OF_BURST        "EB"
+#define CMD_END_OF_BURST       MSG_END_OF_BURST, TOK_END_OF_BURST
+
+#define MSG_END_OF_BURST_ACK    "EOB_ACK"       /* EOB_ */
+#define TOK_END_OF_BURST_ACK    "EA"
+#define CMD_END_OF_BURST_ACK   MSG_END_OF_BURST_ACK, TOK_END_OF_BURST_ACK
+
+#define MSG_PROTO               "PROTO"         /* PROTO */
+#define TOK_PROTO               "PROTO"         /* PROTO */
+#define CMD_PROTO              MSG_PROTO, TOK_PROTO
+
+#define MSG_JUPE                "JUPE"          /* JUPE */
+#define TOK_JUPE                "JU"
+#define CMD_JUPE               MSG_JUPE, TOK_JUPE
+
+#define MSG_OPMODE              "OPMODE"        /* OPMO */
+#define TOK_OPMODE              "OM"
+#define CMD_OPMODE             MSG_OPMODE, TOK_OPMODE
+
+#define MSG_CLEARMODE           "CLEARMODE"     /* CLMO */
+#define TOK_CLEARMODE           "CM"
+#define CMD_CLEARMODE          MSG_CLEARMODE, TOK_CLEARMODE
+
+#define MSG_ACCOUNT            "ACCOUNT"       /* ACCO */
+#define TOK_ACCOUNT            "AC"
+#define CMD_ACCOUNT            MSG_ACCOUNT, TOK_ACCOUNT
+
+#define MSG_ASLL               "ASLL"          /* ASLL */
+#define TOK_ASLL               "LL"
+#define CMD_ASLL               MSG_ASLL, TOK_ASLL
+
+#define MSG_POST                "POST"          /* POST */
+#define TOK_POST                "POST"
+
+#define MSG_SET                        "SET"           /* SET */
+#define TOK_SET                        "SET"
+
+#define MSG_RESET              "RESET"         /* RESE */
+#define TOK_RESET              "RESET"
+
+#define MSG_GET                        "GET"           /* GET */
+#define TOK_GET                        "GET"
+
+#define MSG_PRIVS              "PRIVS"         /* PRIV */
+#define TOK_PRIVS              "PR"
+#define CMD_PRIVS               MSG_PRIVS, TOK_PRIVS
+
+#define MSG_CAP                        "CAP"
+#define TOK_CAP                        "CAP"
+#define CMD_CAP                        MSG_CAP, TOK_CAP
+
+#define MSG_FAKEHOST        "FAKEHOST"
+#define TOK_FAKEHOST        "FH"
+#define CMD_FAKEHOST        MSG_FAKEHOST, TOK_FAKEHOST
+
+#define MSG_FAKEHOST_OLD    "FAKE"
+#define TOK_FAKEHOST_OLD    "FA"
+#define CMD_FAKEHOST_OLD    MSG_FAKEHOST_OLD, TOK_FAKEHOST_OLD
+
+#define MSG_HIDEHOST        "HIDEHOST"
+#define TOK_HIDEHOST        "HH"
+#define CMD_HIDEHOST        MSG_HIDEHOST, TOK_HIDEHOST
+
+#define MSG_SVSMODE        "SVSMODE"
+#define TOK_SVSMODE        "SM"
+#define CMD_SVSMODE        MSG_SVSMODE, TOK_SVSMODE
+
+#define MSG_SVSNICK        "SVSNICK2"
+#define TOK_SVSNICK        "SN"
+#define CMD_SVSNICK        MSG_SVSNICK, TOK_SVSNICK
+
+#define MSG_SVSNICK_OLD    "SVSNICK"
+#define TOK_SVSNICK_OLD    "SVN"
+#define CMD_SVSNICK_OLD    MSG_SVSNICK_OLD, TOK_SVSNICK_OLD
+
+#define MSG_SVSJOIN        "SVSJOIN"
+#define TOK_SVSJOIN        "SJ"
+#define CMD_SVSJOIN        MSG_SVSJOIN, TOK_SVSJOIN
+
+#define MSG_WEBIRC          "WEBIRC"
+#define TOK_WEBIRC          "WEBIRC"
+#define CMD_WEBIRC          MSG_WEBIRC, TOK_WEBIRC
+
+#define MSG_RELAY           "RELAY"
+#define TOK_RELAY           "RL"
+#define CMD_RELAY           MSG_RELAY, TOK_RELAY
+
+#define MSG_CHECK           "CHECK"
+#define TOK_CHECK           "CHECK"
+
+/*
+ * Constants
+ */
+#define   MFLG_SLOW              0x01   /** Limit command usage to
+                                         * once per 2 seconds (for
+                                         * local users). */
+#define   MFLG_UNREG             0x02   /** Command available to
+                                         * unregistered clients. */
+#define   MFLG_IGNORE            0x04   /** Silently ignore command from
+                                         * unregistered clients. */
+#define   MFLG_EXTRA             0x08   /** Handler requests that
+                                         * mptr->extra be passed in
+                                         * parv[1]. */
+
+/*
+ * Structures
+ */
+
+/** Information on how to parse a message. */
+struct Message {
+  char *cmd;                  /**< command string */
+  char *tok;                  /**< token (shorter command string) */
+  unsigned int count;         /**< number of times message used */
+  unsigned int parameters;    /**< minimum number of parameters */
+  unsigned int flags;         /**< MFLG_* flags for command */
+  unsigned int bytes;         /**< bytes received for this message */
+  void *extra;                /**< extra pointer to be passed in parv[1] */
+  /*
+   * cptr = Connected client ptr
+   * sptr = Source client ptr
+   * parc = parameter count
+   * parv = parameter variable array
+   */
+  /* handlers:
+   * UNREGISTERED, CLIENT, SERVER, OPER, SERVICE, LAST
+   */
+  MessageHandler handlers[LAST_HANDLER_TYPE];
+};
+
+extern struct Message msgtab[];
+
+#endif /* INCLUDED_msg_h */
diff --git a/include/msgq.h b/include/msgq.h
new file mode 100644 (file)
index 0000000..6028372
--- /dev/null
@@ -0,0 +1,90 @@
+#ifndef INCLUDED_msgq_h
+#define INCLUDED_msgq_h
+/*
+ * IRC - Internet Relay Chat, include/msgq.h
+ * Copyright (C) 2000 Kevin L. Mitchell <klmitch@mit.edu>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+/** @file
+ * @brief Outbound message queue interface and declarations.
+ * @version $Id: msgq.h 1231 2004-10-05 04:21:37Z entrope $
+ */
+#ifndef INCLUDED_ircd_defs_h
+#include "ircd_defs.h" /* BUFSIZE */
+#endif
+#ifndef INCLUDED_sys_types_h
+#include <sys/types.h>
+#define INCLUDED_sys_types_h
+#endif
+#ifndef INCLUDED_stdarg_h
+#include <stdarg.h>
+#define INCLUDED_stdarg_h
+#endif
+
+struct iovec;
+
+struct Client;
+struct StatDesc;
+
+struct Msg;
+struct MsgBuf;
+
+/** Queue of individual messages. */
+struct MsgQList {
+  struct Msg *head;            /**< First Msg in queue list */
+  struct Msg *tail;            /**< Last Msg in queue list */
+};
+
+/** Entire two-priority message queue for a destination. */
+struct MsgQ {
+  unsigned int length;         /**< Current number of bytes stored */
+  unsigned int count;          /**< Current number of messages stored */
+  struct MsgQList queue;       /**< Normal Msg queue */
+  struct MsgQList prio;                /**< Priority Msg queue */
+};
+
+/** Returns the current number of bytes stored in \a mq. */
+#define MsgQLength(mq) ((mq)->length)
+
+/** Returns the current number of messages stored in \a mq. */
+#define MsgQCount(mq) ((mq)->count)
+
+/** Scratch the current content of the buffer.
+ * Release all allocated buffers and make it empty.
+ */
+#define MsgQClear(mq) msgq_delete((mq), MsgQLength(mq))
+
+/*
+ * Prototypes
+ */
+extern void msgq_init(struct MsgQ *mq);
+extern void msgq_delete(struct MsgQ *mq, unsigned int length);
+extern int msgq_mapiov(const struct MsgQ *mq, struct iovec *iov, int count,
+                      unsigned int *len);
+extern struct MsgBuf *msgq_make(struct Client *dest, const char *format, ...);
+extern struct MsgBuf *msgq_vmake(struct Client *dest, const char *format,
+                                va_list args);
+extern void msgq_append(struct Client *dest, struct MsgBuf *mb,
+                       const char *format, ...);
+extern void msgq_clean(struct MsgBuf *mb);
+extern void msgq_add(struct MsgQ *mq, struct MsgBuf *mb, int prio);
+extern void msgq_count_memory(struct Client *cptr,
+                              size_t *msg_alloc, size_t *msg_used);
+extern void msgq_histogram(struct Client *cptr, const struct StatDesc *sd,
+                           char *param);
+extern unsigned int msgq_bufleft(struct MsgBuf *mb);
+
+#endif /* INCLUDED_msgq_h */
diff --git a/include/numeric.h b/include/numeric.h
new file mode 100644 (file)
index 0000000..49d2de4
--- /dev/null
@@ -0,0 +1,504 @@
+/*
+ * IRC - Internet Relay Chat, include/numeric.h
+ * Copyright (C) 1990 Jarkko Oikarinen
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+/** @file
+ * @brief Declarations of numeric replies and supporting functions.
+ * @version $Id: numeric.h 1905 2009-02-09 01:30:13Z entrope $
+ */
+#ifndef INCLUDED_numeric_h
+#define INCLUDED_numeric_h
+
+/** Numeric reply information. */
+typedef struct Numeric {
+  int         value;  /**< Numeric response. */
+  const char* format; /**< Format string to follow :My.Server NNN Dest */
+  const char* str;    /**< Text form for numeric. */
+} Numeric;
+
+/*
+ * Prototypes
+ */
+extern char* rpl_str(int numeric);
+extern const struct Numeric* get_error_numeric(int err);
+
+/*
+ * References:
+ *  aircd - aircd source.  Doesn't appear to be available on the web.
+ *         anywhere.  Ask me (Isomer) if you'd like a copy. (it's gpl)
+ *  Numeric List - http://www.contactor.se/~dast/irc/numerics.txt
+ */
+
+
+/*
+ * Reserve numerics 000-099 for server-client connections where the client
+ * is local to the server. If any server is passed a numeric in this range
+ * from another server then it is remapped to 100-199. -avalon
+ */
+#define RPL_WELCOME            1
+#define RPL_YOURHOST           2
+#define RPL_CREATED            3
+#define RPL_MYINFO             4
+#define RPL_ISUPPORT           5        /* Undernet/Dalnet extension */
+/*     RPL_MAP                6        unreal */
+/*     RPL_MAPEND             7        unreal */
+#define RPL_SNOMASK            8        /* Undernet extension */
+/*       RPL_BOUNCE           10        efnet, IRCnet extension
+                                        (server redirect) */
+/*      RPL_YOURCOOKIE        14           IRCnet extension */
+#define RPL_MAP               15        /* Undernet extension */
+#define RPL_MAPMORE           16        /* Undernet extension */
+#define RPL_MAPEND            17        /* Undernet extension */
+#define RPL_APASSWARN_SET     30       /* Undernet extension */
+#define RPL_APASSWARN_SECRET  31       /* Undernet extension */
+#define RPL_APASSWARN_CLEAR   32       /* Undernet extension */
+/*     RPL_YOURID            42        IRCnet extension */
+/*      RPL_ATTEMPTINGJUNC    50           aircd extension */
+/*      RPL_ATTEMPTINGREROUTE 51           aircd extension */
+
+/*
+ * Numberic replies from server commands.
+ * These are currently in the range 200-399.
+ */
+
+#define RPL_TRACELINK        200
+#define RPL_TRACECONNECTING  201
+#define RPL_TRACEHANDSHAKE   202
+#define RPL_TRACEUNKNOWN     203
+#define RPL_TRACEOPERATOR    204
+#define RPL_TRACEUSER        205
+#define RPL_TRACESERVER      206
+#define RPL_TRACENEWTYPE     208
+#define RPL_TRACECLASS       209
+/*      RPL_STATS            210 aircd extension, used instead of having
+                                 multiple stats numerics */
+/*      RPL_TRACERECONNECT   210 IRCnet extension */
+#define RPL_STATSLINKINFO    211
+#define RPL_STATSCOMMANDS    212
+#define RPL_STATSCLINE       213
+/*     RPL_STATSOLDNLINE    214    unreal */
+#define RPL_STATSNLINE       214 /* unused */
+#define RPL_STATSILINE       215
+#define RPL_STATSKLINE       216
+#define RPL_STATSPLINE       217        /* Undernet extension */
+/*      RPL_STATSQLINE       217           Various */
+#define RPL_STATSYLINE       218
+#define RPL_ENDOFSTATS       219        /* See also RPL_STATSDLINE */
+/*      RPL_STATSPLINE       220           Hybrid - Because 217 was for
+                                           old Q: lines. */
+/*      RPL_STATSBLINE       220          Numerics List: Dalnet,unreal */
+#define RPL_UMODEIS          221
+/*     RPL_SQLINE_NICK      222           Numerics List: Dalnet */
+#define RPL_STATSJLINE       222       /* Undernet extension */
+/*     RPL_STATSELINE       223           dalnet */
+/*     RPL_STATSGLINE       223           unreal */
+/*      RPL_STATSFLINE       224           Hybrid extension,Dalnet */
+/*     RPL_STATSTLINE       224           unreal */
+/*      RPL_STATSDLINE       225           Hybrid extension */
+/*     RPL_STATSZLINE       225           Dalnet
+       RPL_STATSELINE       225           unreal
+       RPL_STATSCOUNT       226           Dalnet
+       RPL_STATSNLINE       226           unreal
+       RPL_STATSGLINE       227           Dalnet 
+       RPL_STATSVLINE       227           unreal */
+#define RPL_STATSALINE       226        /* Hybrid, Undernet */
+#define RPL_STATSQLINE       228        /* Undernet extension */
+
+/*      RPL_SERVICEINFO      231       unused */
+/*      RPL_ENDOFSERVICES    232       unused */
+/*     RPL_RULES            232        unreal */
+/*      RPL_SERVICE          233       unused */
+/*      RPL_SERVLIST         234       unused */
+/*      RPL_SERVLISTEND      235       unused */
+
+#define RPL_STATSVERBOSE     236        /* Undernet verbose server list */
+#define RPL_STATSENGINE      237       /* Undernet engine name */
+#define RPL_STATSFLINE       238       /* Undernet feature lines */
+/*      RPL_STATSIAUTH       239           IRCnet extension */
+/*      RPL_STATSVLINE       240           IRCnet extension */
+/*     RPL_STATSXLINE       240        austnet */
+#define RPL_STATSLLINE       241       /* Undernet dynamicly loaded modules */
+#define RPL_STATSUPTIME      242
+#define RPL_STATSOLINE       243
+#define RPL_STATSHLINE       244
+/*      RPL_STATSSLINE       245           Reserved / Dalnet / IRCnet / EFnet */
+/*     RPL_STATSSPING       246           Numerics List: IRCnet */
+#define RPL_STATSTLINE       246        /* Undernet extension */
+/*     RPL_STATSULINE       246        Dalnet */
+#define RPL_STATSGLINE       247        /* Undernet extension */
+/*      RPL_STATSXLINE       247           hybrid extension,PTlink,unreal */
+/*     RPL_STATSBLINE       247           Numerics List: IRCnet */
+#define RPL_STATSULINE       248        /* Undernet extension */
+/*     RPL_STATSDEFINE      248           Numerics List: IRCnet */
+#define RPL_STATSDEBUG       249        /* Extension to RFC1459 */
+#define RPL_STATSCONN        250        /* Undernet extension */
+/*     RPL_STATSDLINE       250           Numerics List: IRCnet */
+
+#define RPL_LUSERCLIENT      251
+#define RPL_LUSEROP          252
+#define RPL_LUSERUNKNOWN     253
+#define RPL_LUSERCHANNELS    254
+#define RPL_LUSERME          255
+#define RPL_ADMINME          256
+#define RPL_ADMINLOC1        257
+#define RPL_ADMINLOC2        258
+#define RPL_ADMINEMAIL       259
+
+/*      RPL_TRACELOG         261          unused */
+#define RPL_TRACEEND        262        /* efnet/IRCnet */
+/*      RPL_LOAD_THROTTLED   263           efnet/hybrid */
+/*     RPL_TRYAGAIN         263           Numerics List: IRCnet */
+/*     RPL_LOAD2HI          263           Dalnet */
+/*      RPL_CURRENT_LOCAL    265           aircd/efnet/hybrid/dalnet*/
+/*      RPL_CURRENT_GLOBAL   266           aircd/efnet/hybrid/dalnet */
+/*      RPL_START_NETSTAT    267           aircd */
+/*      RPL_NETSTAT          268           aircd */
+/*      RPL_END_NETSTAT      269           aircd */
+#define RPL_PRIVS            270       /* Undernet extension - privs */
+#define RPL_SILELIST         271        /* Undernet extension */
+#define RPL_ENDOFSILELIST    272        /* Undernet extension */
+/*      RPL_NOTIFY           273           aircd */
+/*      RPL_END_NOTIFY       274           aircd */
+/*      RPL_STATSDELTA       274           IRCnet extension */
+#define RPL_STATSDLINE       275        /* Undernet extension */
+#define RPL_STATSRLINE       276        /* Undernet extension */
+
+#define RPL_GLIST            280        /* Undernet extension */
+#define RPL_ENDOFGLIST       281        /* Undernet extension */
+#define RPL_JUPELIST         282        /* Undernet extension - jupe -Kev */
+#define RPL_ENDOFJUPELIST    283        /* Undernet extension - jupe -Kev */
+#define RPL_FEATURE         284        /* Undernet extension - features */
+/*      RPL_CHANINFO_HANDLE  285           aircd */
+/*      RPL_CHANINFO_USERS   286           aircd */
+#define RPL_CHKHEAD          286        /* IRCu-Patchset extension */
+/*      RPL_CHANINFO_CHOPS   287           aircd */
+#define RPL_CHANUSER         287        /* IRCu-Patchset extension */
+/*      RPL_CHANINFO_VOICES  288           aircd */
+/*      RPL_CHANINFO_AWAY    289           aircd */
+/*      RPL_CHANINFO_OPERS   290           aircd */
+/*     RPL_HELPHDR          290        Numeric List: Dalnet */
+#define RPL_DATASTR          290        /* IRCu-Patchset extension */
+/*      RPL_CHANINFO_BANNED  291           aircd */
+/*     RPL_HELPOP           291        Numeric List: Dalnet */
+#define RPL_ENDOFCHECK       291        /* IRCu-Patchset extension */
+/*      RPL_CHANINFO_BANS    292           aircd */
+/*     RPL_HELPTLR          292        Numeric List: Dalnet */
+/*      RPL_CHANINFO_INVITE  293           aircd */
+/*     RPL_HELPHLP          293        Numeric List: Dalnet */
+/*      RPL_CHANINFO_INVITES 294           aircd */
+/*     RPL_HELPFWD          294        Numeric List: Dalnet */
+/*      RPL_CHANINFO_KICK    295           aircd */
+/*     RPL_HELPIGN          295        Numeric List: Dalnet */
+/*      RPL_CHANINFO_KICKS   296           aircd */
+
+/*      RPL_END_CHANINFO     299           aircd */
+
+/*      RPL_NONE             300       unused */
+#define RPL_AWAY             301
+#define RPL_USERHOST         302
+#define RPL_ISON             303
+/*      RPL_TEXT             304       unused */
+#define RPL_UNAWAY           305
+#define RPL_NOWAWAY          306
+                                        /* NotAway, aircd */
+/*     RPL_WHOISREGNICK     307        Numeric List: Dalnet */
+/*     RPL_SUSERHOST        307        austnet */
+/*      RPL_NOTIFYACTION     308         aircd */
+/*     RPL_WHOISADMIN       308        Numeric List: Dalnet */
+/*     RPL_RULESSTART       308        unreal */
+/*      RPL_NICKTRACE        309         aircd */
+/*     RPL_WHOISSADMIN      309        Numeric List: Dalnet */
+/*     RPL_ENDOFRULES       309        unreal */
+/*     RPL_WHOISHELPER      309        austnet */
+/*      RPL_WHOISSVCMSG      310         Dalnet */
+/*     RPL_WHOISHELPOP      310        unreal */
+/*     RPL_WHOISSERVICE     310        austnet */
+#define RPL_WHOISUSER        311        /* See also RPL_ENDOFWHOIS */
+#define RPL_WHOISSERVER      312
+#define RPL_WHOISOPERATOR    313
+#define RPL_WHOWASUSER       314        /* See also RPL_ENDOFWHOWAS */
+#define RPL_ENDOFWHO         315        /* See RPL_WHOREPLY/RPL_WHOSPCRPL */
+/*      RPL_WHOISCHANOP      316           removed from RFC1459 */
+#define RPL_WHOISIDLE        317
+#define RPL_ENDOFWHOIS       318        /* See RPL_WHOISUSER/RPL_WHOISSERVER/
+                                           RPL_WHOISOPERATOR/RPL_WHOISIDLE */
+#define RPL_WHOISCHANNELS    319
+/*      RPL_WHOIS_HIDDEN     320         Anothernet +h, ick! */
+/*     RPL_WHOISSPECIAL     320        unreal */
+#define RPL_WHOISSSL         320        /* ircu-patchset SSL extension */
+#define RPL_LISTSTART        321
+#define RPL_LIST             322
+#define RPL_LISTEND          323
+#define RPL_CHANNELMODEIS    324
+/*      RPL_CHANNELPASSIS    325           IRCnet extension */
+/*      RPL_UNIQOPIS         325           IRCnet extension */
+/*      RPL_NOCHANPASS       326           IRCnet extension */
+/*      RPL_CHPASSUNKNOWN    327           IRCnet extension */
+/*      RPL_CHANNEL_URL      328           dalnet, anothernet */
+#define RPL_CREATIONTIME     329
+/*      RPL_WHOWAS_TIME      330               ? */
+#define RPL_WHOISACCOUNT     330
+#define RPL_NOTOPIC          331
+#define RPL_TOPIC            332
+#define RPL_TOPICWHOTIME     333        /* Undernet extension */
+#define RPL_LISTUSAGE        334        /* Undernet extension */
+/*     RPL_COMMANDSYNTAX    334           Dalnet */
+/*     RPL_LISTSYNTAX       334           unreal */
+/*      RPL_CHANPASSOK       338           IRCnet extension (?)*/
+#define        RPL_WHOISACTUALLY    338        /* Undernet extension, dalnet */
+/*     RPL_BADCHANPASS      339           IRCnet extension (?) */
+#define RPL_USERIP           340        /* Undernet extension */
+#define RPL_INVITING         341
+/*      RPL_SUMMONING        342           removed from RFC1459 */
+
+#define RPL_ISSUEDINVITE     345        /* Undernet extension */
+#define RPL_INVITELIST       346        /* IRCnet, Undernet extension */
+#define RPL_ENDOFINVITELIST  347        /* IRCnet, Undernet extension */
+#define RPL_EXCEPTIONLIST    348        /* IRCu-Patchset Extension */
+#define RPL_ENDOFEXCEPTIONLIST 349      /* IRCu-Patchset Extension */
+/*      RPL_EXCEPTLIST       348           IRCnet extension */
+/*      RPL_ENDOFEXCEPTLIST  349           IRCnet extension */
+
+#define RPL_VERSION          351
+#define RPL_WHOREPLY         352        /* See also RPL_ENDOFWHO */
+#define RPL_NAMREPLY         353        /* See also RPL_ENDOFNAMES */
+#define RPL_WHOSPCRPL        354        /* Undernet extension,
+                                           See also RPL_ENDOFWHO */
+#define RPL_DELNAMREPLY      355        /* QuakeNet extension */
+
+/*      RPL_KILLDONE         361       not used */
+#define RPL_CLOSING          362
+#define RPL_CLOSEEND         363
+#define RPL_LINKS            364
+#define RPL_ENDOFLINKS       365
+#define RPL_ENDOFNAMES       366        /* See RPL_NAMREPLY */
+#define RPL_BANLIST          367
+#define RPL_ENDOFBANLIST     368
+#define RPL_ENDOFWHOWAS      369
+
+#define RPL_INFO             371
+#define RPL_MOTD             372
+/*      RPL_INFOSTART        373       not used */
+#define RPL_ENDOFINFO        374
+#define RPL_MOTDSTART        375
+#define RPL_ENDOFMOTD        376
+
+#define RPL_WHOISWEBIRC      377    /* IRCu Patchset extension: WebIRC user. */
+/*      RPL_KICKEXPIRED      377   aircd */
+/*     RPL_SPAM             377   austnet */
+#define RPL_WHOISWEBIRCLONG  378    /* IRCu Patchset extension: WebIRC user + orig. ip. */
+/*      RPL_BANEXPIRED       378   aircd */
+/*      RPL_KICKLINKED       379   aircd */
+/*      RPL_BANLINKED        380   aircd */
+
+#define RPL_YOUREOPER        381
+#define RPL_REHASHING        382
+/*     RPL_YOURSERVICE      383           Numeric List: various */
+/*      RPL_MYPORTIS         384       not used */
+/*      RPL_NOTOPERANYMORE   385        Extension to RFC1459, not used */
+/*     RPL_QLIST            386        unreal */
+/*     RPL_ENDOFQLIST       387        unreal */
+/*     RPL_ALIST            388        unreal */
+/*     RPL_ENDOFALIST       389        unreal */
+
+#define RPL_TIME             391
+/*      RPL_START_USERS      392        Dalnet/EFnet/IRCnet */
+/*      RPL_USERS            393        Dalnet/EFnet/IRCnet */
+/*      RPL_END_USERS        394        Dalnet/EFnet/IRCnet */
+/*      RPL_NOUSERS          395        Dalnet/EFnet/IRCnet */
+#define RPL_HOSTHIDDEN       396       /* UMODE +x completed succesfuly */
+
+/*
+ * Errors are in the range from 400-599 currently and are grouped by what
+ * commands they come from.
+ */
+/*      ERR_FIRSTERROR       400       unused */
+#define ERR_NOSUCHNICK       401
+#define ERR_NOSUCHSERVER     402
+#define ERR_NOSUCHCHANNEL    403
+#define ERR_CANNOTSENDTOCHAN 404
+#define ERR_TOOMANYCHANNELS  405
+#define ERR_WASNOSUCHNICK    406
+#define ERR_TOOMANYTARGETS   407
+#define ERR_SEARCHNOMATCH    408      /* IRCu-Patchset extension */
+/*      ERR_NOSUCHSERVICE    408  IRCnet */
+/*     ERR_NOCOLORSONCHAN   408  Dalnet */
+#define ERR_NOORIGIN         409
+#define ERR_UNKNOWNCAPCMD    410
+#define ERR_NORECIPIENT      411
+#define ERR_NOTEXTTOSEND     412
+#define ERR_NOTOPLEVEL       413
+#define ERR_WILDTOPLEVEL     414
+     /* ERR_BADMASK          415           IRCnet extension */
+#define ERR_QUERYTOOLONG     416        /* Undernet extension */
+     /* ERR_TOOMANYMATCHES   416           IRCnet extension */
+#define ERR_INPUTTOOLONG     417
+/*      ERR_LENGTHTRUNCATED  419           aircd */
+
+#define ERR_UNKNOWNCOMMAND   421
+#define ERR_NOMOTD           422
+#define ERR_NOADMININFO      423
+/*      ERR_FILEERROR        424           removed from RFC1459 */
+
+/*     ERR_TOOMANYAWAY      429            Dalnet */
+#define ERR_NONICKNAMEGIVEN  431
+#define ERR_ERRONEUSNICKNAME 432
+#define ERR_NICKNAMEINUSE    433
+/*      ERR_SERVICENAMEINUSE 434 ? */
+/*     ERR_NORULES          434   unreal */
+/*      ERR_SERVICECONFUSED  435 ? */
+/*     ERR_BANONCHAN        435   dalnet */
+#define ERR_NICKCOLLISION    436
+#define ERR_BANNICKCHANGE    437        /* Undernet extension */
+     /* ERR_UNAVAILRESOURCE  437           IRCnet extension */
+#define ERR_NICKTOOFAST      438        /* Undernet extension */
+     /* ERR_DEAD             438           IRCnet reserved for later use */
+#define ERR_TARGETTOOFAST    439        /* Undernet extension */
+#define ERR_SERVICESDOWN     440       /* Dalnet,unreal,Undernet */
+#define ERR_USERNOTINCHANNEL 441
+#define ERR_NOTONCHANNEL     442
+#define ERR_USERONCHANNEL    443
+/*      ERR_NOLOGIN          444           removed from RFC1459 */
+/*      ERR_SUMMONDISABLED   445           removed from RFC1459 */
+/*      ERR_USERSDISABLED    446           removed from RFC1459 */
+/*     ERR_NONICKCHANGE     447         unreal */
+
+#define ERR_NOTREGISTERED    451
+/*      ERR_IDCOLLISION      452           IRCnet extension ? */
+/*      ERR_NICKLOST         453           IRCnet extension ? */
+
+/*     ERR_HOSTILENAME      455           unreal */
+
+/*     ERR_NOHIDING         459           unreal */
+/*     ERR_NOTFORHALFOPS    460           unreal */
+
+#define ERR_NEEDMOREPARAMS   461
+#define ERR_ALREADYREGISTRED 462
+#define ERR_NOPERMFORHOST    463
+#define ERR_PASSWDMISMATCH   464
+#define ERR_YOUREBANNEDCREEP 465
+#define ERR_YOUWILLBEBANNED  466
+#define ERR_KEYSET           467        /* Undernet extension */
+#define ERR_INVALIDUSERNAME  468        /* Undernet extension */
+/*     ERR_ONLYSERVERSCANCHANGE 468       Dalnet,unreal */
+/*     ERR_LINKSET          469        unreal */
+/*     ERR_LINKCHANNEL      470        unreal */
+#define ERR_JOINACCESS       470
+#define ERR_CHANNELISFULL    471
+#define ERR_UNKNOWNMODE      472
+#define ERR_INVITEONLYCHAN   473
+#define ERR_BANNEDFROMCHAN   474
+#define ERR_BADCHANNELKEY    475
+#define ERR_BADCHANMASK      476        /* Undernet extension */
+#define ERR_NEEDREGGEDNICK   477        /* DalNet&Undernet Extention */
+#define ERR_BANLISTFULL      478        /* Undernet extension */
+/*     ERR_LINKFAIL         479        unreal */
+
+#define ERR_BADCHANNAME      479        /* EFNet extension */
+                                        /* 479 Undernet extension badchan */
+/*     ERR_CANNOTKNOCK      480        unreal */
+/*     ERR_NOULINE          480        austnet */
+#define ERR_NOPRIVILEGES     481
+#define ERR_CHANOPRIVSNEEDED 482
+#define ERR_CANTKILLSERVER   483
+#define ERR_ISCHANSERVICE    484        /* Undernet extension */
+/*     ERR_DESYNC           484         Dalnet,PTlink */
+/*     ERR_ATTACKDENY       484         unreal */
+/*     ERR_RESTRICTED       484           IRCnet extension */
+/*      ERR_UNIQOPRIVSNEEDED 485           IRCnet extension */
+/*     ERR_KILLDENY         485           unreal */
+/*     ERR_CANTKICKADMIN    485           PTlink */
+/*     ERR_HTMDISABLED      486           unreal */
+/*      ERR_CHANTOORECENT    487           IRCnet extension (?) */
+/*      ERR_TSLESSCHAN       488           IRCnet extension (?) */
+#define ERR_VOICENEEDED      489        /* Undernet extension */
+
+#define ERR_NOOPERHOST       491
+/*      ERR_NOSERVICEHOST    492          IRCnet extension */
+
+#define ERR_NOFEATURE       493        /* Undernet extension - features */
+#define ERR_BADFEATVALUE     494       /* Undernet extension - features */
+#define ERR_BADLOGTYPE      495        /* Undernet extension - features */
+#define ERR_BADLOGSYS       496        /* Undernet extension - features */
+#define ERR_BADLOGVALUE             497        /* Undernet extension - features */
+
+#define ERR_ISOPERLCHAN      498        /* Undernet extension */
+
+#define ERR_UMODEUNKNOWNFLAG 501
+#define ERR_USERSDONTMATCH   502
+/*      ERR_GHOSTEDCLIENT    503           efnet */
+/*     ERR_VWORLDWARN       503           austnet */
+
+#define ERR_SILELISTFULL     511        /* Undernet extension */
+/*      ERR_NOTIFYFULL       512           aircd */
+/*     ERR_TOOMANYWATCH     512           Numeric List: Dalnet */
+#define ERR_NOSUCHGLINE      512        /* Undernet extension */
+#define ERR_BADPING          513        /* Undernet extension */
+/*      ERR_NEEDPONG        512           Numeric List: Dalnet */
+#define ERR_NOSUCHJUPE       514        /* Undernet extension - jupe -Kev */
+/*     ERR_TOOMANYDCC       514        dalnet */
+#define ERR_BADEXPIRE        515        /* Undernet extension - jupe -Kev */
+#define ERR_DONTCHEAT       516        /* Undernet extension */
+#define ERR_DISABLED        517        /* Undernet extension -Kev */
+/*     ERR_NOINVITE         518        unreal */
+#define ERR_LONGMASK        518        /* Undernet extension -Kev */
+/*     ERR_ADMONLY          519        unreal */
+#define ERR_TOOMANYUSERS     519       /* Undernet extension -Kev */
+/*     ERR_OPERONLY         520        unreal */
+#define ERR_MASKTOOWIDE             520        /* Undernet extension -Kev */
+/*      ERR_WHOTRUNC         520        austnet */
+#define ERR_CHANGEDEXPIRE    521       /* IRCu-Patchset extension -gix */
+/*      ERR_LISTSYNTAX       521        dalnet
+       ERR_LISTSYNTAX       521        dalnet
+       ERR_WHOSYNTAX        522        dalnet
+       ERR_WHOLIMEXCEED     523        dalnet */
+#define ERR_QUARANTINED      524       /* Undernet extension -Vampire */
+#define ERR_INVALIDKEY       525        /* Undernet extension */
+
+#define ERR_NOTLOWEROPLEVEL  560       /* Undernet extension */
+#define ERR_NOTMANAGER       561       /* Undernet extension */
+#define ERR_CHANSECURED      562       /* Undernet extension */
+#define ERR_UPASSSET         563       /* Undernet extension */
+#define ERR_UPASSNOTSET      564       /* Undernet extension */
+/*      ERR_NOMANAGER_LONG   565       no longer used */
+#define ERR_NOMANAGER        566       /* Undernet extension */
+#define ERR_UPASS_SAME_APASS 567        /* Undernet extension */
+#define ERR_LASTERROR        568
+
+/*     RPL_LOGON            600        dalnet,unreal
+       RPL_LOGOFF           601        dalnet,unreal
+       RPL_WATCHOFF         602        dalnet,unreal
+       RPL_WATCHSTAT        603        dalnet,unreal
+       RPL_NOWON            604        dalnet,unreal
+       RPL_NOWOFF           605        dalnet,unreal
+       RPL_WATCHLIST        606        dalnet,unreal
+       RPL_ENDOFWATCHLIST   607        dalnet,unreal
+
+       RPL_MAPMORE          610        unreal
+
+       RPL_MAPMORE          615        PTlink
+
+       RPL_DCCSTATUS        617        dalnet
+       RPL_DCCLIST          618        dalnet
+       RPL_ENDOFDCCLIST     619        dalnet
+       RPL_DCCINFO          620        dalnet
+
+       RPL_DUMPING          640        unreal
+       RPL_DUMPRPL          641        unreal
+       RPL_EODUMP           642        unreal
+*/
+#endif /* INCLUDED_numeric_h */
diff --git a/include/numnicks.h b/include/numnicks.h
new file mode 100644 (file)
index 0000000..a54cd35
--- /dev/null
@@ -0,0 +1,91 @@
+/*
+ * IRC - Internet Relay Chat, include/h.h
+ * Copyright (C) 1996 - 1997 Carlo Wood
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+/** @file
+ * @brief Interface for numeric nickname functions.
+ * @version $Id: numnicks.h 1274 2004-12-16 03:28:52Z entrope $
+ */
+#ifndef INCLUDED_numnicks_h
+#define INCLUDED_numnicks_h
+#ifndef INCLUDED_client_h
+#include "client.h"
+#endif
+#ifndef INCLUDED_sys_types_h
+#include <sys/types.h>
+#define INCLUDED_sys_types_h
+#endif
+
+/*
+ * General defines
+ */
+
+/*
+ * used for buffer size calculations in channel.c
+ */
+/** Maximum length of a full user numnick. */
+#define NUMNICKLEN 5            /* strlen("YYXXX") */
+
+/*
+ * Macros
+ */
+
+/** Provide format string arguments for a user's numnick.
+ * Use this macro as follows: sprintf(buf, "%s%s ...", NumNick(cptr), ...);
+ */
+#define NumNick(c) cli_yxx((cli_user(c))->server), cli_yxx(c)
+
+/** Provide format string arguments for a server's numnick.
+ * Use this macro as follows: sprintf(buf, "%s ...", NumServ(cptr), ...);
+ */
+#define NumServ(c) cli_yxx(c)
+
+/** Provide format string arguments for a server's capacity mask.
+ * Use this macro as follows: sprintf(buf, "%s%s ...", NumServCap(cptr), ...);
+ */
+#define NumServCap(c) cli_yxx(c), (cli_serv(c))->nn_capacity
+
+/*
+ * Structures
+ */
+struct Client;
+
+/*
+ * Proto types
+ */
+extern void SetRemoteNumNick(struct Client* cptr, const char* yxx);
+extern int  SetLocalNumNick(struct Client* cptr);
+extern void RemoveYXXClient(struct Client* server, const char* yxx);
+extern void SetServerYXX(struct Client* cptr, 
+                         struct Client* server, const char* yxx);
+extern void ClearServerYXX(const struct Client* server);
+
+extern void SetYXXCapacity(struct Client* myself, unsigned int max_clients);
+extern void SetYXXServerName(struct Client* myself, unsigned int numeric);
+
+extern int            markMatchexServer(const char* cmask, int minlen);
+extern struct Client* find_match_server(char* mask);
+extern struct Client* findNUser(const char* yxx);
+extern struct Client* FindNServer(const char* numeric);
+
+extern unsigned int   base64toint(const char* str);
+extern const char*    inttobase64(char* buf, unsigned int v, unsigned int count);
+extern const char* iptobase64(char* buf, const struct irc_in_addr* addr, unsigned int count, int v6_ok);
+extern void base64toip(const char* s, struct irc_in_addr* addr);
+
+#endif /* INCLUDED_numnicks_h */
+
diff --git a/include/opercmds.h b/include/opercmds.h
new file mode 100644 (file)
index 0000000..3b7b0cb
--- /dev/null
@@ -0,0 +1,28 @@
+/** @file opercmds.h
+ * @brief Declarations of AsLL ping helper commands.
+ * @version $Id: opercmds.h 1231 2004-10-05 04:21:37Z entrope $
+ */
+#ifndef INCLUDED_opercmds_h
+#define INCLUDED_opercmds_h
+#ifndef INCLUDED_sys_types_h
+#include <sys/types.h>
+#define INCLUDED_sys_types_h
+#endif
+
+struct Client;
+
+/*
+ * General defines
+ */
+
+/*-----------------------------------------------------------------------------
+ * Macro's
+ */
+/*
+ * Proto types
+ */
+
+extern char *militime(char* sec, char* usec);
+extern char *militime_float(char *start);
+
+#endif /* INCLUDED_opercmds_h */
diff --git a/include/packet.h b/include/packet.h
new file mode 100644 (file)
index 0000000..8599e9a
--- /dev/null
@@ -0,0 +1,22 @@
+/** @file packet.h
+ * @brief Declarations for packet handling functions.
+ * @version $Id: packet.h 1231 2004-10-05 04:21:37Z entrope $
+ */
+#ifndef INCLUDED_packet_h
+#define INCLUDED_packet_h
+#ifndef INCLUDED_sys_types_h
+#include <sys/types.h>
+#define INCLUDED_sys_types_h
+#endif
+
+struct Client;
+
+/*
+ * Prototypes
+ */
+
+extern int server_dopacket(struct Client* cptr, const char* buffer, int length);
+extern int connect_dopacket(struct Client* cptr, const char* buffer, int length);
+extern int client_dopacket(struct Client* cptr, unsigned int length);
+
+#endif /* INCLUDED_packet_h */
diff --git a/include/parse.h b/include/parse.h
new file mode 100644 (file)
index 0000000..0333826
--- /dev/null
@@ -0,0 +1,23 @@
+/** @file parse.h
+ * @brief Declarations for parsing input from users and other servers.
+ * @version $Id: parse.h 1231 2004-10-05 04:21:37Z entrope $
+ */
+#ifndef INCLUDED_parse_h
+#define INCLUDED_parse_h
+
+struct Client;
+struct s_map;
+
+/*
+ * Prototypes
+ */
+
+extern int parse_client(struct Client *cptr, char *buffer, char *bufend);
+extern int parse_simul_client(struct Client *cptr, char *buffer);
+extern int parse_server(struct Client *cptr, char *buffer, char *bufend);
+extern void initmsgtree(void);
+
+extern int register_mapping(struct s_map *map);
+extern int unregister_mapping(struct s_map *map);
+
+#endif /* INCLUDED_parse_h */
diff --git a/include/patchlevel.h b/include/patchlevel.h
new file mode 100644 (file)
index 0000000..b9d7de3
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * IRC - Internet Relay Chat, include/patchlevel.h
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id: patchlevel.h 1862 2008-01-09 18:32:43Z klmitch $
+ *
+ */
+#define PATCHSET "-BNCNet"
+
+#define PATCHLEVEL "pk-rc4"
+
+#define RELEASE ".12."
+
+/*
+ * Deliberate empty lines
+ */
+/* Do NOT edit those: */
+
+#ifndef BASE_VERSION
+#define BASE_VERSION "u2.10"
+#endif
+
+#ifndef MAJOR_PROTOCOL
+#define MAJOR_PROTOCOL "10"
+#endif
diff --git a/include/patchlist.h b/include/patchlist.h
new file mode 100644 (file)
index 0000000..bb41aa1
--- /dev/null
@@ -0,0 +1,2 @@
+/* This file was automatically generated by ircd-patch */
+#define PATCHLIST ""
diff --git a/include/querycmds.h b/include/querycmds.h
new file mode 100644 (file)
index 0000000..8076ee9
--- /dev/null
@@ -0,0 +1,99 @@
+/** @file
+ * @brief Interface and declarations for client counting functions.
+ * @version $Id: querycmds.h 1212 2004-10-03 17:02:23Z entrope $
+ */
+#ifndef INCLUDED_querycmds_h
+#define INCLUDED_querycmds_h
+
+#ifndef INCLUDED_ircd_features_h
+#include "ircd_features.h"     /* feature_str() */
+#endif
+
+struct Client;
+
+/*
+ * Structs
+ */
+
+/** Counts types of clients, servers, etc.\ on the network. */
+struct UserStatistics {
+  /* Local connections: */
+  unsigned int unknowns;  /**< Clients of types: unknown, connecting, handshake */
+  unsigned int local_servers;   /**< Directly connected servers. */
+  unsigned int local_clients;   /**< Directly connected clients. */
+
+  /* Global counts: */
+  unsigned int servers;         /**< Known servers, including #me. */
+  unsigned int clients;         /**< Registered users. */
+
+  /* Global user mode changes: */
+  unsigned int inv_clients;     /**< Registered invisible users. */
+  unsigned int opers;           /**< Registered IRC operators. */
+
+  /* Misc: */
+  unsigned int channels;        /**< Existing channels. */
+};
+
+extern struct UserStatistics UserStats;
+
+/*
+ * Macros
+ */
+
+/* Macros for remote connections: */
+/** Count \a cptr as a new remote client. */
+#define Count_newremoteclient(UserStats, cptr)  (++UserStats.clients, ++(cli_serv(cptr)->clients))
+/** Count a new remote server. */
+#define Count_newremoteserver(UserStats)  (++UserStats.servers)
+
+/** Count a remote user quit. */
+#define Count_remoteclientquits(UserStats,cptr)                \
+  do { \
+    --UserStats.clients; \
+    if (!IsServer(cptr)) \
+      --(cli_serv(cli_user(cptr)->server)->clients); \
+  } while (0)
+
+/** Count a remote server quit. */
+#define Count_remoteserverquits(UserStats)      (--UserStats.servers)
+
+/* Macros for local connections: */
+/** Count a new local unknown connection. */
+#define Count_newunknown(UserStats)                     (++UserStats.unknowns)
+/** Update counters when \a cptr goes from unknown to registered. */
+#define Count_unknownbecomesclient(cptr, UserStats) \
+  do { \
+    --UserStats.unknowns; ++UserStats.local_clients; ++UserStats.clients; \
+    if (match(feature_str(FEAT_DOMAINNAME), cli_sockhost(cptr)) == 0) \
+      ++current_load.local_count; \
+    if (UserStats.local_clients > max_client_count) \
+      max_client_count = UserStats.local_clients; \
+    if (UserStats.local_clients + UserStats.local_servers > max_connection_count) \
+    { \
+      max_connection_count = UserStats.local_clients + UserStats.local_servers; \
+      if (max_connection_count % 10 == 0) \
+        sendto_opmask_butone(0, SNO_OLDSNO, "Maximum connections: %d (%d clients)", \
+            max_connection_count, max_client_count); \
+    } \
+  } while(0)
+/** Update counters when \a cptr goes from unknown to server. */
+#define Count_unknownbecomesserver(UserStats)   do { --UserStats.unknowns; ++UserStats.local_servers; ++UserStats.servers; } while(0)
+/** Update counters when \a cptr (a local user) disconnects. */
+#define Count_clientdisconnects(cptr, UserStats) \
+  do \
+  { \
+    --UserStats.local_clients; --UserStats.clients; \
+    if (match(feature_str(FEAT_DOMAINNAME), cli_sockhost(cptr)) == 0) \
+      --current_load.local_count; \
+  } while(0)
+/** Update counters when a local server disconnects. */
+#define Count_serverdisconnects(UserStats)              do { --UserStats.local_servers; --UserStats.servers; } while(0)
+/** Update counters when an unknown client disconnects. */
+#define Count_unknowndisconnects(UserStats)             (--UserStats.unknowns)
+
+/*
+ * Prototypes
+ */
+
+
+#endif /* INCLUDED_querycmds_h */
diff --git a/include/random.h b/include/random.h
new file mode 100644 (file)
index 0000000..a1495dd
--- /dev/null
@@ -0,0 +1,19 @@
+/** @file random.h
+ * @brief 32-bit pseudo-random number generator interface.
+ * @version $Id: random.h 1213 2004-10-03 17:53:13Z entrope $
+ */
+#ifndef INCLUDED_random_h
+#define INCLUDED_random_h
+
+struct Client;
+
+/*
+ * Proto types
+ */
+
+extern int random_seed_set(struct Client* from, const char* const* fields,
+                          int count);
+
+extern unsigned int ircrandom(void);
+
+#endif /* INCLUDED_random_h */
diff --git a/include/res.h b/include/res.h
new file mode 100644 (file)
index 0000000..e95d4d6
--- /dev/null
@@ -0,0 +1,158 @@
+/** @file
+ * @brief IRC resolver API.
+ * @version $Id: res.h 1823 2007-08-09 03:41:18Z entrope $
+ */
+
+#ifndef INCLUDED_res_h
+#define INCLUDED_res_h
+
+#ifndef INCLUDED_config_h
+#include "config.h"
+#endif
+
+#ifndef INCLUDED_sys_types_h
+#include <sys/types.h>
+#define INCLUDED_sys_types_h
+#endif
+
+#ifndef INCLUDED_sys_socket_h
+#include <sys/socket.h>
+#define INCLUDED_sys_socket_h
+#endif
+
+#include <netdb.h>
+
+#ifndef INCLUDED_netinet_in_h
+#include <netinet/in.h>
+#define INCLUDED_netinet_in_h
+#endif
+
+#ifdef HAVE_STDINT_H
+#ifndef INCLUDED_stdint_h
+#include <stdint.h>
+#define INCLUDED_stdint_h
+#endif
+#endif
+
+struct Client;
+struct StatDesc;
+
+/* Here we define some values lifted from nameser.h */
+#define NS_INT16SZ 2 /**< Size of a 16-bit value. */
+#define NS_INT32SZ 4 /**< Size of a 32-bit value. */
+#define NS_CMPRSFLGS 0xc0 /**< Prefix flags that indicate special types */
+#define NS_MAXCDNAME 255 /**< Maximum length of a compressed domain name. */
+#define QUERY 0      /**< Forward (normal) DNS query operation. */
+#define NO_ERRORS 0  /**< No errors processing a query. */
+#define SERVFAIL 2   /**< Server error while processing a query. */
+#define NXDOMAIN 3   /**< Domain name in query does not exist. */
+#define T_A 1        /**< Hostname -> IPv4 query type. */
+#define T_AAAA 28    /**< Hostname -> IPv6 query type. */
+#define T_PTR 12     /**< IP(v4 or v6) -> hostname query type. */
+#define T_CNAME 5    /**< Canonical name resolution query type. */
+#define C_IN 1       /**< Internet query class. */
+#define QFIXEDSZ 4   /**< Length of fixed-size part of query. */
+#define HFIXEDSZ 12  /**< Length of fixed-size DNS header. */
+
+/** Structure to store an IP address. */
+struct irc_in_addr
+{
+  unsigned short in6_16[8]; /**< IPv6 encoded parts, little-endian. */
+};
+
+/** Structure to store an IP address and port number. */
+struct irc_sockaddr
+{
+  struct irc_in_addr addr; /**< IP address. */
+  unsigned short port;     /**< Port number, host-endian. */
+};
+
+/** DNS callback function signature. */
+typedef void (*dns_callback_f)(void *vptr, const struct irc_in_addr *addr, const char *h_name);
+
+/** DNS query and response header. */
+typedef struct
+{
+       unsigned        id :16;         /**< query identification number */
+#ifdef WORDS_BIGENDIAN
+                       /* fields in third byte */
+       unsigned        qr: 1;          /**< response flag */
+       unsigned        opcode: 4;      /**< purpose of message */
+       unsigned        aa: 1;          /**< authoritive answer */
+       unsigned        tc: 1;          /**< truncated message */
+       unsigned        rd: 1;          /**< recursion desired */
+                       /* fields in fourth byte */
+       unsigned        ra: 1;          /**< recursion available */
+       unsigned        unused :1;      /**< unused bits (MBZ as of 4.9.3a3) */
+       unsigned        ad: 1;          /**< authentic data from named */
+       unsigned        cd: 1;          /**< checking disabled by resolver */
+       unsigned        rcode :4;       /**< response code */
+#else
+                       /* fields in third byte */
+       unsigned        rd :1;          /**< recursion desired */
+       unsigned        tc :1;          /**< truncated message */
+       unsigned        aa :1;          /**< authoritive answer */
+       unsigned        opcode :4;      /**< purpose of message */
+       unsigned        qr :1;          /**< response flag */
+                       /* fields in fourth byte */
+       unsigned        rcode :4;       /**< response code */
+       unsigned        cd: 1;          /**< checking disabled by resolver */
+       unsigned        ad: 1;          /**< authentic data from named */
+       unsigned        unused :1;      /**< unused bits (MBZ as of 4.9.3a3) */
+       unsigned        ra :1;          /**< recursion available */
+#endif
+                       /* remaining bytes */
+       unsigned        qdcount :16;    /**< number of question entries */
+       unsigned        ancount :16;    /**< number of answer entries */
+       unsigned        nscount :16;    /**< number of authority entries */
+       unsigned        arcount :16;    /**< number of resource entries */
+} HEADER;
+
+extern void restart_resolver(void);
+extern void clear_nameservers(void);
+extern void add_nameserver(const char *ipaddr);
+extern void add_local_domain(char *hname, size_t size);
+extern size_t cres_mem(struct Client* cptr);
+extern void delete_resolver_queries(const void *vptr);
+extern void report_dns_servers(struct Client *source_p, const struct StatDesc *sd, char *param);
+extern void gethost_byname(const char *name, dns_callback_f callback, void *ctx);
+extern void gethost_byaddr(const struct irc_in_addr *addr, dns_callback_f callback, void *ctx);
+
+/** Evaluate to non-zero if \a ADDR is an unspecified (all zeros) address. */
+#define irc_in_addr_unspec(ADDR) (((ADDR)->in6_16[0] == 0) \
+                                  && ((ADDR)->in6_16[1] == 0) \
+                                  && ((ADDR)->in6_16[2] == 0) \
+                                  && ((ADDR)->in6_16[3] == 0) \
+                                  && ((ADDR)->in6_16[4] == 0) \
+                                  && ((ADDR)->in6_16[6] == 0) \
+                                  && ((ADDR)->in6_16[7] == 0) \
+                                  && ((ADDR)->in6_16[5] == 0 \
+                                      || (ADDR)->in6_16[5] == 65535))
+/** Evaluate to non-zero if \a ADDR is a valid address (not all 0s and not all 1s). */
+#define irc_in_addr_valid(ADDR) (((ADDR)->in6_16[0] && ~(ADDR)->in6_16[0]) \
+                                 || (ADDR)->in6_16[1] != (ADDR)->in6_16[0] \
+                                 || (ADDR)->in6_16[2] != (ADDR)->in6_16[0] \
+                                 || (ADDR)->in6_16[3] != (ADDR)->in6_16[0] \
+                                 || (ADDR)->in6_16[4] != (ADDR)->in6_16[0] \
+                                 || (ADDR)->in6_16[5] != (ADDR)->in6_16[0] \
+                                 || (ADDR)->in6_16[6] != (ADDR)->in6_16[0] \
+                                 || (ADDR)->in6_16[7] != (ADDR)->in6_16[0])
+/** Evaluate to non-zero if \a ADDR (of type struct irc_in_addr) is an IPv4 address. */
+#define irc_in_addr_is_ipv4(ADDR) (!(ADDR)->in6_16[0] && !(ADDR)->in6_16[1] && !(ADDR)->in6_16[2] \
+                                   && !(ADDR)->in6_16[3] && !(ADDR)->in6_16[4] \
+                                   && ((!(ADDR)->in6_16[5] && (ADDR)->in6_16[6]) \
+                                       || (ADDR)->in6_16[5] == 65535))
+/** Evaluate to non-zero if \a A is a different IP than \a B. */
+#define irc_in_addr_cmp(A,B) (irc_in_addr_is_ipv4(A) ? ((A)->in6_16[6] != (B)->in6_16[6] \
+                                  || (A)->in6_16[7] != (B)->in6_16[7] || !irc_in_addr_is_ipv4(B)) \
+                              : memcmp((A), (B), sizeof(struct irc_in_addr)))
+/** Evaluate to non-zero if \a ADDR is a loopback address. */
+#define irc_in_addr_is_loopback(ADDR) (!(ADDR)->in6_16[0] && !(ADDR)->in6_16[1] && !(ADDR)->in6_16[2] \
+                                       && !(ADDR)->in6_16[3] && !(ADDR)->in6_16[4] \
+                                       && ((!(ADDR)->in6_16[5] \
+                                            && ((!(ADDR)->in6_16[6] && (ADDR)->in6_16[7] == htons(1)) \
+                                                || (ntohs((ADDR)->in6_16[6]) & 0xff00) == 0x7f00)) \
+                                           || (((ADDR)->in6_16[5] == 65535) \
+                                               && (ntohs((ADDR)->in6_16[6]) & 0xff00) == 0x7f00)))
+
+#endif
diff --git a/include/s_auth.h b/include/s_auth.h
new file mode 100644 (file)
index 0000000..1a763c9
--- /dev/null
@@ -0,0 +1,57 @@
+/************************************************************************
+ *   IRC - Internet Relay Chat, include/s_auth.h
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 1, or (at your option)
+ *   any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+/** @file
+ * @brief Interface for DNS and ident lookups.
+ * @version $Id: s_auth.h 1748 2007-01-16 01:21:37Z entrope $
+ */
+#ifndef INCLUDED_s_auth_h
+#define INCLUDED_s_auth_h
+#ifndef INCLUDED_sys_types_h
+#include <sys/types.h>
+#define INCLUDED_sys_types_h
+#endif
+#ifndef INCLUDED_ircd_events_h
+#include "ircd_events.h"
+#endif
+
+struct Client;
+struct AuthRequest;
+struct StatDesc;
+
+extern void start_auth(struct Client *);
+extern int EmptyPassString(char* password);
+extern int auth_ping_timeout(struct Client *);
+extern int auth_set_pong(struct AuthRequest *auth, unsigned int cookie);
+extern int auth_set_user(struct AuthRequest *auth, const char *username, const char *hostname, const char *servername, const char *userinfo);
+extern int auth_set_nick(struct AuthRequest *auth, const char *nickname);
+extern int auth_set_password(struct AuthRequest *auth, char *password);
+extern int auth_cap_start(struct AuthRequest *auth);
+extern int auth_cap_done(struct AuthRequest *auth);
+extern void destroy_auth_request(struct AuthRequest *req);
+extern signed int auth_loc_query(struct AuthRequest *auth, const char *account, const char *pass, int force);
+extern void auth_loc_reply(const char *numeric, const char *account, const char *fakehost, const char *flags[], signed int argc);
+
+extern int auth_spawn(int argc, char *argv[], int required);
+extern void auth_send_exit(struct Client *cptr);
+extern void auth_mark_closing(void);
+extern void auth_close_unused(void);
+extern void report_iauth_conf(struct Client *cptr, const struct StatDesc *sd, char *param);
+extern void report_iauth_stats(struct Client *cptr, const struct StatDesc *sd, char *param);
+
+#endif /* INCLUDED_s_auth_h */
+
diff --git a/include/s_bsd.h b/include/s_bsd.h
new file mode 100644 (file)
index 0000000..5bf4e67
--- /dev/null
@@ -0,0 +1,78 @@
+/** @file s_bsd.h
+ * @brief Wrapper functions to avoid direct use of BSD APIs.
+ * @version $Id: s_bsd.h 1764 2007-02-25 15:41:49Z entrope $
+ */
+#ifndef INCLUDED_s_bsd_h
+#define INCLUDED_s_bsd_h
+#ifndef INCLUDED_sys_types_h
+#include <sys/types.h>         /* size_t, time_t */
+#define INCLUDED_sys_types_h
+#endif
+#ifndef INCLUDED_netinet_in_h
+#include <netinet/in.h>
+#define INCLUDED_netinet_in_h
+#endif
+
+#include "ssl.h"
+
+struct Client;
+struct ConfItem;
+struct Listener;
+struct MsgQ;
+struct irc_in_addr;
+struct Event;
+
+/*
+ * TCP window sizes
+ * Set server window to a large value for fat pipes,
+ * set client to a smaller size to allow TCP flow control
+ * to reduce flooding
+ */
+/** Default TCP window size for server connections. */
+#define SERVER_TCP_WINDOW 61440
+/** Default TCP window size for client connections. */
+#define CLIENT_TCP_WINDOW 2048
+
+extern void report_error(const char* text, const char* who, int err);
+/*
+ * text for report_error
+ */
+extern const char* const BIND_ERROR_MSG;
+extern const char* const LISTEN_ERROR_MSG;
+extern const char* const NONB_ERROR_MSG;
+extern const char* const REUSEADDR_ERROR_MSG;
+extern const char* const SOCKET_ERROR_MSG;
+extern const char* const CONNLIMIT_ERROR_MSG;
+extern const char* const ACCEPT_ERROR_MSG;
+extern const char* const PEERNAME_ERROR_MSG;
+extern const char* const POLL_ERROR_MSG;
+extern const char* const SELECT_ERROR_MSG;
+extern const char* const CONNECT_ERROR_MSG;
+extern const char* const SETBUFS_ERROR_MSG;
+extern const char* const TOS_ERROR_MSG;
+extern const char* const REGISTER_ERROR_MSG;
+
+extern int            HighestFd;
+extern struct Client* LocalClientArray[MAXCONNECTIONS];
+extern struct irc_sockaddr VirtualHost_v4;
+extern struct irc_sockaddr VirtualHost_v6;
+extern struct irc_sockaddr VirtualHost_dns_v4;
+extern struct irc_sockaddr VirtualHost_dns_v6;
+
+/*
+ * Proto types
+ */
+extern unsigned int deliver_it(struct Client *cptr, struct MsgQ *buf);
+extern int connect_server(struct ConfItem* aconf, struct Client* by);
+extern int  net_close_unregistered_connections(struct Client* source);
+extern void close_connection(struct Client *cptr);
+extern void add_connection(struct Listener* listener, int fd, ssl_session_t *ssl);
+extern int  read_message(time_t delay);
+extern void init_server_identity(void);
+extern void close_connections(int close_stderr);
+extern int  init_connection_limits(void);
+extern void update_write(struct Client* cptr);
+extern int completed_connection(struct Client* cptr);
+extern void client_sock_callback(struct Event* ev);
+
+#endif /* INCLUDED_s_bsd_h */
diff --git a/include/s_conf.h b/include/s_conf.h
new file mode 100644 (file)
index 0000000..fb9135b
--- /dev/null
@@ -0,0 +1,230 @@
+/** @file s_conf.h
+ * @brief ircd configuration file API.
+ * @version $Id: s_conf.h 1462 2005-08-21 13:46:08Z entrope $
+ */
+#ifndef INCLUDED_s_conf_h
+#define INCLUDED_s_conf_h
+#ifndef INCLUDED_time_h
+#include <time.h>              /* struct tm */
+#define INCLUDED_time_h
+#endif
+#ifndef INCLUDED_sys_types_h
+#include <sys/types.h>
+#define INCLUDED_sys_types_h
+#endif
+#include "client.h"
+
+struct Client;
+struct SLink;
+struct Message;
+
+/*
+ * General defines
+ */
+
+/*-----------------------------------------------------------------------------
+ * Macros
+ */
+
+#define CONF_ILLEGAL            0x80000000 /**< Delete the ConfItem when no remaining clients. */
+#define CONF_CLIENT             0x0002     /**< ConfItem describes a Client block */
+#define CONF_SERVER             0x0004     /**< ConfItem describes a Connect block */
+#define CONF_OPERATOR           0x0020     /**< ConfItem describes an Operator block */
+#define CONF_UWORLD             0x8000     /**< ConfItem describes a Uworld server */
+
+#define CONF_AUTOCONNECT        0x0001     /**< Autoconnect to a server */
+#define CONF_SECURE             0x0002     /**< Secure connection */
+
+/** Indicates ConfItem types that count associated clients. */
+#define CONF_CLIENT_MASK        (CONF_CLIENT | CONF_OPERATOR | CONF_SERVER)
+
+/** Checks whether the CONF_ILLEGAL bit is set on \a x. */
+#define IsIllegal(x)    ((x)->status & CONF_ILLEGAL)
+
+/*
+ * Structures
+ */
+
+/** Configuration item to limit peer or client access. */
+struct ConfItem
+{
+  struct ConfItem *next;    /**< Next ConfItem in #GlobalConfList */
+  unsigned int status;      /**< Set of CONF_* bits. */
+  unsigned int clients;     /**< Number of *LOCAL* clients using this */
+  unsigned int maximum;     /**< For CONF_SERVER, max hops.
+                               For CONF_CLIENT, max connects per IP. */
+  struct ConnectionClass *conn_class;  /**< Class of connection */
+  struct irc_sockaddr origin;  /**< Local address for outbound connections */
+  struct irc_sockaddr address; /**< IP and port */
+  char *username;     /**< For CONF_CLIENT and CONF_OPERATOR, username mask. */
+  char *host;         /**< Peer hostname */
+  char *origin_name;  /**< Text form of origin address */
+  char *passwd;       /**< Password field */
+  char *name;         /**< Name of peer */
+  char *hub_limit;    /**< Mask that limits servers allowed behind
+                         this one. */
+  time_t hold;        /**< Earliest time to attempt an outbound
+                         connect on this ConfItem. */
+  int dns_pending;    /**< A dns request is pending. */
+  int flags;          /**< Additional modifiers for item. */
+  int addrbits;       /**< Number of bits valid in ConfItem::address. */
+  struct Privs privs; /**< Privileges for opers. */
+  /** Used to detect if a privilege has been set by this ConfItem. */
+  struct Privs privs_dirty;
+};
+
+/** Channel quarantine structure. */
+struct qline
+{
+  struct qline *next; /**< Next qline in #GlobalQuarantineList. */
+  char *chname;       /**< Quarantined channel name. */
+  char *reason;       /**< Reason for quarantine. */
+};
+
+/** Local K-line structure. */
+struct DenyConf {
+  struct DenyConf*    next;     /**< Next DenyConf in #denyConfList. */
+  char*               hostmask; /**< Mask for  IP or hostname. */
+  char*               message;  /**< Message to send to denied users. */
+  char*               usermask; /**< Mask for client's username. */
+  char*               realmask; /**< Mask for realname. */
+  struct irc_in_addr  address;  /**< Address for IP-based denies. */
+  unsigned int        flags;    /**< Interpretation flags for the above.  */
+  unsigned char       bits;     /**< Number of bits for ipkills */
+};
+
+#define DENY_FLAGS_FILE     0x0001 /**< Comment is a filename */
+
+/** Local server configuration. */
+struct LocalConf {
+  char*          name;        /**< Name of server. */
+  char*          description; /**< Description of server. */
+  unsigned int   numeric;     /**< Globally assigned server numnick. */
+  char*          location1;   /**< First line of location information. */
+  char*          location2;   /**< Second line of location information. */
+  char*          contact;     /**< Admin contact information. */
+};
+
+enum {
+  CRULE_AUTO = 1, /**< CRule applies to automatic connections. */
+  CRULE_ALL  = 2, /**< CRule applies to oper-requested connections. */
+  CRULE_MASK = 3
+};
+
+/** Connection rule configuration. */
+struct CRuleConf {
+  struct CRuleConf* next;     /**< Next CRule in cruleConfList. */
+  char*             hostmask; /**< Mask of affected server names. */
+  char*             rule;     /**< Text version of the rule. */
+  int               type;     /**< One of CRULE_AUTO or CRULE_ALL. */
+  struct CRuleNode* node;     /**< Parsed form of the rule. */
+};
+
+/** Authorization check result. */
+enum AuthorizationCheckResult {
+  ACR_OK,                 /**< User accepted. */
+  ACR_NO_AUTHORIZATION,   /**< No matching ConfItem for the user. */
+  ACR_TOO_MANY_IN_CLASS,  /**< Connection class was already full. */
+  ACR_TOO_MANY_FROM_IP,   /**< User's IP already has max connections. */
+  ACR_ALREADY_AUTHORIZED, /**< User already had an attached ConfItem. */
+  ACR_BAD_SOCKET          /**< Client has bad file descriptor. */
+};
+
+/** Target description for service commands. */
+struct nick_host {
+  struct nick_host *next; /**< Next nick_host struct in struct s_map. */
+  int nicklen;            /**< offset of @ part of server string */
+  char nick[1];           /**< start of nick\@server string */
+};
+
+#define SMAP_FAST 1           /**< Command does not have MFLG_SLOW. */
+
+/** Target set for a service pseudo-command. */
+struct s_map {
+  struct s_map *next;         /**< Next element in #GlobalServiceMapList. */
+  struct Message *msg;        /**< Message element formed for this mapping. */
+  char *name;                 /**< Text name of the mapping. */
+  char *command;              /**< Command name to use. */
+  char *prepend;              /**< Extra text to prepend to user's text. */
+  unsigned int flags;         /**< Bitwise map of SMAP_* flags. */
+  struct nick_host *services; /**< Linked list of possible targets. */
+};
+
+/** WebIRC config types. */
+#define WEBIRC_PASS  0      /**< Password the webirc has to send. */
+#define WEBIRC_HOST  1      /**< Host/IP mask which must match to the webirc socket. */
+#define WEBIRC_SPOOF 2      /**< Host/IP mask which must match the spoofed ip. */
+
+/** WebIRC config node */
+struct webirc_node {
+    unsigned int type;
+    unsigned int neg;
+    char *content;
+    struct webirc_node *next, *prev;
+};
+
+/** WebIRC config list */
+struct webirc_block {
+    char name[NICKLEN + 1];             /**< name of the block */
+    struct webirc_node *list;           /**< list of entries: circular double linked list;
+                                                              NULL if empty; list itself is the first node
+                                                              sorted by type (ascending) */
+    struct webirc_block *next, *prev;
+};
+
+
+/*
+ * GLOBALS
+ */
+extern struct ConfItem* GlobalConfList;
+extern int              GlobalConfCount;
+extern struct s_map*    GlobalServiceMapList;
+extern struct qline*    GlobalQuarantineList;
+extern char *           GlobalForwards[256];
+
+/* WebIRC config list.
+ * - circular double linked list
+ * - NULL if no node present
+ * - the list itself is the first node
+ */
+extern struct webirc_block *GlobalWebIRCConf;
+
+/*
+ * Proto types
+ */
+
+extern int init_conf(void);
+
+extern const struct LocalConf* conf_get_local(void);
+extern const struct CRuleConf* conf_get_crule_list(void);
+extern const struct DenyConf*  conf_get_deny_list(void);
+
+extern struct webirc_block *webirc_block();
+extern void webirc_establish(struct webirc_block *block);
+extern void webirc_set(struct webirc_block *block, unsigned int type, const char *content, unsigned int len, unsigned int neg);
+extern void webirc_list_clear(struct webirc_block *block);
+extern void webirc_clear();
+
+extern const char* conf_eval_crule(const char* name, int mask);
+
+extern struct ConfItem* attach_confs_byhost(struct Client* cptr, const char* host, int statmask);
+extern struct ConfItem* find_conf_byhost(struct SLink* lp, const char* host, int statmask);
+extern struct ConfItem* find_conf_byname(struct SLink* lp, const char *name, int statmask);
+extern struct ConfItem* conf_find_server(const char* name);
+
+extern void det_confs_butmask(struct Client *cptr, int mask);
+extern enum AuthorizationCheckResult attach_conf(struct Client *cptr, struct ConfItem *aconf);
+extern struct ConfItem* find_conf_exact(const char* name, struct Client *cptr, int statmask);
+extern enum AuthorizationCheckResult conf_check_client(struct Client *cptr);
+extern int  conf_check_server(struct Client *cptr);
+extern int rehash(struct Client *cptr, int sig);
+extern int find_kill(struct Client *cptr);
+extern const char *find_quarantine(const char* chname);
+extern void lookup_confhost(struct ConfItem *aconf);
+extern void conf_parse_userhost(struct ConfItem *aconf, char *host);
+extern struct ConfItem *conf_debug_iline(const char *client);
+extern void free_mapping(struct s_map *smap);
+
+extern void yyerror(const char *msg);
+
+#endif /* INCLUDED_s_conf_h */
diff --git a/include/s_debug.h b/include/s_debug.h
new file mode 100644 (file)
index 0000000..ccb9f26
--- /dev/null
@@ -0,0 +1,68 @@
+/* @file s_debug.h
+ * @brief Debug APIs for the ircd.
+ * @version $Id: s_debug.h 1231 2004-10-05 04:21:37Z entrope $
+ */
+#ifndef INCLUDED_s_debug_h
+#define INCLUDED_s_debug_h
+#ifndef INCLUDED_config_h
+#include "config.h"          /* Needed for DEBUGMODE */
+#endif
+#ifndef INCLUDED_ircd_defs_h
+#include "ircd_defs.h"       /* Needed for HOSTLEN */
+#endif
+#ifndef INCLUDED_stdarg_h
+#include <stdarg.h>
+#define INCLUDED_stdarg_h
+#endif
+
+struct Client;
+struct StatDesc;
+
+#ifdef DEBUGMODE
+
+/*
+ * Macro's
+ */
+
+/** If DEBUGMODE is defined, output the debug message.
+ * @param x A two-or-more element list containing level, format and arguments.
+ */
+#define Debug(x) debug x
+#define LOGFILE LPATH /**< Path to debug log file. */
+
+/*
+ * defined debugging levels
+ */
+#define DEBUG_FATAL   0  /**< fatal error */
+#define DEBUG_ERROR   1  /**< report_error() and other errors that are found */
+#define DEBUG_NOTICE  3  /**< somewhat useful, but non-critical, messages */
+#define DEBUG_DNS     4  /**< used by all DNS related routines - a *lot* */
+#define DEBUG_INFO    5  /**< general useful info */
+#define DEBUG_SEND    7  /**< everything that is sent out */
+#define DEBUG_DEBUG   8  /**< everything that is received */ 
+#define DEBUG_MALLOC  9  /**< malloc/free calls */
+#define DEBUG_LIST   10  /**< debug list use */
+#define DEBUG_ENGINE 11  /**< debug event engine; can dump gigabyte logs */
+
+/*
+ * proto types
+ */
+
+extern void vdebug(int level, const char *form, va_list vl);
+extern void debug(int level, const char *form, ...);
+extern void send_usage(struct Client *cptr, const struct StatDesc *sd,
+                       char *param);
+
+#else /* !DEBUGMODE */
+
+#define Debug(x)
+#define LOGFILE "/dev/null"
+
+#endif /* !DEBUGMODE */
+
+extern const char* debug_serveropts(void);
+extern void debug_init(int use_tty);
+extern void count_memory(struct Client *cptr, const struct StatDesc *sd,
+                         char *param);
+
+#endif /* INCLUDED_s_debug_h */
diff --git a/include/s_misc.h b/include/s_misc.h
new file mode 100644 (file)
index 0000000..13d7e2d
--- /dev/null
@@ -0,0 +1,94 @@
+/** @file s_misc.h
+ * @brief Miscellaneous support functions and declarations.
+ * @version $Id: s_misc.h 1436 2005-06-27 13:11:52Z entrope $
+ */
+#ifndef INCLUDED_s_misc_h
+#define INCLUDED_s_misc_h
+#ifndef INCLUDED_stdarg_h
+#include <stdarg.h>           /* va_list */
+#define INCLUDED_stdarg_h
+#endif
+#ifndef INCLUDED_sys_types_h
+#include <sys/types.h>        /* time_t */
+#define INCLUDED_sys_types_h
+#endif
+
+
+struct Client;
+struct StatDesc;
+struct ConfItem;
+
+/*-----------------------------------------------------------------------------
+ * Macros
+ */
+
+/** Return value from various functions to indicate the source has
+ * been disconnected. */
+#define CPTR_KILLED     -2
+
+/*
+ * Structures
+ */
+
+#ifdef HAVE_INTTYPES_H
+# ifndef INCLUDED_inttypes_h
+#  include <inttypes.h>
+#  define INCLUDED_inttypes_h
+# endif
+#else
+# ifdef HAVE_STDINT_H
+#  ifndef INCLUDED_stdint_h
+#   include <stdint.h>
+#   define INCLUDED_stdint_h
+#  endif
+# endif
+#endif
+
+/** Structure used to count many server-wide statistics. */
+struct ServerStatistics {
+  unsigned int is_cl;           /**< number of client connections */
+  unsigned int is_sv;           /**< number of server connections */
+  unsigned int is_ni;           /**< connection but no idea who it was */
+  uint64_t is_cbs;              /**< bytes sent to clients */
+  uint64_t is_cbr;              /**< bytes received to clients */
+  uint64_t is_sbs;              /**< bytes sent to servers */
+  uint64_t is_sbr;              /**< bytes received to servers */
+  uint64_t is_cti;              /**< time spent connected by clients */
+  uint64_t is_sti;              /**< time spent connected by servers */
+  unsigned int is_ac;           /**< connections accepted */
+  unsigned int is_ref;          /**< accepts refused */
+  unsigned int is_unco;         /**< unknown commands */
+  unsigned int is_wrdi;         /**< command going in wrong direction */
+  unsigned int is_unpf;         /**< unknown prefix */
+  unsigned int is_empt;         /**< empty message */
+  unsigned int is_num;          /**< numeric message */
+  unsigned int is_kill;         /**< number of kills generated on collisions */
+  unsigned int is_fake;         /**< MODE 'fakes' */
+  unsigned int is_asuc;         /**< successful auth requests */
+  unsigned int is_abad;         /**< bad auth requests */
+  unsigned int is_loc;          /**< local connections made */
+  unsigned int uping_recv;      /**< UDP Pings received */
+};
+
+/*
+ * Prototypes
+ */
+
+extern int check_registered(struct Client *sptr);
+extern int check_registered_user(struct Client *sptr);
+extern int exit_client(struct Client *cptr, struct Client *bcptr,
+    struct Client *sptr, const char *comment);
+extern char *myctime(time_t value);
+extern int exit_client_msg(struct Client *cptr, struct Client *bcptr,
+                           struct Client *sptr, const char *pattern, ...);
+extern void initstats(void);
+extern char *date(time_t clock);
+extern int vexit_client_msg(struct Client *cptr, struct Client *bcptr,
+    struct Client *sptr, const char *pattern, va_list vl);
+extern void tstats(struct Client *cptr, const struct StatDesc *sd,
+                   char *param);
+
+extern struct ServerStatistics* ServerStats;
+
+#endif /* INCLUDED_s_misc_h */
+
diff --git a/include/s_numeric.h b/include/s_numeric.h
new file mode 100644 (file)
index 0000000..f8d8168
--- /dev/null
@@ -0,0 +1,17 @@
+/** @file s_numeric.h
+ * @brief Send a numeric message to a client.
+ * @version $Id: s_numeric.h 1231 2004-10-05 04:21:37Z entrope $
+ */
+#ifndef INCLUDED_s_numeric_h
+#define INCLUDED_s_numeric_h
+
+struct Client;
+
+/*
+ * Prototypes
+ */
+
+extern int do_numeric(int numeric, int nnn, struct Client *cptr, struct Client *sptr,
+    int parc, char *parv[]);
+
+#endif /* INCLUDED_s_numeric_h */
diff --git a/include/s_serv.h b/include/s_serv.h
new file mode 100644 (file)
index 0000000..866590a
--- /dev/null
@@ -0,0 +1,27 @@
+/** @file s_serv.h
+ * @brief Miscellaneous server support functions.
+ * @version $Id: s_serv.h 1231 2004-10-05 04:21:37Z entrope $
+ */
+#ifndef INCLUDED_s_serv_h
+#define INCLUDED_s_serv_h
+#ifndef INCLUDED_sys_types_h
+#include <sys/types.h>
+#define INCLUDED_sys_types_h
+#endif
+
+struct ConfItem;
+struct Client;
+
+extern unsigned int max_connection_count;
+extern unsigned int max_client_count;
+
+/*
+ * Prototypes
+ */
+extern int exit_new_server(struct Client* cptr, struct Client* sptr,
+                           const char* host, time_t timestamp, const char* fmt, ...);
+extern int a_kills_b_too(struct Client *a, struct Client *b);
+extern int server_estab(struct Client *cptr, struct ConfItem *aconf);
+
+
+#endif /* INCLUDED_s_serv_h */
diff --git a/include/s_stats.h b/include/s_stats.h
new file mode 100644 (file)
index 0000000..cbffe63
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ * IRC - Internet Relay Chat, include/s_stats.h
+ * Copyright (C) 2000 Joseph Bongaarts
+ *
+ * See file AUTHORS in IRC package for additional names of
+ * the programmers.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+/** @file
+ * @brief Report configuration lines and other statistics from this server.
+ * @version $Id: s_stats.h 1521 2005-10-12 01:13:48Z entrope $
+ */
+
+#ifndef INCLUDED_s_stats_h
+#define INCLUDED_s_stats_h
+#ifndef INCLUDED_features_h
+#include "ircd_features.h"
+#endif
+
+struct Client;
+
+struct StatDesc;
+
+/** Statistics callback function.
+ * @param[in] cptr Client requesting statistics.
+ * @param[in] sd Stats descriptor for request.
+ * @param[in] param Extra parameter from user (may be NULL).
+ */
+typedef void (*StatFunc)(struct Client *cptr, const struct StatDesc *sd, char *param);
+
+/** Statistics entry. */
+struct StatDesc
+{
+  char         sd_c;           /**< stats character (or '\\0') */
+  char        *sd_name;        /**< full name for stats */
+  unsigned int sd_flags;       /**< flags to control the stats */
+  enum Feature sd_control;     /**< feature controlling stats */
+  StatFunc     sd_func;        /**< function to dispatch to */
+  int          sd_funcdata;    /**< extra data for the function */
+  char        *sd_desc;        /**< descriptive text */
+};
+
+#define STAT_FLAG_OPERONLY 0x01    /**< Oper-only stat */
+#define STAT_FLAG_OPERFEAT 0x02    /**< Oper-only if the feature is true */
+#define STAT_FLAG_LOCONLY  0x04    /**< Local user only */
+#define STAT_FLAG_CASESENS 0x08    /**< Flag is case-sensitive */
+#define STAT_FLAG_VARPARAM 0x10    /**< May have an extra parameter */
+
+extern void stats_init(void);
+const struct StatDesc *stats_find(const char *name_or_char);
+
+#endif /* INCLUDED_s_stats_h */
diff --git a/include/s_user.h b/include/s_user.h
new file mode 100644 (file)
index 0000000..bc365b5
--- /dev/null
@@ -0,0 +1,116 @@
+/** @file s_user.h
+ * @brief Miscellaneous user-related helper functions.
+ * @version $Id: s_user.h 1818 2007-07-14 02:40:01Z isomer $
+ */
+#ifndef INCLUDED_s_user_h
+#define INCLUDED_s_user_h
+#ifndef INCLUDED_sys_types_h
+#include <sys/types.h>
+#define INCLUDED_sys_types_h
+#endif
+
+struct Client;
+struct User;
+struct Channel;
+struct MsgBuf;
+struct Flags;
+
+/*
+ * Macros
+ */
+
+/**
+ * Nick flood limit.
+ * Minimum time between nick changes.
+ * (The first two changes are allowed quickly after another however).
+ */
+#define NICK_DELAY 30
+
+/**
+ * Target flood time.
+ * Minimum time between target changes.
+ * (MAXTARGETS are allowed simultaneously however).
+ * Its set to a power of 2 because we devide through it quite a lot.
+ */
+#define TARGET_DELAY 128
+
+/* return values for hunt_server() */
+
+#define HUNTED_NOSUCH   (-1)    /**< if the hunted server is not found */
+#define HUNTED_ISME     0       /**< if this server should execute the command */
+#define HUNTED_PASS     1       /**< if message passed onwards successfully */
+
+/* send sets for send_umode() */
+#define ALL_UMODES 0  /**< both local and global user modes */
+#define SEND_UMODES 1  /**< global user modes only */
+#define SEND_UMODES_BUT_OPER 2  /**< global user modes except for FLAG_OPER */
+
+/* used when sending to #mask or $mask */
+
+#define MATCH_SERVER  1 /**< flag for relay_masked_message (etc) to indicate the mask matches a server name */
+#define MATCH_HOST    2 /**< flag for relay_masked_message (etc) to indicate the mask matches host name */
+
+/* used for parsing user modes */
+#define ALLOWMODES_ANY 0 /**< Allow any user mode */
+#define ALLOWMODES_DEFAULT  1 /**< Only allow the subset of modes that are legit defaults */
+#define ALLOWMODES_WITHSECSERV  2
+
+/** Formatter function for send_user_info().
+ * @param who Client being displayed.
+ * @param sptr Client requesting information.
+ * @param buf Message buffer that should receive the response text.
+ */
+typedef void (*InfoFormatter)(struct Client* who, struct Client *sptr, struct MsgBuf* buf);
+
+/*
+ * Prototypes
+ */
+extern struct User* make_user(struct Client *cptr);
+extern void         free_user(struct User *user);
+extern int          register_user(struct Client* cptr, struct Client *sptr);
+
+extern void         user_count_memory(size_t* count_out, size_t* bytes_out);
+
+extern int set_nick_name(struct Client* cptr, struct Client* sptr,
+                         const char* nick, int parc, char* parv[], unsigned int force);
+extern void send_umode_out(struct Client* cptr, struct Client* sptr,
+                          struct Flags* old, int prop);
+extern int whisper(struct Client* source, const char* nick,
+                   const char* channel, const char* text, int is_notice);
+extern void send_user_info(struct Client* to, char* names, int rpl,
+                           InfoFormatter fmt);
+
+extern int hide_hostmask(struct Client *cptr, unsigned int flags);
+extern int apply_fakehost(struct Client *cptr);
+extern int set_user_mode(struct Client *cptr, struct Client *sptr,
+                         int parc, char *parv[], int allow_modes);
+extern int is_silenced(struct Client *sptr, struct Client *acptr);
+extern int hunt_server_cmd(struct Client *from, const char *cmd,
+                          const char *tok, struct Client *one,
+                          int MustBeOper, const char *pattern, int server,
+                          int parc, char *parv[]);
+extern int hunt_server_prio_cmd(struct Client *from, const char *cmd,
+                               const char *tok, struct Client *one,
+                               int MustBeOper, const char *pattern,
+                               int server, int parc, char *parv[]);
+extern struct Client* next_client(struct Client* next, const char* ch);
+extern char *umode_str(struct Client *cptr);
+extern int send_umode(struct Client *cptr, struct Client *sptr,
+                      struct Flags *old, int sendset, int fakehost);
+extern void set_snomask(struct Client *, unsigned int, int);
+extern int is_snomask(char *);
+extern int check_target_limit(struct Client *sptr, void *target, const char *name,
+    int created);
+extern void add_target(struct Client *sptr, void *target);
+extern unsigned int umode_make_snomask(unsigned int oldmask, char *arg,
+                                       int what);
+extern int send_supported(struct Client *cptr);
+
+#define NAMES_ALL 1 /**< List all users in channel */
+#define NAMES_VIS 2 /**< List only visible users in non-secret channels */
+#define NAMES_EON 4 /**< Add an 'End Of Names' reply to the end */
+#define NAMES_DEL 8 /**< Show delayed joined users only */
+
+void do_names(struct Client* sptr, struct Channel* chptr, int filter);
+
+#endif /* INCLUDED_s_user_h */
diff --git a/include/send.h b/include/send.h
new file mode 100644 (file)
index 0000000..3d05ef9
--- /dev/null
@@ -0,0 +1,123 @@
+/** @file send.h
+ * @brief Send messages to certain targets.
+ * @version $Id: send.h 1274 2004-12-16 03:28:52Z entrope $
+ */
+#ifndef INCLUDED_send_h
+#define INCLUDED_send_h
+#ifndef INCLUDED_stdarg_h
+#include <stdarg.h>         /* va_list */
+#define INCLUDED_stdarg_h 
+#endif
+#ifndef INCLUDED_time_h
+#include <time.h>      /* time_t */
+#define INCLUDED_time_h
+#endif
+
+struct Channel;
+struct Client;
+struct DBuf;
+struct MsgBuf;
+
+/*
+ * Prototypes
+ */
+extern struct SLink *opsarray[];
+
+extern void send_buffer(struct Client* to, struct MsgBuf* buf, int prio);
+
+extern void kill_highest_sendq(int servers_too);
+extern void flush_connections(struct Client* cptr);
+extern void send_queued(struct Client *to);
+
+/* Send a raw message to one client; USE ONLY IF YOU MUST SEND SOMETHING
+ * WITHOUT A PREFIX!
+ */
+extern void sendrawto_one(struct Client *to, const char *pattern, ...);
+
+/* Send a command to one client */
+extern void sendcmdto_one(struct Client *from, const char *cmd,
+                         const char *tok, struct Client *to,
+                         const char *pattern, ...);
+
+/* Same as above, except it puts the message on the priority queue */
+extern void sendcmdto_prio_one(struct Client *from, const char *cmd,
+                              const char *tok, struct Client *to,
+                              const char *pattern, ...);
+
+/* Send command to servers by flags except one */
+extern void sendcmdto_flag_serv_butone(struct Client *from, const char *cmd,
+                                       const char *tok, struct Client *one,
+                                       int require, int forbid,
+                                       const char *pattern, ...);
+
+/* Send command to all servers except one */
+extern void sendcmdto_serv_butone(struct Client *from, const char *cmd,
+                                 const char *tok, struct Client *one,
+                                 const char *pattern, ...);
+
+/* Send command to all channels user is on */
+extern void sendcmdto_common_channels_butone(struct Client *from,
+                                            const char *cmd,
+                                            const char *tok,
+                                            struct Client *one,
+                                            const char *pattern, ...);
+
+/* Send command to all channel users on this server */
+extern void sendcmdto_channel_butserv_butone(struct Client *from,
+                                            const char *cmd,
+                                            const char *tok,
+                                            struct Channel *to,
+                                            struct Client *one,
+                                             unsigned int skip,
+                                            const char *pattern, ...);
+
+/* Send command to all servers interested in a channel */
+extern void sendcmdto_channel_servers_butone(struct Client *from,
+                                             const char *cmd,
+                                             const char *tok,
+                                             struct Channel *to,
+                                             struct Client *one,
+                                             unsigned int skip,
+                                             const char *pattern, ...);
+
+/* Send command to all interested channel users */
+extern void sendcmdto_channel_butone(struct Client *from, const char *cmd,
+                                    const char *tok, struct Channel *to,
+                                    struct Client *one, unsigned int skip,
+                                    unsigned char prefix, const char *pattern, ...);
+
+#define SKIP_DEAF      0x01    /**< skip users that are +d */
+#define SKIP_BURST     0x02    /**< skip users that are bursting */
+#define SKIP_NONOPS    0x04    /**< skip users that aren't chanops */
+#define SKIP_NONVOICES  0x08    /**< skip users that aren't voiced (includes
+                                   chanops) */
+
+/* Send command to all users having a particular flag set */
+extern void sendwallto_group_butone(struct Client *from, int type, 
+                                   struct Client *one, const char *pattern,
+                                   ...);
+
+#define WALL_DESYNCH   1       /**< send as a DESYNCH message */
+#define WALL_WALLOPS   2       /**< send to all +w opers */
+#define WALL_WALLUSERS 3       /**< send to all +w users */
+
+/* Send command to all matching clients */
+extern void sendcmdto_match_butone(struct Client *from, const char *cmd,
+                                  const char *tok, const char *to,
+                                  struct Client *one, unsigned int who,
+                                  const char *pattern, ...);
+
+/* Send server notice to opers but one--one can be NULL */
+extern void sendto_opmask_butone(struct Client *one, unsigned int mask,
+                                const char *pattern, ...);
+
+/* Same as above, but rate limited */
+extern void sendto_opmask_butone_ratelimited(struct Client *one,
+                                            unsigned int mask, time_t *rate,
+                                            const char *pattern, ...);
+
+/* Same as above, but with variable argument list */
+extern void vsendto_opmask_butone(struct Client *one, unsigned int mask,
+                                 const char *pattern, va_list vl);
+
+#endif /* INCLUDED_send_h */
diff --git a/include/ssl.h b/include/ssl.h
new file mode 100644 (file)
index 0000000..c349d54
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ * IRC - Internet Relay Chat, include/ssl.h
+ * Written by David Herrmann.
+ */
+
+
+#ifndef INCLUDED_ssl_h
+#define INCLUDED_ssl_h
+
+
+/* config.h is always included, but we also need "ircd_osdep.h"
+ * to get the IOResult type.
+ */
+#include "config.h"
+#include "ircd_osdep.h"
+
+
+/* Forward declarations.
+ * Including "listener.h" or "msgq.h" breaks other dependencies.
+ */
+struct Listener;
+struct MsgQ;
+struct Client;
+struct ssl_session_t;
+struct ssl_cred_t;
+typedef struct ssl_session_t ssl_session_t;
+typedef struct ssl_cred_t ssl_cred_t;
+
+
+/* If an SSL backend is available, we declare HAVE_SSL. */
+#if defined(HAVE_OPENSSL) || defined(HAVE_GNUTLS)
+    #define HAVE_SSL
+#endif
+
+
+/* Defines whether the fd is a client or server SSL handle. */
+#define SSL_CLIENT 0
+#define SSL_SERVER 1
+
+
+/* Diffie-Hellman bits. */
+#define SSL_DH_BITS 1024 /* We support ~ bits. */
+#define SSL_DH_RBITS 1024 /* We require the other server to use at least ~ bits. */
+
+
+/* Set certificate and trusted CAs. */
+extern void ssl_setcert(const char *cert);
+extern void ssl_clearcert();
+extern void ssl_addtrust(const char *trust);
+extern void ssl_cleartrusts();
+
+
+extern void ssl_init(void);
+extern void ssl_deinit(void);
+
+extern ssl_cred_t *ssl_cred_new(unsigned int mode, char *cert, char **trusts);
+extern void ssl_cred_free(ssl_cred_t *cred);
+
+extern ssl_session_t *ssl_session_new(unsigned int mode);
+extern void ssl_session_shutdown(ssl_session_t *ssl);
+extern void ssl_session_free(ssl_session_t *ssl);
+
+extern void ssl_accept(struct Listener *listener, signed int fd);
+extern signed int ssl_connect(struct Client *cptr);
+extern void ssl_close(signed int fd, ssl_session_t *ssl, const char *buf, unsigned int len);
+
+extern signed int ssl_send(signed int fd, ssl_session_t *ssl, const char *buf, unsigned int len);
+extern IOResult ssl_recv(signed int fd, ssl_session_t *ssl, char *buf, unsigned int len, unsigned int *count_out);
+extern IOResult ssl_sendv(signed int fd, ssl_session_t *ssl, struct MsgQ *buf, unsigned int *count_in, unsigned int *count_out);
+
+extern const char *ssl_cipherstr(ssl_session_t *ssl);
+
+
+#endif /* INCLUDED_ssl_h */
+
diff --git a/include/struct.h b/include/struct.h
new file mode 100644 (file)
index 0000000..beec331
--- /dev/null
@@ -0,0 +1,93 @@
+/*
+ * IRC - Internet Relay Chat, include/struct.h
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ *                    University of Oulu, Computing Center
+ * Copyright (C) 1996 -1997 Carlo Wood
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+/** @file
+ * @brief Structure definitions for users and servers.
+ * @version $Id: struct.h 1746 2007-01-15 03:08:23Z entrope $
+ */
+#ifndef INCLUDED_struct_h
+#define INCLUDED_struct_h
+#ifndef INCLUDED_sys_types_h
+#include <sys/types.h>      /* time_t */
+#define INCLUDED_sys_types_h
+#endif
+#ifndef INCLUDED_ircd_defs_h
+#include "ircd_defs.h"       /* sizes */
+#endif
+
+struct DLink;
+struct Client;
+struct User;
+struct Membership;
+struct SLink;
+
+/** Describes a server on the network. */
+struct Server {
+  struct Client*  up;           /**< Server one closer to me */
+  struct DLink*   down;         /**< List with downlink servers */
+  struct DLink*   updown;       /**< own Dlink in up->serv->down struct */
+  struct Client** client_list;  /**< List with client pointers on this server */
+  struct User*    user;         /**< who activated this connection */
+  time_t          timestamp;    /**< Remotely determined connect try time */
+  time_t          ghost;        /**< Local time at which a new server
+                                   caused a Ghost */
+  int             lag;          /**< Approximation of the amount of lag to this server */
+  unsigned int    clients;      /**< Number of clients on the server */
+  unsigned short  prot;         /**< Major protocol */
+  unsigned int    nn_mask;      /**< Number of clients supported by server, minus 1 */
+  char          nn_capacity[4]; /**< Numeric representation of server capacity */
+
+  int            asll_rtt;      /**< AsLL round-trip time */
+  int            asll_to;       /**< AsLL upstream lag */
+  int            asll_from;     /**< AsLL downstream lag */
+  time_t         asll_last;     /**< Last time we sent or received an AsLL ping */
+
+  char *last_error_msg;         /**< Allocated memory with last message receive with an ERROR */
+  char by[NICKLEN + 1];         /**< Numnick of client who requested the link */
+};
+
+/** Describes a user on the network. */
+struct User {
+  struct Client*     server;         /**< client structure of server */
+  struct Membership* channel;        /**< chain of channel pointer blocks */
+  struct SLink*      invited;        /**< chain of invite pointer blocks */
+  struct Ban*        silence;        /**< chain of silence pointer blocks */
+  char*              away;           /**< pointer to away message */
+  time_t             last;           /**< last time user sent a message */
+  unsigned int       refcnt;         /**< Number of times this block is referenced */
+  unsigned int       joined;         /**< number of channels joined */
+  unsigned int       invites;        /**< Number of channels we've been invited to */
+  /** Remote account name.  Before registration is complete, this is
+   * either empty or contains the username from the USER command.
+   * After registration, that may be prefixed with ~ or it may be
+   * overwritten with the ident response.
+   */
+  char               username[USERLEN + 1];
+  char               host[HOSTLEN + 1];       /**< displayed hostname */
+  char               realhost[HOSTLEN + 1];   /**< actual hostname */
+  char               fakehost[HOSTLEN + 1];   /**< fakehost */
+  char               account[ACCOUNTLEN + 1]; /**< IRC account name */
+  time_t            acc_create;              /**< IRC account timestamp */
+  time_t             lastmsg_time;            /**< time last PRIVMSG was sent */
+  unsigned int       lastmsg_num;             /**< number of prev msg that matched */
+  char               *lastmsg;                /**< last message */
+};
+
+#endif /* INCLUDED_struct_h */
diff --git a/include/supported.h b/include/supported.h
new file mode 100644 (file)
index 0000000..5b70570
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+ * IRC - Internet Relay Chat, include/supported.h
+ * Copyright (C) 1999 Perry Lorier.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id: supported.h 1860 2007-12-28 15:52:43Z klmitch $
+ *
+ * Description: This file has the featureset that ircu announces on connecting
+ *              a client.  It's in this .h because it's likely to be appended
+ *              to frequently and s_user.h is included by basically everyone.
+ */
+#ifndef INCLUDED_supported_h
+#define INCLUDED_supported_h
+
+#include "channel.h"
+#include "ircd_defs.h"
+
+/* 
+ * 'Features' supported by this ircd
+ */
+#define FEATURES1 \
+                "WHOX"\
+                " WALLCHOPS"\
+                " WALLVOICES"\
+                " USERIP"\
+                " CPRIVMSG"\
+                " CNOTICE"\
+                " SILENCE=%i" \
+                " MODES=%i" \
+                " MAXCHANNELS=%i" \
+                " MAXBANS=%i" \
+                " NICKLEN=%i"
+                
+
+#define FEATURES2 "MAXNICKLEN=%i" \
+                " TOPICLEN=%i" \
+                " AWAYLEN=%i" \
+                " KICKLEN=%i" \
+                " CHANNELLEN=%i" \
+                " MAXCHANNELLEN=%i" \
+                " CHANTYPES=%s" \
+                " PREFIX=%s" \
+                " STATUSMSG=%s" \
+                " CHANMODES=%s" \
+                " CASEMAPPING=%s" \
+                " NETWORK=%s"
+
+#define FEATURESVALUES1 feature_int(FEAT_MAXSILES), MAXMODEPARAMS, \
+                       feature_int(FEAT_MAXCHANNELSPERUSER), \
+                        feature_int(FEAT_MAXBANS), feature_int(FEAT_NICKLEN)
+
+#define FEATURESVALUES2 NICKLEN, TOPICLEN, AWAYLEN, TOPICLEN, \
+                        feature_int(FEAT_CHANNELLEN), CHANNELLEN, \
+                        (feature_bool(FEAT_LOCAL_CHANNELS) ? "#&" : "#"), "(ov)@+", "@+", \
+                        (feature_bool(FEAT_OPLEVELS) ? "b,AkU,al,cCimMnNpstrDdRz" : "b,k,al,cCimMnNpstrDdRz"), \
+                        "rfc1459", feature_str(FEAT_NETWORK)
+
+#endif /* INCLUDED_supported_h */
+
diff --git a/include/sys.h b/include/sys.h
new file mode 100644 (file)
index 0000000..5ef121c
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * IRC - Internet Relay Chat, include/sys.h
+ * Copyright (C) 1990 University of Oulu, Computing Center
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id: sys.h 1442 2005-07-12 02:13:10Z entrope $
+ */
+#ifndef INCLUDED_sys_h
+#define INCLUDED_sys_h
+
+/*
+ * safety margin so we can always have one spare fd, for motd/authd or
+ * whatever else.  -24 allows "safety" margin of 10 listen ports, 8 servers
+ * and space reserved for logfiles, DNS sockets and identd sockets etc.
+ */
+#define MAXCLIENTS      (MAXCONNECTIONS-24)
+
+#define IRCD_MAX(a, b)  ((a) > (b) ? (a) : (b))
+#define IRCD_MIN(a, b)  ((a) < (b) ? (a) : (b))
+
+#endif /* INCLUDED_sys_h */
diff --git a/include/umkpasswd.h b/include/umkpasswd.h
new file mode 100644 (file)
index 0000000..cb4a9cd
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * IRC - Internet Relay Chat, include/umkpasswd.h
+ * Copyright (C) 2002 hikari
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id: umkpasswd.h 1077 2004-06-15 01:20:36Z entrope $
+ */
+#ifndef INCLUDED_umkpasswd_h
+#define INCLUDED_umkpasswd_h 
+
+struct umkpasswd_conf_s {
+ int debuglevel;       /* you really need me to comment this? */
+ char* mech;           /* mechanism we want to use */
+ char* conf;           /* conf file, otherwise DPATH/CPATH */
+ int flags;            /* to add or not to add (or maybe to update) */
+ char* user;           /* username */
+ int operclass;                /* connection class to use */
+};
+
+typedef struct umkpasswd_conf_s umkpasswd_conf_t;
+
+/* values for flags */
+#define ACT_ADDOPER    0x1
+#define ACT_UPDOPER    0x2
+#define ACT_ADDSERV    0x4 /* not implemented yet */
+#define ACT_UPDSRRV    0x8 /* not implemented yet */
+
+const char* default_salts = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789./";
+
+#endif /* INCLUDED_umkpasswd_h */
+
diff --git a/include/uping.h b/include/uping.h
new file mode 100644 (file)
index 0000000..bb9aff6
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+ * IRC - Internet Relay Chat, include/uping.h
+ * Copyright (C) 1995 Carlo Wood
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+/** @file
+ * @brief UDP ping implementation.
+ * @version $Id: uping.h 1290 2004-12-29 03:08:09Z entrope $
+ */
+#ifndef INCLUDED_uping_h
+#define INCLUDED_uping_h
+#ifndef INCLUDED_sys_types_h
+#include <sys/types.h>
+#define INCLUDED_sys_types_h
+#endif
+#ifndef INCLUDED_netinet_in_h
+#include <netinet/in.h>
+#define INCLUDED_netinet_in_h
+#endif
+#ifndef INCLUDED_ircd_defs_h
+#include "ircd_defs.h"
+#endif
+#ifndef INCLUDED_ircd_events_h
+#include "ircd_events.h"
+#endif
+#ifndef INCLUDED_res_h
+#include "res.h"
+#endif
+
+struct Client;
+struct ConfItem;
+
+/** Tracks state of a UDP ping to some other server. */
+struct UPing
+{
+  struct UPing*      next;     /**< next ping in list */
+  int                fd;       /**< socket file descriptor */
+  struct irc_sockaddr addr;    /**< socket name (ip addr, port, family ) */
+  char               count;    /**< number of pings requested */
+  char               sent;     /**< pings sent */
+  char               received; /**< pings received */
+  char               active;   /**< ping active flag */
+  struct Client*     client;   /**< who requested the pings */
+  time_t             lastsent; /**< when last ping was sent */
+  int                ms_min;   /**< minimum time in milliseconds */
+  int                ms_ave;   /**< average time in milliseconds */
+  int                ms_max;   /**< maximum time in milliseconds */
+  struct Socket      socket;   /**< socket structure */
+  struct Timer       sender;   /**< timer telling when next to send a ping */
+  struct Timer       killer;   /**< timer to kill us */
+  unsigned int       freeable; /**< zero when structure can be free()'d */
+  char               name[HOSTLEN + 1]; /**< server name to poing */
+  char               buf[BUFSIZE];      /**< buffer to hold ping times */
+};
+
+#define UPING_PENDING_SOCKET   0x01 /**< pending socket destruction event */
+#define UPING_PENDING_SENDER   0x02 /**< pending sender destruction event */
+#define UPING_PENDING_KILLER   0x04 /**< pending killer destruction event */
+
+extern int  uping_init(void);
+extern void uping_send(struct UPing* pptr);
+extern void uping_read(struct UPing* pptr);
+extern void uping_end(struct UPing* pptr);
+extern void uping_cancel(struct Client *sptr, struct Client *acptr);
+extern struct UPing* uping_begin(void);
+extern int uping_server(struct Client* sptr, struct ConfItem* aconf, int port, int count);
+
+
+#endif /* INCLUDED_uping_h */
diff --git a/include/userload.h b/include/userload.h
new file mode 100644 (file)
index 0000000..3640e1a
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * Userload module by Michael L. VanLoon (mlv) <michaelv@iastate.edu>
+ * Written 2/93.  Originally grafted into irc2.7.2g 4/93.
+ * Rewritten 9/97 by Carlo Wood for ircu2.10.01.
+ *
+ * IRC - Internet Relay Chat, ircd/userload.h
+ * Copyright (C) 1990 University of Oulu, Computing Center
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+/** @file
+ * @brief Userload tracking and statistics.
+ * @version $Id: userload.h 1231 2004-10-05 04:21:37Z entrope $
+ */
+#ifndef INCLUDED_userload_h
+#define INCLUDED_userload_h
+
+struct Client;
+struct StatDesc;
+
+/*
+ * Structures
+ */
+
+/** Tracks load of various types of users. */
+struct current_load_st {
+  unsigned int client_count; /**< Count of locally connected clients. */
+  unsigned int local_count; /**< This field is updated but apparently meaningless. */
+  unsigned int conn_count; /**< Locally connected clients plus servers. */
+};
+
+/*
+ * Proto types
+ */
+
+extern void update_load(void);
+extern void calc_load(struct Client *sptr, const struct StatDesc *sd,
+                      char *param);
+extern void initload(void);
+
+extern struct current_load_st current_load;
+
+#endif /* INCLUDED_userload_h */
diff --git a/include/version.h b/include/version.h
new file mode 100644 (file)
index 0000000..9aebe08
--- /dev/null
@@ -0,0 +1,15 @@
+/*
+ * version.h
+ *
+ * $Id: version.h 27 2000-03-18 05:20:30Z bleep $
+ */
+#ifndef INCLUDED_version_h
+#define INCLUDED_version_h
+
+extern const char *version;
+extern const char *creation;
+extern const char *infotext[];
+extern const char *generation;
+extern const char *svn_srev;
+
+#endif /* INCLUDED_version_h */
diff --git a/include/whocmds.h b/include/whocmds.h
new file mode 100644 (file)
index 0000000..9d266b9
--- /dev/null
@@ -0,0 +1,92 @@
+/** @file whocmds.h
+ * @brief Support functions for /WHO-like commands.
+ * @version $Id: whocmds.h 1838 2007-10-30 01:53:33Z entrope $
+ */
+#ifndef INCLUDED_whocmds_h
+#define INCLUDED_whocmds_h
+
+struct Client;
+struct Channel;
+
+
+/*
+ * m_who() 
+ * m_who with support routines rewritten by Nemesi, August 1997
+ * - Alghoritm have been flattened (no more recursive)
+ * - Several bug fixes
+ * - Strong performance improvement
+ * - Added possibility to have specific fields in the output
+ * See readme.who for further details.
+ */
+
+/* Macros used only in here by m_who and its support functions */
+
+#define WHOSELECT_OPER 1   /**< Flag for /WHO: Show IRC operators. */
+#define WHOSELECT_EXTRA 2  /**< Flag for /WHO: Pull rank to see users. */
+#define WHOSELECT_DELAY 4  /**< Flag for /WHO: Show join-delayed users. */
+
+#define WHO_FIELD_QTY 1    /**< Display query type. */
+#define WHO_FIELD_CHA 2    /**< Show common channel name. */
+#define WHO_FIELD_UID 4    /**< Show username. */
+#define WHO_FIELD_NIP 8    /**< Show IP address. */
+#define WHO_FIELD_HOS 16   /**< Show hostname. */
+#define WHO_FIELD_SER 32   /**< Show server. */
+#define WHO_FIELD_NIC 64   /**< Show nickname. */
+#define WHO_FIELD_FLA 128  /**< Show flags (away, oper, chanop, etc). */
+#define WHO_FIELD_DIS 256  /**< Show hop count (distance). */
+#define WHO_FIELD_REN 512  /**< Show realname (info). */
+#define WHO_FIELD_IDL 1024 /**< Show idle time. */
+#define WHO_FIELD_ACC 2048 /**< Show account name. */
+#define WHO_FIELD_OPL 4096 /**< Show oplevel. */
+
+/** Default fields for /WHO */
+#define WHO_FIELD_DEF ( WHO_FIELD_NIC | WHO_FIELD_UID | WHO_FIELD_HOS | WHO_FIELD_SER )
+
+/** Is \a ac plainly visible to \a s?
+ * @param[in] s Client trying to see \a ac.
+ * @param[in] ac Client being looked at.
+ */
+#define IS_VISIBLE_USER(s,ac) ((s==ac) || (!IsInvisible(ac)))
+
+/** Can \a s see \a ac by using the flags in \a b?
+ * @param[in] s Client trying to see \a ac.
+ * @param[in] ac Client being looked at.
+ * @param[in] b Bitset of extra flags (options: WHOSELECT_EXTRA).
+ */
+#define SEE_LUSER(s, ac, b) (IS_VISIBLE_USER(s, ac) || \
+                             ((b & WHOSELECT_EXTRA) && MyConnect(ac) && \
+                             (HasPriv((s), PRIV_SHOW_INVIS) || \
+                              HasPriv((s), PRIV_SHOW_ALL_INVIS))))
+
+/** Can \a s see \a ac by using the flags in \a b?
+ * @param[in] s Client trying to see \a ac.
+ * @param[in] ac Client being looked at.
+ * @param[in] b Bitset of extra flags (options: WHOSELECT_EXTRA).
+ */
+#define SEE_USER(s, ac, b) (SEE_LUSER(s, ac, b) || \
+                            ((b & WHOSELECT_EXTRA) && \
+                              HasPriv((s), PRIV_SHOW_ALL_INVIS)))
+
+/** Should we show more clients to \a sptr?
+ * @param[in] sptr Client listing other users.
+ * @param[in,out] counter Default count for clients.
+ */
+#define SHOW_MORE(sptr, counter) (HasPriv(sptr, PRIV_UNLIMIT_QUERY) || (!(counter-- < 0)) )
+
+/** Can \a s see \a chptr?
+ * @param[in] s Client trying to see \a chptr.
+ * @param[in] chptr Channel being looked at.
+ * @param[in] b Bitset of extra flags (options: WHOSELECT_EXTRA).
+ */
+#define SEE_CHANNEL(s, chptr, b) (!SecretChannel(chptr) || ((b & WHOSELECT_EXTRA) && HasPriv((s), PRIV_SEE_CHAN)))
+
+/** Maximum number of lines to send in response to a /WHOIS. */
+#define MAX_WHOIS_LINES 50
+
+/*
+ * Prototypes
+ */
+extern void do_who(struct Client* sptr, struct Client* acptr, struct Channel* repchan,
+                   int fields, char* qrt);
+
+#endif /* INCLUDED_whocmds_h */
diff --git a/include/whowas.h b/include/whowas.h
new file mode 100644 (file)
index 0000000..8e885f5
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+ * IRC - Internet Relay Chat, include/whowas.h
+ * Copyright (C) 1990 Markku Savela
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+/** @file
+ * @brief Globally visible declarations to manipulate whowas information.
+ * @version $Id: whowas.h 1229 2004-10-05 04:14:44Z entrope $
+ */
+#ifndef INCLUDED_whowas_h
+#define INCLUDED_whowas_h
+#ifndef INCLUDED_sys_types_h
+#include <sys/types.h>        /* size_t */
+#define INCLUDED_sys_types_h
+#endif
+
+struct Client;
+
+/*
+ * General defines
+ */
+
+#define BITS_PER_COL            3   /**< Magic number used by whowas hash function. */
+#define BITS_PER_COL_MASK       0x7 /**< Mask with #BITS_PER_COL least significant bits set. */
+#define WW_MAX_INITIAL          16  /**< Magic number used by whowas hash function. */
+
+#define MAX_SUB (1 << BITS_PER_COL) /**< Magic number used by whowas hash function. */
+#define WW_MAX_INITIAL_MASK (WW_MAX_INITIAL - 1) /**< Magic number used by whowas hash function. */
+#define WW_MAX (WW_MAX_INITIAL * MAX_SUB) /**< Size of whowas hash table. */
+
+/*
+ * Structures
+ */
+
+/** Tracks previously used nicknames. */
+struct Whowas {
+  unsigned int hashv;           /**< Hash value for nickname. */
+  char *name;                   /**< Client's old nickname. */
+  char *username;               /**< Client's username. */
+  char *hostname;               /**< Client's hostname. */
+  char *realhost;               /**< Client's real hostname. */
+  char *servername;             /**< Name of client's server. */
+  char *realname;               /**< Client's realname (user info). */
+  char *away;                   /**< Client's away message. */
+  time_t logoff;                /**< When the client logged off. */
+  struct Client *online;        /**< Needed for get_history() (nick chasing). */
+  struct Whowas *hnext;         /**< Next entry with the same hash value. */
+  struct Whowas **hprevnextp;   /**< Pointer to previous next pointer. */
+  struct Whowas *cnext;         /**< Next entry with the same 'online' pointer. */
+  struct Whowas **cprevnextp;   /**< Pointer to previous next pointer. */
+  struct Whowas *wnext;                /**< Next entry in whowas linked list. */
+  struct Whowas *wprev;                /**< Pointer to previous next pointer. */
+};
+
+/*
+ * Proto types
+ */
+extern struct Whowas* whowashash[];
+
+extern unsigned int hash_whowas_name(const char *name);
+
+extern struct Client *get_history(const char *nick, time_t timelimit);
+extern void add_history(struct Client *cptr, int still_on);
+extern void off_history(const struct Client *cptr);
+extern void initwhowas(void);
+extern void count_whowas_memory(int *wwu, size_t *wwm, int *wwa, size_t *wwam);
+
+extern void whowas_realloc(void);
+
+#endif /* INCLUDED_whowas_h */
diff --git a/install-sh b/install-sh
new file mode 100644 (file)
index 0000000..ebc6691
--- /dev/null
@@ -0,0 +1,250 @@
+#! /bin/sh
+#
+# install - install a program, script, or datafile
+# This comes from X11R5 (mit/util/scripts/install.sh).
+#
+# Copyright 1991 by the Massachusetts Institute of Technology
+#
+# Permission to use, copy, modify, distribute, and sell this software and its
+# documentation for any purpose is hereby granted without fee, provided that
+# the above copyright notice appear in all copies and that both that
+# copyright notice and this permission notice appear in supporting
+# documentation, and that the name of M.I.T. not be used in advertising or
+# publicity pertaining to distribution of the software without specific,
+# written prior permission.  M.I.T. makes no representations about the
+# suitability of this software for any purpose.  It is provided "as is"
+# without express or implied warranty.
+#
+# Calling this script install-sh is preferred over install.sh, to prevent
+# `make' implicit rules from creating a file called install from it
+# when there is no Makefile.
+#
+# This script is compatible with the BSD install script, but was written
+# from scratch.  It can only install one file at a time, a restriction
+# shared with many OS's install programs.
+
+
+# set DOITPROG to echo to test this script
+
+# Don't use :- since 4.3BSD and earlier shells don't like it.
+doit="${DOITPROG-}"
+
+
+# put in absolute paths if you don't have them in your path; or use env. vars.
+
+mvprog="${MVPROG-mv}"
+cpprog="${CPPROG-cp}"
+chmodprog="${CHMODPROG-chmod}"
+chownprog="${CHOWNPROG-chown}"
+chgrpprog="${CHGRPPROG-chgrp}"
+stripprog="${STRIPPROG-strip}"
+rmprog="${RMPROG-rm}"
+mkdirprog="${MKDIRPROG-mkdir}"
+
+transformbasename=""
+transform_arg=""
+instcmd="$mvprog"
+chmodcmd="$chmodprog 0755"
+chowncmd=""
+chgrpcmd=""
+stripcmd=""
+rmcmd="$rmprog -f"
+mvcmd="$mvprog"
+src=""
+dst=""
+dir_arg=""
+
+while [ x"$1" != x ]; do
+    case $1 in
+       -c) instcmd="$cpprog"
+           shift
+           continue;;
+
+       -d) dir_arg=true
+           shift
+           continue;;
+
+       -m) chmodcmd="$chmodprog $2"
+           shift
+           shift
+           continue;;
+
+       -o) chowncmd="$chownprog $2"
+           shift
+           shift
+           continue;;
+
+       -g) chgrpcmd="$chgrpprog $2"
+           shift
+           shift
+           continue;;
+
+       -s) stripcmd="$stripprog"
+           shift
+           continue;;
+
+       -t=*) transformarg=`echo $1 | sed 's/-t=//'`
+           shift
+           continue;;
+
+       -b=*) transformbasename=`echo $1 | sed 's/-b=//'`
+           shift
+           continue;;
+
+       *)  if [ x"$src" = x ]
+           then
+               src=$1
+           else
+               # this colon is to work around a 386BSD /bin/sh bug
+               :
+               dst=$1
+           fi
+           shift
+           continue;;
+    esac
+done
+
+if [ x"$src" = x ]
+then
+       echo "install:  no input file specified"
+       exit 1
+else
+       true
+fi
+
+if [ x"$dir_arg" != x ]; then
+       dst=$src
+       src=""
+       
+       if [ -d $dst ]; then
+               instcmd=:
+       else
+               instcmd=mkdir
+       fi
+else
+
+# Waiting for this to be detected by the "$instcmd $src $dsttmp" command
+# might cause directories to be created, which would be especially bad 
+# if $src (and thus $dsttmp) contains '*'.
+
+       if [ -f $src -o -d $src ]
+       then
+               true
+       else
+               echo "install:  $src does not exist"
+               exit 1
+       fi
+       
+       if [ x"$dst" = x ]
+       then
+               echo "install:  no destination specified"
+               exit 1
+       else
+               true
+       fi
+
+# If destination is a directory, append the input filename; if your system
+# does not like double slashes in filenames, you may need to add some logic
+
+       if [ -d $dst ]
+       then
+               dst="$dst"/`basename $src`
+       else
+               true
+       fi
+fi
+
+## this sed command emulates the dirname command
+dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'`
+
+# Make sure that the destination directory exists.
+#  this part is taken from Noah Friedman's mkinstalldirs script
+
+# Skip lots of stat calls in the usual case.
+if [ ! -d "$dstdir" ]; then
+defaultIFS='   
+'
+IFS="${IFS-${defaultIFS}}"
+
+oIFS="${IFS}"
+# Some sh's can't handle IFS=/ for some reason.
+IFS='%'
+set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'`
+IFS="${oIFS}"
+
+pathcomp=''
+
+while [ $# -ne 0 ] ; do
+       pathcomp="${pathcomp}${1}"
+       shift
+
+       if [ ! -d "${pathcomp}" ] ;
+        then
+               $mkdirprog "${pathcomp}"
+       else
+               true
+       fi
+
+       pathcomp="${pathcomp}/"
+done
+fi
+
+if [ x"$dir_arg" != x ]
+then
+       $doit $instcmd $dst &&
+
+       if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else true ; fi &&
+       if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else true ; fi &&
+       if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else true ; fi &&
+       if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else true ; fi
+else
+
+# If we're going to rename the final executable, determine the name now.
+
+       if [ x"$transformarg" = x ] 
+       then
+               dstfile=`basename $dst`
+       else
+               dstfile=`basename $dst $transformbasename | 
+                       sed $transformarg`$transformbasename
+       fi
+
+# don't allow the sed command to completely eliminate the filename
+
+       if [ x"$dstfile" = x ] 
+       then
+               dstfile=`basename $dst`
+       else
+               true
+       fi
+
+# Make a temp file name in the proper directory.
+
+       dsttmp=$dstdir/#inst.$$#
+
+# Move or copy the file name to the temp name
+
+       $doit $instcmd $src $dsttmp &&
+
+       trap "rm -f ${dsttmp}" 0 &&
+
+# and set any options; do chmod last to preserve setuid bits
+
+# If any of these fail, we abort the whole thing.  If we want to
+# ignore errors from any of these, just make sure not to ignore
+# errors from the above "$doit $instcmd $src $dsttmp" command.
+
+       if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else true;fi &&
+       if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else true;fi &&
+       if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else true;fi &&
+       if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else true;fi &&
+
+# Now rename the file to the real destination.
+
+       $doit $rmcmd -f $dstdir/$dstfile &&
+       $doit $mvcmd $dsttmp $dstdir/$dstfile 
+
+fi &&
+
+
+exit 0
diff --git a/ircd-patch b/ircd-patch
new file mode 100644 (file)
index 0000000..ab1e045
--- /dev/null
@@ -0,0 +1,226 @@
+#!/bin/sh
+#
+# IRC - Internet Relay Chat, ircd-patch
+# Copyright (C) 2002 Alex Badea <vampire@p16.pub.ro>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 1, or (at your option)
+# any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+# $Id: ircd-patch,v 1.5.2.1 2005/12/29 03:41:56 entrope Exp $
+#
+#
+# Experimental centralized patch system for ircu
+# Run with no arguments to get help.
+#
+# Return codes:
+#   0 - success
+#   1 - at least one live patch failed
+#   2 - at least one simulation (dry run) failed 
+#   3 - invalid arguments (i.e. no such patch)
+#   4 - invalid operation (i.e. tried to apply when already applied)
+#
+
+DIFFS=patches/diffs
+MARKS=patches/marks
+PLIST_FILE=include/patchlist.h
+
+retcode=0
+force=0
+
+
+PLIST=""
+for fname in $DIFFS/*.diff ; do
+       name=`basename $fname | sed -e 's/\.diff//'`
+       PLIST="$PLIST $name"
+done
+
+update_patchlist() {
+       list=""
+       for name in $PLIST ; do
+               test -f $MARKS/$name && list="$list.$name"
+       done
+       echo "/* This file was automatically generated by ircd-patch */" > $PLIST_FILE
+       echo "#define PATCHLIST \"$list\"" >> $PLIST_FILE
+       echo "Updated $PLIST_FILE"
+}
+
+test -d $DIFFS || (echo "*** Missing $DIFFS, creating it" ; mkdir -p $DIFFS)
+test -d $MARKS || (echo "*** Missing $MARKS, creating it" ; mkdir -p $MARKS)
+
+dry_run() {
+       rejects=`patch -p0 -N -t --dry-run $2 < $1 | grep "hunk FAILED" | sed -e 's/.*to file /  /;s/\.rej$//'`
+       test -z "$rejects"
+}
+
+patch_list() {
+       echo "Available patches (* marks applied patches):"
+       for name in $PLIST ; do
+               test -f $MARKS/$name && echo -n " * " || echo -n "   "
+               echo $name
+       done
+       echo "Done."
+}
+
+patch_test() {
+       echo "Testing patches:"
+       list="$*"
+       test "z$list" = "z" && list=$PLIST
+       for name in $list ; do
+               fname=$DIFFS/$name.diff
+               echo -ne "  $name\t"
+               if test ! -f $MARKS/$name ; then
+                       if dry_run "$fname" ; then
+                               echo -n " OK"
+                       else
+                               echo -n " PATCH FAILED"
+                               retcode=2
+                       fi
+               else
+                       echo -n " APPLIED"
+                       if dry_run "$fname" -R ; then
+                               echo -n " OK"
+                       else
+                               echo -n " REVERSE FAILED"
+                               retcode=2
+                       fi
+               fi
+               echo
+       done
+       echo "Done."
+}
+
+patch_add() {
+       name=$1
+       fname="$DIFFS/$name.diff"
+       if test ! -f $fname ; then
+               echo "Patch $name ($fname) does not exist"
+               retcode=3
+               return
+       fi
+
+       if test $force -lt 2 -a -f $MARKS/$name ; then
+               echo "Patch $name seems already applied"
+               retcode=4
+               return
+       fi
+
+       if test $force -lt 1 ; then
+               echo -n "Testing $fname... "
+               if ! dry_run $fname ; then
+                       echo "Failed (use -f to force)."
+                       echo "The following files failed patching:"
+                       echo "$rejects"
+                       retcode=2
+                       return
+               fi
+               echo "seems ok."
+       fi
+
+       echo "Applying $fname..."
+       if patch -p0 -N -t < $fname ; then
+               touch $MARKS/$name
+               echo "Done."
+       else
+               echo "Failed."
+               retcode=1
+       fi
+}
+
+patch_del() {
+       name=$1
+       fname="$DIFFS/$name.diff"
+       if test ! -f $fname ; then
+               echo "Patch $name ($fname) does not exist"
+               retcode=3
+               return
+       fi
+
+       if test $force -lt 2 -a ! -f $MARKS/$name ; then
+               echo "Patch $name doesn't seem to be applied"
+               retcode=4
+               return
+       fi
+
+       if test $force -lt 1 ; then
+               echo -n "Testing $fname... "
+               if ! dry_run $fname -R ; then
+                       echo "Failed (use -f to force)."
+                       echo "The following files failed patching:"
+                       echo "$rejects"
+                       retcode=2
+                       return
+               fi
+               echo "seems ok."
+       fi
+       
+       echo "Reversing $fname..."
+       if patch -p0 -R -t < $fname ; then
+               rm -f $MARKS/$name
+               echo "Done."
+       else
+               echo "Failed."
+               retcode=1
+       fi
+}
+
+do_help() {
+       echo "Usage: $0 [-f [-f]] [args]"
+       echo "Arguments may be:"
+       echo "  help                Prints this help"
+       echo "  list                List available patches"
+       echo "  test [patch list]   Tests whether patches can be (un)applied correctly"
+       echo "  add  <patch list>   Applies a patch"
+       echo "  del  <patch list>   Reverses a patch"
+       echo "  update              Updates $PLIST_FILE with the currently applied patches"
+       echo "The -f option forces patching even if a dry run fails (effective on 'add'"
+       echo "and 'del' commands only). Using it twice will also skip checking whether"
+       echo "a patch is already applied."
+}
+
+while test "$1" = "-f" ; do
+       force=`expr $force + 1`
+       shift
+done
+
+case "$1" in
+       add)
+               shift
+               for name in $* ; do
+                       patch_add $name
+               done
+               update_patchlist
+               ;;
+       del)
+               shift
+               for name in $* ; do
+                       patch_del $name
+               done
+               update_patchlist
+               ;;
+       test)
+               shift
+               patch_test $*
+               ;;
+       list)
+               patch_list
+               ;;
+       update)
+               update_patchlist
+               ;;
+       *)
+               do_help
+               ;;
+esac
+
+exit $retcode
diff --git a/ircd/IPcheck.c b/ircd/IPcheck.c
new file mode 100644 (file)
index 0000000..863d394
--- /dev/null
@@ -0,0 +1,564 @@
+/*
+ * IRC - Internet Relay Chat, ircd/IPcheck.c
+ * Copyright (C) 1998 Carlo Wood ( Run @ undernet.org )
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+/** @file
+ * @brief Code to count users connected from particular IP addresses.
+ * @version $Id: IPcheck.c 1456 2005-08-15 23:22:50Z entrope $
+ */
+#include "config.h"
+
+#include "IPcheck.h"
+#include "client.h"
+#include "ircd.h"
+#include "match.h"
+#include "msg.h"
+#include "ircd_alloc.h"
+#include "ircd_events.h"
+#include "ircd_features.h"
+#include "ircd_log.h"
+#include "ircd_string.h"    /* ircd_ntoa */
+#include "s_debug.h"        /* Debug */
+#include "s_user.h"         /* TARGET_DELAY */
+#include "send.h"
+
+/* #include <assert.h> -- Now using assert in ircd_log.h */
+#include <string.h>
+
+/** Stores free target information for a particular user. */
+struct IPTargetEntry {
+  unsigned int  count; /**< Number of free targets targets. */
+  unsigned char targets[MAXTARGETS]; /**< Array of recent targets. */
+};
+
+/** Stores recent information about a particular IP address. */
+struct IPRegistryEntry {
+  struct IPRegistryEntry*  next;   /**< Next entry in the hash chain. */
+  struct IPTargetEntry*    target; /**< Recent targets, if any. */
+  struct irc_in_addr       addr;   /**< IP address for this user. */
+  int                     last_connect; /**< Last connection attempt timestamp. */
+  unsigned short           connected; /**< Number of currently connected clients. */
+  unsigned char            attempts; /**< Number of recent connection attempts. */
+};
+
+/** Size of hash table (must be a power of two). */
+#define IP_REGISTRY_TABLE_SIZE 0x10000
+/** Report current time for tracking in IPRegistryEntry::last_connect. */
+#define NOW ((unsigned short)(CurrentTime & 0xffff))
+/** Time from \a x until now, in seconds. */
+#define CONNECTED_SINCE(x) (NOW - (x))
+
+/** Macro for easy access to configured IPcheck clone limit. */
+#define IPCHECK_CLONE_LIMIT feature_int(FEAT_IPCHECK_CLONE_LIMIT)
+/** Macro for easy access to configured IPcheck clone period. */
+#define IPCHECK_CLONE_PERIOD feature_int(FEAT_IPCHECK_CLONE_PERIOD)
+/** Macro for easy access to configured IPcheck clone delay. */
+#define IPCHECK_CLONE_DELAY feature_int(FEAT_IPCHECK_CLONE_DELAY)
+
+/** Hash table for storing IPRegistryEntry entries. */
+static struct IPRegistryEntry* hashTable[IP_REGISTRY_TABLE_SIZE];
+/** List of allocated but unused IPRegistryEntry structs. */
+static struct IPRegistryEntry* freeList;
+/** Periodic timer to look for too-old registry entries. */
+static struct Timer expireTimer;
+
+/** Convert IP addresses to canonical form for comparison.  IPv4
+ * addresses are translated into 6to4 form; IPv6 addresses are left
+ * alone.
+ * @param[out] out Receives canonical format for address.
+ * @param[in] in IP address to canonicalize.
+ */
+static void ip_registry_canonicalize(struct irc_in_addr *out, const struct irc_in_addr *in)
+{
+    if (irc_in_addr_is_ipv4(in)) {
+        out->in6_16[0] = htons(0x2002);
+        out->in6_16[1] = in->in6_16[6];
+        out->in6_16[2] = in->in6_16[7];
+        out->in6_16[3] = out->in6_16[4] = out->in6_16[5] = 0;
+        out->in6_16[6] = out->in6_16[7] = 0;
+    } else
+        memcpy(out, in, sizeof(*out));
+}
+
+/** Calculate hash value for an IP address.
+ * @param[in] ip Address to hash; must be in canonical form.
+ * @return Hash value for address.
+ */
+static unsigned int ip_registry_hash(const struct irc_in_addr *ip)
+{
+  unsigned int res;
+  /* Only use the first 64 bits of address, since the last 64 bits
+   * tend to be under user control. */
+  res = ip->in6_16[0] ^ ip->in6_16[1] ^ ip->in6_16[2] ^ ip->in6_16[3];
+  return res & (IP_REGISTRY_TABLE_SIZE - 1);
+}
+
+/** Find an IP registry entry if one exists for the IP address.
+ * If \a ip looks like an IPv6 address, only consider the first 64 bits
+ * of the address. Otherwise, only consider the final 32 bits.
+ * @param[in] ip IP address to search for.
+ * @return Matching registry entry, or NULL if none exists.
+ */
+static struct IPRegistryEntry* ip_registry_find(const struct irc_in_addr *ip)
+{
+  struct irc_in_addr canon;
+  struct IPRegistryEntry* entry;
+  ip_registry_canonicalize(&canon, ip);
+  entry = hashTable[ip_registry_hash(&canon)];
+  for ( ; entry; entry = entry->next) {
+    int bits = (canon.in6_16[0] == htons(0x2002)) ? 48 : 64;
+    if (ipmask_check(&canon, &entry->addr, bits))
+      break;
+  }
+  return entry;
+}
+
+/** Add an IP registry entry to the hash table.
+ * @param[in] entry Registry entry to add.
+ */
+static void ip_registry_add(struct IPRegistryEntry* entry)
+{
+  unsigned int bucket = ip_registry_hash(&entry->addr);
+  entry->next = hashTable[bucket];
+  hashTable[bucket] = entry;
+}
+
+/** Remove an IP registry entry from the hash table.
+ * @param[in] entry Registry entry to add.
+ */
+static void ip_registry_remove(struct IPRegistryEntry* entry)
+{
+  unsigned int bucket = ip_registry_hash(&entry->addr);
+  if (hashTable[bucket] == entry)
+    hashTable[bucket] = entry->next;
+  else {
+    struct IPRegistryEntry* prev = hashTable[bucket];
+    for ( ; prev; prev = prev->next) {
+      if (prev->next == entry) {
+        prev->next = entry->next;
+        break;
+      }
+    }
+  }
+}
+
+/** Allocate a new IP registry entry.
+ * For members that have a sensible default value, that is used.
+ * @return Newly allocated registry entry.
+ */
+static struct IPRegistryEntry* ip_registry_new_entry(void)
+{
+  struct IPRegistryEntry* entry = freeList;
+  if (entry)
+    freeList = entry->next;
+  else
+    entry = (struct IPRegistryEntry*) MyMalloc(sizeof(struct IPRegistryEntry));
+
+  assert(0 != entry);
+  memset(entry, 0, sizeof(struct IPRegistryEntry));
+  entry->last_connect = NOW;     /* Seconds since last connect attempt */
+  entry->connected    = 1;       /* connected clients for this IP */
+  entry->attempts     = 1;       /* Number attempts for this IP */
+  return entry;
+}
+
+/** Deallocate memory for \a entry.
+ * The entry itself is prepended to #freeList.
+ * @param[in] entry IP registry entry to release.
+ */
+static void ip_registry_delete_entry(struct IPRegistryEntry* entry)
+{
+  if (entry->target)
+    MyFree(entry->target);
+  entry->next = freeList;
+  freeList = entry;
+}
+
+/** Update free target count for \a entry.
+ * @param[in,out] entry IP registry entry to update.
+ */
+static unsigned int ip_registry_update_free_targets(struct IPRegistryEntry* entry)
+{
+  unsigned int free_targets = STARTTARGETS;
+
+  if (entry->target) {
+    free_targets = entry->target->count + (CONNECTED_SINCE(entry->last_connect) / TARGET_DELAY);
+    if (free_targets > STARTTARGETS)
+      free_targets = STARTTARGETS;
+    entry->target->count = free_targets;
+  }
+  return free_targets;
+}
+
+/** Check whether all or part of \a entry needs to be expired.
+ * If the entry is at least 600 seconds stale, free the entire thing.
+ * If it is at least 120 seconds stale, expire its free targets list.
+ * @param[in] entry Registry entry to check for expiration.
+ */
+static void ip_registry_expire_entry(struct IPRegistryEntry* entry)
+{
+  /*
+   * Don't touch this number, it has statistical significance
+   * XXX - blah blah blah
+   */
+  if (CONNECTED_SINCE(entry->last_connect) > 600) {
+    /*
+     * expired
+     */
+    Debug((DEBUG_DNS, "IPcheck expiring registry for %s (no clients connected).", ircd_ntoa(&entry->addr)));
+    ip_registry_remove(entry);
+    ip_registry_delete_entry(entry);
+  }
+  else if (CONNECTED_SINCE(entry->last_connect) > 120 && 0 != entry->target) {
+    /*
+     * Expire storage of targets
+     */
+    MyFree(entry->target);
+    entry->target = 0;
+  }
+}
+
+/** Periodic timer callback to check for expired registry entries.
+ * @param[in] ev Timer event (ignored).
+ */
+static void ip_registry_expire(struct Event* ev)
+{
+  int i;
+  struct IPRegistryEntry* entry;
+  struct IPRegistryEntry* entry_next;
+
+  assert(ET_EXPIRE == ev_type(ev));
+  assert(0 != ev_timer(ev));
+
+  for (i = 0; i < IP_REGISTRY_TABLE_SIZE; ++i) {
+    for (entry = hashTable[i]; entry; entry = entry_next) {
+      entry_next = entry->next;
+      if (0 == entry->connected)
+        ip_registry_expire_entry(entry);
+    }
+  }
+}
+
+/** Initialize the IPcheck subsystem. */
+void IPcheck_init(void)
+{
+  timer_add(timer_init(&expireTimer), ip_registry_expire, 0, TT_PERIODIC, 60);
+}
+
+/** Check whether a new connection from a local client should be allowed.
+ * A connection is rejected if someone from the "same" address (see
+ * ip_registry_find()) connects IPCHECK_CLONE_LIMIT times, each time
+ * separated by no more than IPCHECK_CLONE_PERIOD seconds.
+ * @param[in] addr Address of client.
+ * @param[out] next_target_out Receives time to grant another free target.
+ * @return Non-zero if the connection is permitted, zero if denied.
+ */
+int ip_registry_check_local(const struct irc_in_addr *addr, time_t* next_target_out)
+{
+  struct IPRegistryEntry* entry = ip_registry_find(addr);
+  unsigned int free_targets = STARTTARGETS;
+
+  if (0 == entry) {
+    entry       = ip_registry_new_entry();
+    ip_registry_canonicalize(&entry->addr, addr);
+    ip_registry_add(entry);
+    Debug((DEBUG_DNS, "IPcheck added new registry for local connection from %s.", ircd_ntoa(&entry->addr)));
+    return 1;
+  }
+  /* Note that this also counts server connects.
+   * It is hard and not interesting, to change that.
+   * Refuse connection if it would overflow the counter.
+   */
+  if (0 == ++entry->connected)
+  {
+    entry->connected--;
+    Debug((DEBUG_DNS, "IPcheck refusing local connection from %s: counter overflow.", ircd_ntoa(&entry->addr)));
+    return 0;
+  }
+
+  if (CONNECTED_SINCE(entry->last_connect) > IPCHECK_CLONE_PERIOD)
+    entry->attempts = 0;
+
+  free_targets = ip_registry_update_free_targets(entry);
+  entry->last_connect = NOW;
+
+  if (0 == ++entry->attempts)   /* Check for overflow */
+    --entry->attempts;
+
+  if (entry->attempts < IPCHECK_CLONE_LIMIT) {
+    if (next_target_out)
+      *next_target_out = CurrentTime - (TARGET_DELAY * free_targets - 1);
+  }
+  else if ((CurrentTime - cli_since(&me)) > IPCHECK_CLONE_DELAY) {
+    /*
+     * Don't refuse connection when we just rebooted the server
+     */
+#ifndef NOTHROTTLE
+    assert(entry->connected > 0);
+    --entry->connected;
+    Debug((DEBUG_DNS, "IPcheck refusing local connection from %s: too fast.", ircd_ntoa(&entry->addr)));
+    return 0;
+#endif
+  }
+  Debug((DEBUG_DNS, "IPcheck accepting local connection from %s.", ircd_ntoa(&entry->addr)));
+  return 1;
+}
+
+/** Check whether a connection from a remote client should be allowed.
+ * This is much more relaxed than ip_registry_check_local(): The only
+ * cause for rejection is when the IPRegistryEntry::connected counter
+ * would overflow.
+ * @param[in] cptr Client that has connected.
+ * @param[in] is_burst Non-zero if client was introduced during a burst.
+ * @return Non-zero if the client should be accepted, zero if they must be killed.
+ */
+int ip_registry_check_remote(struct Client* cptr, int is_burst)
+{
+  struct IPRegistryEntry* entry;
+
+  /*
+   * Mark that we did add/update an IPregistry entry
+   */
+  SetIPChecked(cptr);
+  if (!irc_in_addr_valid(&cli_ip(cptr))) {
+    Debug((DEBUG_DNS, "IPcheck accepting remote connection from invalid %s.", ircd_ntoa(&cli_ip(cptr))));
+    return 1;
+  }
+  entry = ip_registry_find(&cli_ip(cptr));
+  if (0 == entry) {
+    entry = ip_registry_new_entry();
+    ip_registry_canonicalize(&entry->addr, &cli_ip(cptr));
+    if (is_burst)
+      entry->attempts = 0;
+    ip_registry_add(entry);
+    Debug((DEBUG_DNS, "IPcheck added new registry for remote connection from %s.", ircd_ntoa(&entry->addr)));
+    return 1;
+  }
+  /* Avoid overflowing the connection counter. */
+  if (0 == ++entry->connected) {
+    Debug((DEBUG_DNS, "IPcheck refusing remote connection from %s: counter overflow.", ircd_ntoa(&entry->addr)));
+    return 0;
+  }
+  if (CONNECTED_SINCE(entry->last_connect) > IPCHECK_CLONE_PERIOD)
+    entry->attempts = 0;
+  if (!is_burst) {
+    if (0 == ++entry->attempts) {
+      /*
+       * Check for overflow
+       */
+      --entry->attempts;
+    }
+    ip_registry_update_free_targets(entry);
+    entry->last_connect = NOW;
+  }
+  Debug((DEBUG_DNS, "IPcheck counting remote connection from %s.", ircd_ntoa(&entry->addr)));
+  return 1;
+}
+
+/** Handle a client being rejected during connection through no fault
+ * of their own.  This "undoes" the effect of ip_registry_check_local()
+ * so the client's address is not penalized for the failure.
+ * @param[in] addr Address of rejected client.
+ */
+void ip_registry_connect_fail(const struct irc_in_addr *addr)
+{
+  struct IPRegistryEntry* entry = ip_registry_find(addr);
+  if (entry && 0 == --entry->attempts) {
+    Debug((DEBUG_DNS, "IPcheck noting local connection failure for %s.", ircd_ntoa(&entry->addr)));
+    ++entry->attempts;
+  }
+}
+
+/** Handle a client that has successfully connected.
+ * This copies free target information to \a cptr from his address's
+ * registry entry and sends him a NOTICE describing the parameters for
+ * the entry.
+ * @param[in,out] cptr Client that has successfully connected.
+ */
+void ip_registry_connect_succeeded(struct Client *cptr)
+{
+  const char*             tr    = "";
+  unsigned int free_targets     = STARTTARGETS;
+  struct IPRegistryEntry* entry = ip_registry_find(&cli_ip(cptr));
+
+  assert(entry);
+  if (entry->target) {
+    memcpy(cli_targets(cptr), entry->target->targets, MAXTARGETS);
+    free_targets = entry->target->count;
+    tr = " tr";
+  }
+  Debug((DEBUG_DNS, "IPcheck noting local connection success for %s.", ircd_ntoa(&entry->addr)));
+  sendcmdto_one(&me, CMD_NOTICE, cptr, "%C :on %u ca %u(%u) ft %u(%u)%s",
+               cptr, entry->connected, entry->attempts, IPCHECK_CLONE_LIMIT,
+               free_targets, STARTTARGETS, tr);
+}
+
+/** Handle a client that decided to disconnect (or was killed after
+ * completing his connection).  This updates the free target
+ * information for his IP registry entry.
+ * @param[in] cptr Client that has exited.
+ */
+void ip_registry_disconnect(struct Client *cptr)
+{
+  struct IPRegistryEntry* entry = ip_registry_find(&cli_ip(cptr));
+  if (!irc_in_addr_valid(&cli_ip(cptr))) {
+    Debug((DEBUG_DNS, "IPcheck noting dicconnect from invalid %s.", ircd_ntoa(&cli_ip(cptr))));
+    return;
+  }
+  assert(entry);
+  assert(entry->connected > 0);
+  Debug((DEBUG_DNS, "IPcheck noting disconnect from %s.", ircd_ntoa(&entry->addr)));
+  /*
+   * If this was the last one, set `last_connect' to disconnect time (used for expiration)
+   */
+  if (0 == --entry->connected) {
+    if (CONNECTED_SINCE(entry->last_connect) > IPCHECK_CLONE_LIMIT * IPCHECK_CLONE_PERIOD) {
+      /*
+       * Otherwise we'd penalize for this old value if the client reconnects within 20 seconds
+       */
+      entry->attempts = 0;
+    }
+    ip_registry_update_free_targets(entry);
+    entry->last_connect = NOW;
+  }
+  if (MyConnect(cptr)) {
+    unsigned int free_targets;
+    /*
+     * Copy the clients targets
+     */
+    if (0 == entry->target) {
+      entry->target = (struct IPTargetEntry*) MyMalloc(sizeof(struct IPTargetEntry));
+      entry->target->count = STARTTARGETS;
+    }
+    assert(0 != entry->target);
+
+    memcpy(entry->target->targets, cli_targets(cptr), MAXTARGETS);
+    /*
+     * This calculation can be pretty unfair towards large multi-user hosts, but
+     * there is "nothing" we can do without also allowing spam bots to send more
+     * messages or by drastically increasing the amount of memory used in the IPregistry.
+     *
+     * The problem is that when a client disconnects, leaving no free targets, then
+     * the next client from that IP number has to pay for it (getting no free targets).
+     * But ALSO the next client, and the next client, and the next client etc - until
+     * another client disconnects that DOES leave free targets.  The reason for this
+     * is that if there are 10 SPAM bots, and they all disconnect at once, then they
+     * ALL should get no free targets when reconnecting.  We'd need to store an entry
+     * per client (instead of per IP number) to avoid this.
+     */
+    if (cli_nexttarget(cptr) < CurrentTime) {
+        /*
+         * Number of free targets
+         */
+      free_targets = (CurrentTime - cli_nexttarget(cptr)) / TARGET_DELAY + 1;
+    }
+    else
+      free_targets = 0;
+    /*
+     * Add bonus, this is pretty fuzzy, but it will help in some cases.
+     */
+    if ((CurrentTime - cli_firsttime(cptr)) > 600)
+      /*
+       * Was longer then 10 minutes online?
+       */
+      free_targets += (CurrentTime - cli_firsttime(cptr) - 600) / TARGET_DELAY;
+    /*
+     * Finally, store smallest value for Judgment Day
+     */
+    if (free_targets < entry->target->count)
+      entry->target->count = free_targets;
+  }
+}
+
+/** Find number of clients from a particular IP address.
+ * @param[in] addr Address to look up.
+ * @return Number of clients known to be connected from that address.
+ */
+int ip_registry_count(const struct irc_in_addr *addr)
+{
+  struct IPRegistryEntry* entry = ip_registry_find(addr);
+  return (entry) ? entry->connected : 0;
+}
+
+/** Check whether a client is allowed to connect locally.
+ * @param[in] a Address of client.
+ * @param[out] next_target_out Receives time to grant another free target.
+ * @return Non-zero if the connection is permitted, zero if denied.
+ */
+int IPcheck_local_connect(const struct irc_in_addr *a, time_t* next_target_out)
+{
+  assert(0 != next_target_out);
+  return ip_registry_check_local(a, next_target_out);
+}
+
+/** Check whether a client is allowed to connect remotely.
+ * @param[in] cptr Client that has connected.
+ * @param[in] is_burst Non-zero if client was introduced during a burst.
+ * @return Non-zero if the client should be accepted, zero if they must be killed.
+ */
+int IPcheck_remote_connect(struct Client *cptr, int is_burst)
+{
+  assert(0 != cptr);
+  assert(!IsIPChecked(cptr));
+  return ip_registry_check_remote(cptr, is_burst);
+}
+
+/** Handle a client being rejected during connection through no fault
+ * of their own.  This "undoes" the effect of ip_registry_check_local()
+ * so the client's address is not penalized for the failure.
+ * @param[in] cptr Client who has been rejected.
+ */
+void IPcheck_connect_fail(const struct Client *cptr)
+{
+  assert(IsIPChecked(cptr));
+  ip_registry_connect_fail(&cli_ip(cptr));
+}
+
+/** Handle a client that has successfully connected.
+ * This copies free target information to \a cptr from his address's
+ * registry entry and sends him a NOTICE describing the parameters for
+ * the entry.
+ * @param[in,out] cptr Client that has successfully connected.
+ */
+void IPcheck_connect_succeeded(struct Client *cptr)
+{
+  assert(0 != cptr);
+  assert(IsIPChecked(cptr));
+  ip_registry_connect_succeeded(cptr);
+}
+
+/** Handle a client that decided to disconnect (or was killed after
+ * completing his connection).  This updates the free target
+ * information for his IP registry entry.
+ * @param[in] cptr Client that has exited.
+ */
+void IPcheck_disconnect(struct Client *cptr)
+{
+  assert(0 != cptr);
+  assert(IsIPChecked(cptr));
+  ip_registry_disconnect(cptr);
+}
+
+/** Find number of clones of a client.
+ * @param[in] cptr Client whose address to look up.
+ * @return Number of clients known to be connected from that address.
+ */
+unsigned short IPcheck_nr(struct Client *cptr)
+{
+  assert(0 != cptr);
+  return ip_registry_count(&cli_ip(cptr));
+}
diff --git a/ircd/Makefile.in b/ircd/Makefile.in
new file mode 100644 (file)
index 0000000..a4888a5
--- /dev/null
@@ -0,0 +1,1517 @@
+# ircd/Makefile for the Undernet IRC Daemon.
+# Copyright (C) 1990 Jarkko Oikarinen
+# Copyright (C) 1997 Carlo Wood
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+# 02111-1307, USA.
+
+#### Start of system configuration section. ####
+
+# Output variables of the 'configure' script:
+
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+top_srcdir = @top_srcdir@
+srcdir = @srcdir@
+VPATH = @srcdir@
+DEFS = @DEFS@
+INSTALL = @INSTALL@
+SHELL = @SHPROG@
+RM = @RMPROG@
+AWK = @AWK@
+LN_S = @LN_S@
+MV = mv
+CHMOD = chmod
+CHOWN = chown
+CHGRP = chgrp
+MKDIR = mkdir
+TOUCH = touch
+GREP = grep
+LEX = @LEX@
+YACC = @YACC@
+ENGINE_C = @ENGINE_C@
+@SET_MAKE@
+
+BINDIR = @bindir@
+INSTALL_RULE = @INSTALL_RULE@
+SYMLINK = @SYMLINK@
+IRCDMODE = @IRCDMODE@
+IRCDOWN = @IRCDOWN@
+IRCDGRP = @IRCDGRP@
+DPATH = @DPATH@
+MPATH = ${DPATH}/ircd.motd
+RPATH = ${DPATH}/remote.motd
+
+CC = @CC@
+CFLAGS = @CFLAGS@
+CPPFLAGS = -I. -I.. -I${top_srcdir}/include @CPPFLAGS@
+LDFLAGS = @LDFLAGS@
+LIBS = @LIBS@
+
+#### End of system configuration section. ####
+PURIFY =
+RINGLOG_O =
+
+ENGINE_SRC = \
+       engine_devpoll.c \
+       engine_poll.c \
+       engine_kqueue.c \
+       engine_select.c
+
+CRYPTO_SRC = \
+       ircd_md5.c \
+       ircd_crypt_plain.c \
+       ircd_crypt_smd5.c \
+       ircd_crypt_native.c
+
+UMKPASSWD_SRC = ${CRYPTO_SRC} \
+       ircd_alloc.c \
+       ircd_string.c \
+       memdebug.c \
+       umkpasswd.c
+
+IRCD_SRC = \
+       IPcheck.c \
+       channel.c \
+       class.c \
+       client.c \
+       crule.c \
+       dbuf.c \
+       destruct_event.c \
+       fileio.c \
+       gline.c \
+       hash.c \
+       ircd.c \
+       ircd_alloc.c \
+       ircd_crypt.c \
+       ircd_events.c \
+       ircd_features.c \
+       ircd_log.c \
+       ircd_relay.c \
+       ircd_reply.c \
+       ircd_res.c \
+       ircd_reslib.c \
+       ircd_signal.c \
+       ircd_snprintf.c \
+       ircd_string.c \
+       jupe.c \
+       lex.yy.c \
+       list.c \
+       listener.c \
+       m_account.c \
+       m_admin.c \
+       m_asll.c \
+       m_away.c \
+       m_burst.c \
+       m_cap.c \
+       m_check.c \
+       m_clearmode.c \
+       m_close.c \
+       m_connect.c \
+       m_cprivmsg.c \
+       m_create.c \
+       m_defaults.c \
+       m_destruct.c \
+       m_desynch.c \
+       m_die.c \
+       m_endburst.c \
+       m_error.c \
+       m_fakehost.c \
+       m_get.c \
+       m_gline.c \
+       m_help.c \
+       m_hidehost.c \
+       m_info.c \
+       m_invite.c \
+       m_ison.c \
+       m_join.c \
+       m_jupe.c \
+       m_kick.c \
+       m_kill.c \
+       m_links.c \
+       m_list.c \
+       m_lusers.c \
+       m_map.c \
+       m_mode.c \
+       m_motd.c \
+       m_names.c \
+       m_nick.c \
+       m_notice.c \
+       m_oper.c \
+       m_opmode.c \
+       m_part.c \
+       m_pass.c \
+       m_ping.c \
+       m_pong.c \
+       m_privmsg.c \
+       m_privs.c \
+       m_proto.c \
+       m_pseudo.c \
+       m_quit.c \
+       m_rehash.c \
+       m_relay.c \
+       m_reset.c \
+       m_restart.c \
+       m_rping.c \
+       m_rpong.c \
+       m_server.c \
+       m_set.c \
+       m_settime.c \
+       m_silence.c \
+       m_squit.c \
+       m_stats.c \
+       m_svsmode.c \
+       m_svsnick.c \
+       m_svsjoin.c \
+       m_time.c \
+       m_topic.c \
+       m_trace.c \
+       m_uping.c \
+       m_user.c \
+       m_userhost.c \
+       m_userip.c \
+       m_version.c \
+       m_wallchops.c \
+       m_wallops.c \
+       m_wallusers.c \
+       m_wallvoices.c \
+       m_webirc.c \
+       m_who.c \
+       m_whois.c \
+       m_whowas.c \
+       match.c \
+       memdebug.c \
+       motd.c \
+       msgq.c \
+       numnicks.c \
+       opercmds.c \
+       os_generic.c \
+       packet.c \
+       parse.c \
+       querycmds.c \
+       random.c \
+       s_auth.c \
+       s_bsd.c \
+       s_conf.c \
+       s_debug.c \
+       s_err.c \
+       s_misc.c \
+       s_numeric.c \
+       s_serv.c \
+       s_stats.c \
+       s_user.c \
+       send.c \
+       ssl.c \
+       uping.c \
+       userload.c \
+       whocmds.c \
+       whowas.c \
+       y.tab.c
+
+SRC = ${IRCD_SRC} ${ENGINE_C} ${CRYPTO_SRC}
+
+OBJS = ${SRC:%.c=%.o}
+
+UMKPASSWD_OBJS = ${UMKPASSWD_SRC:%.c=%.o}
+
+DEP_SRC = ${IRCD_SRC} ${ENGINE_SRC} ${CRYPTO_SRC}
+
+all:
+       ( cd ..; make -f Makefile )
+
+.SUFFIXES: .c .o
+
+.c.o:
+       ${CC} ${CFLAGS} ${CPPFLAGS} -c $< -o $@
+
+build: ircd
+
+ircd: ${OBJS} ../include/patchlevel.h version.o
+       ${PURIFY} ${CC} ${OBJS} version.o ${RINGLOG_O} ${LDFLAGS} ${LIBS} \
+               -o ircd
+       ${CHMOD} ${IRCDMODE} ircd
+
+.PHONY: version.c
+version.c: version.c.SH umkpasswd
+       ${SHELL} ${srcdir}/version.c.SH ${top_srcdir}
+
+ircd_string.o: ircd_string.c chattr.tab.c
+
+table_gen: table_gen.o
+       ${CC} ${LDFLAGS} -o $@ table_gen.o
+
+chattr.tab.c: table_gen
+       ./table_gen > chattr.tab.c
+
+lex.yy.c: ircd_lexer.l y.tab.h
+       ${LEX} ${srcdir}/ircd_lexer.l
+
+y.tab.c y.tab.h: ircd_parser.y
+       ${YACC} -d ${srcdir}/ircd_parser.y
+
+umkpasswd: ${UMKPASSWD_OBJS}
+       ${CC} ${LDFLAGS} ${UMKPASSWD_OBJS} ${LIBS} -o $@
+
+mkbindir:
+       @test -d ${BINDIR} || mkdir ${BINDIR}
+
+install: ${INSTALL_RULE}
+
+install-with-symlink: build mkbindir
+       @if [ ! -d ${DPATH} -a ! -f ${DPATH} ]; then \
+         echo "Creating directory ${DPATH}"; \
+         ${MKDIR} ${DPATH}; \
+         ${CHMOD} 700 ${DPATH}; \
+         ${CHOWN} ${IRCDOWN} ${DPATH}; \
+         ${CHGRP} ${IRCDGRP} ${DPATH}; \
+       fi
+       @echo `date +%Y%m%d%H%M` > /tmp/ircd.tag;
+       @echo "Installing new ircd as ${BINDIR}/ircd.`cat /tmp/ircd.tag` :"
+       ${INSTALL} -m ${IRCDMODE} -o ${IRCDOWN} -g ${IRCDGRP} ircd ${BINDIR}/ircd.`cat /tmp/ircd.tag`
+       @( cd ${BINDIR}; \
+         ${RM} -f ${SYMLINK}; \
+         ${LN_S} ircd.`cat /tmp/ircd.tag` ${SYMLINK}; )
+       @${RM} /tmp/ircd.tag
+       ${INSTALL} -s -m 700 -o ${IRCDOWN} -g ${IRCDGRP} umkpasswd ${BINDIR}
+       ${INSTALL} -m 600 -o ${IRCDOWN} -g ${IRCDGRP} ${top_srcdir}/doc/example.conf ${DPATH}
+
+install-no-symlink: build mkbindir
+       @if [ ! -d ${DPATH} -a ! -f ${DPATH} ]; then \
+         echo "Creating directory ${DPATH}"; \
+         ${MKDIR} ${DPATH}; \
+         ${CHMOD} 700 ${DPATH}; \
+         ${CHOWN} ${IRCDOWN} ${DPATH}; \
+         ${CHGRP} ${IRCDGRP} ${DPATH}; \
+       fi
+       @echo "Installing new ircd as ${BINDIR}/ircd :"
+       ${INSTALL} -m ${IRCDMODE} -o ${IRCDOWN} -g ${IRCDGRP} ircd ${BINDIR}/ircd
+       ${INSTALL} -s -m 700 -o ${IRCDOWN} -g ${IRCDGRP} umkpasswd ${BINDIR}
+       ${INSTALL} -m 600 -o ${IRCDOWN} -g ${IRCDGRP} ${top_srcdir}/doc/example.conf ${DPATH}
+
+uninstall:
+       @if [ "${BINDIR}" != "${DPATH}" ]; then \
+               echo "${RM} -f ${BINDIR}/${SYMLINK} ${BINDIR}/ircd.9*"; \
+               ${RM} -f ${BINDIR}/${SYMLINK} ${BINDIR}/ircd.9*; \
+       fi
+       @echo "Please remove the contents of ${DPATH} manually"
+
+clean:
+       ${RM} -f *.o *.bak ircd umkpasswd chattr.tab.c table_gen y.tab.* lex.yy.*
+
+distclean: clean
+       ${RM} -f Makefile stamp-m
+
+maintainer-clean: distclean
+
+# If I read this right, this will only work with gcc.  Still, how many admins
+# are going to be doing "make depend"?
+depend: ${DEP_SRC} chattr.tab.c
+       @cd ${srcdir}; \
+       if [ -f Makefile.in.bak ]; then \
+         echo "make depend: First remove ircd/Makefile.in.bak"; \
+       else \
+         ( ${MV} Makefile.in Makefile.in.bak; \
+           ${GREP} -A1 -B10000 '^# DO NOT DELETE THIS LINE' Makefile.in.bak > Makefile.in;\
+           ${CC} ${CFLAGS} -MM ${CPPFLAGS} ${DEP_SRC} >> Makefile.in; ) \
+       fi
+
+# DO NOT DELETE THIS LINE (or the blank line after it) -- make depend depends on them.
+
+IPcheck.o: IPcheck.c ../config.h ../include/IPcheck.h ../include/client.h \
+  ../include/ircd_defs.h ../include/dbuf.h ../include/msgq.h \
+  ../include/ircd_events.h ../config.h ../include/ircd_handler.h \
+  ../include/res.h ../include/capab.h ../include/ircd.h \
+  ../include/struct.h ../include/match.h ../include/msg.h \
+  ../include/ircd_alloc.h ../include/ircd_events.h \
+  ../include/ircd_features.h ../include/ircd_log.h \
+  ../include/ircd_string.h ../include/ircd_chattr.h ../include/s_debug.h \
+  ../include/s_user.h ../include/send.h
+channel.o: channel.c ../config.h ../include/channel.h \
+  ../include/ircd_defs.h ../include/res.h ../config.h ../include/client.h \
+  ../include/dbuf.h ../include/msgq.h ../include/ircd_events.h \
+  ../include/ircd_handler.h ../include/capab.h \
+  ../include/destruct_event.h ../include/hash.h ../include/ircd.h \
+  ../include/struct.h ../include/ircd_alloc.h ../include/ircd_chattr.h \
+  ../include/ircd_defs.h ../include/ircd_features.h ../include/ircd_log.h \
+  ../include/ircd_reply.h ../include/ircd_snprintf.h \
+  ../include/ircd_string.h ../include/list.h ../include/match.h \
+  ../include/msg.h ../include/msgq.h ../include/numeric.h \
+  ../include/numnicks.h ../include/querycmds.h ../include/ircd_features.h \
+  ../include/s_bsd.h ../include/s_conf.h ../include/client.h \
+  ../include/s_debug.h ../include/s_misc.h ../include/s_user.h \
+  ../include/send.h ../include/struct.h ../include/sys.h \
+  ../include/whowas.h
+class.o: class.c ../config.h ../include/class.h ../include/client.h \
+  ../include/ircd_defs.h ../include/dbuf.h ../include/msgq.h \
+  ../include/ircd_events.h ../config.h ../include/ircd_handler.h \
+  ../include/res.h ../include/capab.h ../include/client.h \
+  ../include/ircd.h ../include/struct.h ../include/ircd_alloc.h \
+  ../include/ircd_features.h ../include/ircd_log.h \
+  ../include/ircd_reply.h ../include/ircd_string.h \
+  ../include/ircd_chattr.h ../include/list.h ../include/numeric.h \
+  ../include/s_conf.h ../include/s_debug.h ../include/send.h
+client.o: client.c ../config.h ../include/client.h ../include/ircd_defs.h \
+  ../include/dbuf.h ../include/msgq.h ../include/ircd_events.h \
+  ../config.h ../include/ircd_handler.h ../include/res.h \
+  ../include/capab.h ../include/class.h ../include/client.h \
+  ../include/ircd.h ../include/struct.h ../include/ircd_features.h \
+  ../include/ircd_log.h ../include/ircd_reply.h ../include/list.h \
+  ../include/msgq.h ../include/numeric.h ../include/s_conf.h \
+  ../include/s_debug.h ../include/send.h ../include/struct.h
+crule.o: crule.c ../config.h ../include/crule.h ../include/client.h \
+  ../include/ircd_defs.h ../include/dbuf.h ../include/msgq.h \
+  ../include/ircd_events.h ../config.h ../include/ircd_handler.h \
+  ../include/res.h ../include/capab.h ../include/ircd.h \
+  ../include/struct.h ../include/ircd_alloc.h ../include/ircd_chattr.h \
+  ../include/ircd_string.h ../include/match.h ../include/s_bsd.h \
+  ../include/s_debug.h ../include/struct.h
+dbuf.o: dbuf.c ../config.h ../include/dbuf.h ../include/ircd_alloc.h \
+  ../include/ircd_chattr.h ../include/ircd_features.h \
+  ../include/ircd_log.h ../include/send.h ../include/sys.h
+destruct_event.o: destruct_event.c ../config.h ../include/channel.h \
+  ../include/ircd_defs.h ../include/res.h ../config.h \
+  ../include/s_debug.h ../include/ircd_alloc.h ../include/ircd.h \
+  ../include/struct.h ../include/ircd_events.h ../include/ircd_log.h \
+  ../include/send.h ../include/msg.h ../include/ircd_handler.h
+fileio.o: fileio.c ../config.h ../include/fileio.h \
+  ../include/ircd_alloc.h ../include/ircd_log.h
+gline.o: gline.c ../config.h ../include/gline.h ../include/res.h \
+  ../config.h ../include/client.h ../include/ircd_defs.h \
+  ../include/dbuf.h ../include/msgq.h ../include/ircd_events.h \
+  ../include/ircd_handler.h ../include/capab.h ../include/ircd.h \
+  ../include/struct.h ../include/ircd_alloc.h ../include/ircd_features.h \
+  ../include/ircd_log.h ../include/ircd_reply.h \
+  ../include/ircd_snprintf.h ../include/ircd_string.h \
+  ../include/ircd_chattr.h ../include/match.h ../include/numeric.h \
+  ../include/s_bsd.h ../include/s_debug.h ../include/s_misc.h \
+  ../include/s_stats.h ../include/send.h ../include/struct.h \
+  ../include/msg.h ../include/numnicks.h ../include/whocmds.h \
+  ../include/hash.h ../include/channel.h
+hash.o: hash.c ../config.h ../include/hash.h ../include/client.h \
+  ../include/ircd_defs.h ../include/dbuf.h ../include/msgq.h \
+  ../include/ircd_events.h ../config.h ../include/ircd_handler.h \
+  ../include/res.h ../include/capab.h ../include/channel.h \
+  ../include/ircd_alloc.h ../include/ircd_chattr.h ../include/ircd_log.h \
+  ../include/ircd_reply.h ../include/ircd_string.h ../include/ircd.h \
+  ../include/struct.h ../include/match.h ../include/msg.h \
+  ../include/numeric.h ../include/random.h ../include/send.h \
+  ../include/struct.h ../include/sys.h
+ircd.o: ircd.c ../config.h ../include/ircd.h ../include/struct.h \
+  ../include/ircd_defs.h ../include/IPcheck.h ../include/class.h \
+  ../include/client.h ../include/dbuf.h ../include/msgq.h \
+  ../include/ircd_events.h ../config.h ../include/ircd_handler.h \
+  ../include/res.h ../include/capab.h ../include/client.h \
+  ../include/crule.h ../include/destruct_event.h ../include/channel.h \
+  ../include/hash.h ../include/ircd_alloc.h ../include/ircd_events.h \
+  ../include/ircd_features.h ../include/ircd_log.h \
+  ../include/ircd_reply.h ../include/ircd_signal.h \
+  ../include/ircd_string.h ../include/ircd_chattr.h \
+  ../include/ircd_crypt.h ../include/jupe.h ../include/list.h \
+  ../include/match.h ../include/motd.h ../include/msg.h \
+  ../include/numeric.h ../include/numnicks.h ../include/opercmds.h \
+  ../include/parse.h ../include/res.h ../include/s_auth.h \
+  ../include/s_bsd.h ../include/s_conf.h ../include/s_debug.h \
+  ../include/s_misc.h ../include/s_stats.h ../include/send.h \
+  ../include/sys.h ../include/uping.h ../include/userload.h \
+  ../include/version.h ../include/whowas.h
+ircd_alloc.o: ircd_alloc.c ../config.h ../include/ircd_alloc.h \
+  ../include/ircd_log.h ../include/ircd_string.h ../include/ircd_chattr.h \
+  ../include/s_debug.h ../config.h ../include/ircd_defs.h
+ircd_crypt.o: ircd_crypt.c ../config.h ../include/ircd_crypt.h \
+  ../include/ircd_alloc.h ../include/ircd_features.h \
+  ../include/ircd_log.h ../include/ircd_string.h ../include/ircd_chattr.h \
+  ../include/s_debug.h ../config.h ../include/ircd_defs.h \
+  ../include/ircd_crypt_native.h ../include/ircd_crypt_plain.h \
+  ../include/ircd_crypt_smd5.h
+ircd_events.o: ircd_events.c ../config.h ../include/ircd_events.h \
+  ../config.h ../include/ircd.h ../include/struct.h \
+  ../include/ircd_defs.h ../include/ircd_alloc.h ../include/ircd_log.h \
+  ../include/ircd_snprintf.h ../include/s_debug.h
+ircd_features.o: ircd_features.c ../config.h ../include/ircd_features.h \
+  ../include/channel.h ../include/ircd_defs.h ../include/res.h \
+  ../config.h ../include/class.h ../include/client.h ../include/dbuf.h \
+  ../include/msgq.h ../include/ircd_events.h ../include/ircd_handler.h \
+  ../include/capab.h ../include/client.h ../include/hash.h \
+  ../include/ircd.h ../include/struct.h ../include/ircd_alloc.h \
+  ../include/ircd_log.h ../include/ircd_reply.h ../include/ircd_string.h \
+  ../include/ircd_chattr.h ../include/match.h ../include/motd.h \
+  ../include/msg.h ../include/numeric.h ../include/numnicks.h \
+  ../include/random.h ../include/s_bsd.h ../include/s_debug.h \
+  ../include/s_misc.h ../include/send.h ../include/struct.h \
+  ../include/sys.h ../include/whowas.h
+ircd_log.o: ircd_log.c ../config.h ../include/ircd_log.h \
+  ../include/client.h ../include/ircd_defs.h ../include/dbuf.h \
+  ../include/msgq.h ../include/ircd_events.h ../config.h \
+  ../include/ircd_handler.h ../include/res.h ../include/capab.h \
+  ../include/ircd_alloc.h ../include/ircd_reply.h \
+  ../include/ircd_snprintf.h ../include/ircd_string.h \
+  ../include/ircd_chattr.h ../include/ircd.h ../include/struct.h \
+  ../include/numeric.h ../include/s_debug.h ../include/send.h \
+  ../include/struct.h
+ircd_relay.o: ircd_relay.c ../config.h ../include/ircd_relay.h \
+  ../include/channel.h ../include/ircd_defs.h ../include/res.h \
+  ../config.h ../include/client.h ../include/dbuf.h ../include/msgq.h \
+  ../include/ircd_events.h ../include/ircd_handler.h ../include/capab.h \
+  ../include/hash.h ../include/ircd.h ../include/struct.h \
+  ../include/ircd_chattr.h ../include/ircd_features.h \
+  ../include/ircd_log.h ../include/ircd_reply.h ../include/ircd_string.h \
+  ../include/match.h ../include/msg.h ../include/numeric.h \
+  ../include/numnicks.h ../include/s_debug.h ../include/s_misc.h \
+  ../include/s_user.h ../include/send.h
+ircd_reply.o: ircd_reply.c ../config.h ../include/ircd_reply.h \
+  ../include/client.h ../include/ircd_defs.h ../include/dbuf.h \
+  ../include/msgq.h ../include/ircd_events.h ../config.h \
+  ../include/ircd_handler.h ../include/res.h ../include/capab.h \
+  ../include/ircd.h ../include/struct.h ../include/ircd_log.h \
+  ../include/ircd_snprintf.h ../include/msg.h ../include/msgq.h \
+  ../include/numeric.h ../include/s_conf.h ../include/client.h \
+  ../include/s_debug.h ../include/send.h
+ircd_res.o: ircd_res.c ../include/client.h ../include/ircd_defs.h \
+  ../include/dbuf.h ../include/msgq.h ../include/ircd_events.h \
+  ../config.h ../include/ircd_handler.h ../include/res.h \
+  ../include/capab.h ../include/ircd_alloc.h ../include/ircd_log.h \
+  ../include/ircd_osdep.h ../include/ircd_reply.h \
+  ../include/ircd_string.h ../include/ircd_chattr.h \
+  ../include/ircd_snprintf.h ../include/ircd.h ../include/struct.h \
+  ../include/numeric.h ../include/fileio.h ../include/random.h \
+  ../include/s_bsd.h ../include/s_debug.h ../include/s_stats.h \
+  ../include/ircd_features.h ../include/send.h ../include/sys.h \
+  ../include/res.h ../include/ircd_reslib.h
+ircd_reslib.o: ircd_reslib.c ../include/ircd.h ../include/struct.h \
+  ../include/ircd_defs.h ../include/res.h ../config.h \
+  ../include/ircd_reslib.h ../include/ircd_defs.h ../include/fileio.h \
+  ../include/ircd_string.h ../include/ircd_chattr.h
+ircd_signal.o: ircd_signal.c ../config.h ../include/ircd.h \
+  ../include/struct.h ../include/ircd_defs.h ../include/ircd_alloc.h \
+  ../include/ircd_events.h ../config.h ../include/ircd_log.h \
+  ../include/ircd_signal.h ../include/s_conf.h ../include/client.h \
+  ../include/dbuf.h ../include/msgq.h ../include/ircd_handler.h \
+  ../include/res.h ../include/capab.h
+ircd_snprintf.o: ircd_snprintf.c ../config.h ../include/client.h \
+  ../include/ircd_defs.h ../include/dbuf.h ../include/msgq.h \
+  ../include/ircd_events.h ../config.h ../include/ircd_handler.h \
+  ../include/res.h ../include/capab.h ../include/channel.h \
+  ../include/ircd_log.h ../include/ircd_snprintf.h ../include/struct.h
+ircd_string.o: ircd_string.c ../config.h ../include/ircd_string.h \
+  ../include/ircd_chattr.h ../include/ircd_defs.h \
+  ../include/ircd_chattr.h ../include/ircd_log.h ../include/res.h \
+  ../config.h chattr.tab.c
+jupe.o: jupe.c ../config.h ../include/jupe.h ../include/client.h \
+  ../include/ircd_defs.h ../include/dbuf.h ../include/msgq.h \
+  ../include/ircd_events.h ../config.h ../include/ircd_handler.h \
+  ../include/res.h ../include/capab.h ../include/hash.h ../include/ircd.h \
+  ../include/struct.h ../include/ircd_alloc.h ../include/ircd_features.h \
+  ../include/ircd_log.h ../include/ircd_reply.h ../include/ircd_string.h \
+  ../include/ircd_chattr.h ../include/match.h ../include/msg.h \
+  ../include/numeric.h ../include/numnicks.h ../include/s_bsd.h \
+  ../include/s_misc.h ../include/send.h ../include/struct.h \
+  ../include/sys.h
+lex.yy.o: lex.yy.c ../config.h ../include/ircd.h ../include/struct.h \
+  ../include/ircd_defs.h ../include/ircd_alloc.h ../include/ircd_string.h \
+  ../include/ircd_chattr.h ../include/s_debug.h ../config.h y.tab.h
+list.o: list.c ../config.h ../include/list.h ../include/client.h \
+  ../include/ircd_defs.h ../include/dbuf.h ../include/msgq.h \
+  ../include/ircd_events.h ../config.h ../include/ircd_handler.h \
+  ../include/res.h ../include/capab.h ../include/ircd.h \
+  ../include/struct.h ../include/ircd_alloc.h ../include/ircd_events.h \
+  ../include/ircd_log.h ../include/ircd_reply.h ../include/ircd_string.h \
+  ../include/ircd_chattr.h ../include/listener.h ../include/match.h \
+  ../include/numeric.h ../include/res.h ../include/s_auth.h \
+  ../include/s_bsd.h ../include/s_conf.h ../include/client.h \
+  ../include/s_debug.h ../include/s_misc.h ../include/s_user.h \
+  ../include/send.h ../include/struct.h ../include/whowas.h
+listener.o: listener.c ../config.h ../include/listener.h \
+  ../include/ircd_defs.h ../include/ircd_events.h ../config.h \
+  ../include/res.h ../include/client.h ../include/dbuf.h \
+  ../include/msgq.h ../include/ircd_handler.h ../include/capab.h \
+  ../include/ircd.h ../include/struct.h ../include/ircd_alloc.h \
+  ../include/ircd_events.h ../include/ircd_features.h \
+  ../include/ircd_log.h ../include/ircd_osdep.h ../include/ircd_reply.h \
+  ../include/ircd_snprintf.h ../include/ircd_string.h \
+  ../include/ircd_chattr.h ../include/match.h ../include/numeric.h \
+  ../include/s_bsd.h ../include/s_conf.h ../include/client.h \
+  ../include/s_misc.h ../include/s_stats.h ../include/send.h \
+  ../include/sys.h
+m_account.o: m_account.c ../config.h ../include/client.h \
+  ../include/ircd_defs.h ../include/dbuf.h ../include/msgq.h \
+  ../include/ircd_events.h ../config.h ../include/ircd_handler.h \
+  ../include/res.h ../include/capab.h ../include/ircd.h \
+  ../include/struct.h ../include/ircd_log.h ../include/ircd_reply.h \
+  ../include/ircd_string.h ../include/ircd_chattr.h ../include/msg.h \
+  ../include/numnicks.h ../include/s_debug.h ../include/s_user.h \
+  ../include/send.h
+m_admin.o: m_admin.c ../config.h ../include/client.h \
+  ../include/ircd_defs.h ../include/dbuf.h ../include/msgq.h \
+  ../include/ircd_events.h ../config.h ../include/ircd_handler.h \
+  ../include/res.h ../include/capab.h ../include/hash.h ../include/ircd.h \
+  ../include/struct.h ../include/ircd_features.h ../include/ircd_log.h \
+  ../include/ircd_reply.h ../include/msg.h ../include/numeric.h \
+  ../include/numnicks.h ../include/s_conf.h ../include/client.h \
+  ../include/s_user.h
+m_asll.o: m_asll.c ../config.h ../include/client.h ../include/ircd_defs.h \
+  ../include/dbuf.h ../include/msgq.h ../include/ircd_events.h \
+  ../config.h ../include/ircd_handler.h ../include/res.h \
+  ../include/capab.h ../include/hash.h ../include/ircd.h \
+  ../include/struct.h ../include/ircd_log.h ../include/ircd_reply.h \
+  ../include/ircd_string.h ../include/ircd_chattr.h ../include/numeric.h \
+  ../include/numnicks.h ../include/match.h ../include/msg.h \
+  ../include/send.h ../include/s_bsd.h ../include/s_user.h
+m_away.o: m_away.c ../config.h ../include/client.h ../include/ircd_defs.h \
+  ../include/dbuf.h ../include/msgq.h ../include/ircd_events.h \
+  ../config.h ../include/ircd_handler.h ../include/res.h \
+  ../include/capab.h ../include/ircd.h ../include/struct.h \
+  ../include/ircd_alloc.h ../include/ircd_log.h ../include/ircd_reply.h \
+  ../include/ircd_string.h ../include/ircd_chattr.h ../include/msg.h \
+  ../include/numeric.h ../include/numnicks.h ../include/s_user.h \
+  ../include/send.h
+m_burst.o: m_burst.c ../config.h ../include/channel.h \
+  ../include/ircd_defs.h ../include/res.h ../config.h ../include/client.h \
+  ../include/dbuf.h ../include/msgq.h ../include/ircd_events.h \
+  ../include/ircd_handler.h ../include/capab.h ../include/hash.h \
+  ../include/ircd.h ../include/struct.h ../include/ircd_alloc.h \
+  ../include/ircd_features.h ../include/ircd_log.h \
+  ../include/ircd_reply.h ../include/ircd_string.h \
+  ../include/ircd_chattr.h ../include/list.h ../include/match.h \
+  ../include/msg.h ../include/numeric.h ../include/numnicks.h \
+  ../include/s_conf.h ../include/client.h ../include/s_misc.h \
+  ../include/send.h ../include/struct.h ../include/ircd_snprintf.h
+m_cap.o: m_cap.c ../config.h ../include/client.h ../include/ircd_defs.h \
+  ../include/dbuf.h ../include/msgq.h ../include/ircd_events.h \
+  ../config.h ../include/ircd_handler.h ../include/res.h \
+  ../include/capab.h ../include/ircd.h ../include/struct.h \
+  ../include/ircd_chattr.h ../include/ircd_log.h ../include/ircd_reply.h \
+  ../include/ircd_snprintf.h ../include/ircd_string.h ../include/msg.h \
+  ../include/numeric.h ../include/send.h ../include/s_auth.h \
+  ../include/s_user.h
+m_clearmode.o: m_clearmode.c ../config.h ../include/client.h \
+  ../include/ircd_defs.h ../include/dbuf.h ../include/msgq.h \
+  ../include/ircd_events.h ../config.h ../include/ircd_handler.h \
+  ../include/res.h ../include/capab.h ../include/channel.h \
+  ../include/hash.h ../include/ircd.h ../include/struct.h \
+  ../include/ircd_alloc.h ../include/ircd_features.h \
+  ../include/ircd_log.h ../include/ircd_reply.h ../include/ircd_string.h \
+  ../include/ircd_chattr.h ../include/list.h ../include/msg.h \
+  ../include/numeric.h ../include/numnicks.h ../include/s_conf.h \
+  ../include/client.h ../include/send.h
+m_close.o: m_close.c ../config.h ../include/client.h \
+  ../include/ircd_defs.h ../include/dbuf.h ../include/msgq.h \
+  ../include/ircd_events.h ../config.h ../include/ircd_handler.h \
+  ../include/res.h ../include/capab.h ../include/ircd.h \
+  ../include/struct.h ../include/ircd_log.h ../include/ircd_reply.h \
+  ../include/numeric.h ../include/s_bsd.h ../include/send.h
+m_connect.o: m_connect.c ../config.h ../include/client.h \
+  ../include/ircd_defs.h ../include/dbuf.h ../include/msgq.h \
+  ../include/ircd_events.h ../config.h ../include/ircd_handler.h \
+  ../include/res.h ../include/capab.h ../include/crule.h \
+  ../include/hash.h ../include/ircd.h ../include/struct.h \
+  ../include/ircd_features.h ../include/ircd_log.h \
+  ../include/ircd_reply.h ../include/ircd_string.h \
+  ../include/ircd_chattr.h ../include/jupe.h ../include/match.h \
+  ../include/msg.h ../include/numeric.h ../include/numnicks.h \
+  ../include/s_bsd.h ../include/s_conf.h ../include/client.h \
+  ../include/s_user.h ../include/send.h
+m_cprivmsg.o: m_cprivmsg.c ../config.h ../include/client.h \
+  ../include/ircd_defs.h ../include/dbuf.h ../include/msgq.h \
+  ../include/ircd_events.h ../config.h ../include/ircd_handler.h \
+  ../include/res.h ../include/capab.h ../include/ircd_log.h \
+  ../include/ircd_reply.h ../include/ircd_string.h \
+  ../include/ircd_chattr.h ../include/s_user.h
+m_create.o: m_create.c ../config.h ../include/channel.h \
+  ../include/ircd_defs.h ../include/res.h ../config.h ../include/client.h \
+  ../include/dbuf.h ../include/msgq.h ../include/ircd_events.h \
+  ../include/ircd_handler.h ../include/capab.h ../include/hash.h \
+  ../include/ircd.h ../include/struct.h ../include/ircd_log.h \
+  ../include/ircd_reply.h ../include/ircd_string.h \
+  ../include/ircd_chattr.h ../include/msg.h ../include/numeric.h \
+  ../include/numnicks.h ../include/s_debug.h ../include/s_misc.h \
+  ../include/s_user.h ../include/send.h
+m_defaults.o: m_defaults.c ../config.h ../include/client.h \
+  ../include/ircd_defs.h ../include/dbuf.h ../include/msgq.h \
+  ../include/ircd_events.h ../config.h ../include/ircd_handler.h \
+  ../include/res.h ../include/capab.h ../include/ircd.h \
+  ../include/struct.h ../include/ircd_log.h ../include/ircd_reply.h \
+  ../include/numeric.h ../include/numnicks.h ../include/send.h \
+  ../include/supported.h ../include/channel.h ../include/version.h
+m_destruct.o: m_destruct.c ../config.h ../include/client.h \
+  ../include/ircd_defs.h ../include/dbuf.h ../include/msgq.h \
+  ../include/ircd_events.h ../config.h ../include/ircd_handler.h \
+  ../include/res.h ../include/capab.h ../include/hash.h ../include/ircd.h \
+  ../include/struct.h ../include/ircd_log.h ../include/ircd_reply.h \
+  ../include/ircd_string.h ../include/ircd_chattr.h ../include/msg.h \
+  ../include/numeric.h ../include/numnicks.h ../include/send.h \
+  ../include/channel.h ../include/destruct_event.h
+m_desynch.o: m_desynch.c ../config.h ../include/client.h \
+  ../include/ircd_defs.h ../include/dbuf.h ../include/msgq.h \
+  ../include/ircd_events.h ../config.h ../include/ircd_handler.h \
+  ../include/res.h ../include/capab.h ../include/hash.h ../include/ircd.h \
+  ../include/struct.h ../include/ircd_log.h ../include/ircd_reply.h \
+  ../include/ircd_string.h ../include/ircd_chattr.h ../include/msg.h \
+  ../include/numeric.h ../include/numnicks.h ../include/s_bsd.h \
+  ../include/send.h
+m_die.o: m_die.c ../config.h ../include/client.h ../include/ircd_defs.h \
+  ../include/dbuf.h ../include/msgq.h ../include/ircd_events.h \
+  ../config.h ../include/ircd_handler.h ../include/res.h \
+  ../include/capab.h ../include/ircd.h ../include/struct.h \
+  ../include/ircd_log.h ../include/ircd_reply.h ../include/ircd_string.h \
+  ../include/ircd_chattr.h ../include/msg.h ../include/numeric.h \
+  ../include/numnicks.h ../include/s_bsd.h ../include/send.h
+m_endburst.o: m_endburst.c ../config.h ../include/channel.h \
+  ../include/ircd_defs.h ../include/res.h ../config.h ../include/client.h \
+  ../include/dbuf.h ../include/msgq.h ../include/ircd_events.h \
+  ../include/ircd_handler.h ../include/capab.h ../include/hash.h \
+  ../include/ircd.h ../include/struct.h ../include/ircd_log.h \
+  ../include/ircd_reply.h ../include/ircd_string.h \
+  ../include/ircd_chattr.h ../include/msg.h ../include/numeric.h \
+  ../include/numnicks.h ../include/send.h
+m_error.o: m_error.c ../config.h ../include/client.h \
+  ../include/ircd_defs.h ../include/dbuf.h ../include/msgq.h \
+  ../include/ircd_events.h ../config.h ../include/ircd_handler.h \
+  ../include/res.h ../include/capab.h ../include/hash.h ../include/ircd.h \
+  ../include/struct.h ../include/ircd_alloc.h ../include/ircd_log.h \
+  ../include/ircd_reply.h ../include/ircd_string.h \
+  ../include/ircd_chattr.h ../include/numeric.h ../include/numnicks.h \
+  ../include/s_debug.h ../include/s_misc.h ../include/send.h
+m_fakehost.o: m_fakehost.c ../config.h ../include/client.h \
+  ../include/ircd_defs.h ../include/dbuf.h ../include/msgq.h \
+  ../include/ircd_events.h ../include/ircd_handler.h ../include/hash.h \
+  ../include/ircd.h ../include/struct.h ../include/ircd_reply.h \
+  ../include/ircd_string.h ../include/ircd_chattr.h ../include/msg.h \
+  ../include/numeric.h ../include/numnicks.h ../include/s_conf.h \
+  ../include/s_user.h ../include/send.h
+m_get.o: m_get.c ../config.h ../include/client.h ../include/ircd_defs.h \
+  ../include/dbuf.h ../include/msgq.h ../include/ircd_events.h \
+  ../config.h ../include/ircd_handler.h ../include/res.h \
+  ../include/capab.h ../include/hash.h ../include/ircd.h \
+  ../include/struct.h ../include/ircd_features.h ../include/ircd_log.h \
+  ../include/ircd_reply.h ../include/ircd_string.h \
+  ../include/ircd_chattr.h ../include/numeric.h ../include/numnicks.h \
+  ../include/send.h
+m_gline.o: m_gline.c ../config.h ../include/client.h \
+  ../include/ircd_defs.h ../include/dbuf.h ../include/msgq.h \
+  ../include/ircd_events.h ../config.h ../include/ircd_handler.h \
+  ../include/res.h ../include/capab.h ../include/gline.h \
+  ../include/hash.h ../include/ircd.h ../include/struct.h \
+  ../include/ircd_features.h ../include/ircd_log.h \
+  ../include/ircd_reply.h ../include/ircd_string.h \
+  ../include/ircd_chattr.h ../include/match.h ../include/msg.h \
+  ../include/numeric.h ../include/numnicks.h ../include/s_conf.h \
+  ../include/client.h ../include/s_misc.h ../include/send.h
+m_help.o: m_help.c ../config.h ../include/client.h ../include/ircd_defs.h \
+  ../include/dbuf.h ../include/msgq.h ../include/ircd_events.h \
+  ../config.h ../include/ircd_handler.h ../include/res.h \
+  ../include/capab.h ../include/hash.h ../include/ircd.h \
+  ../include/struct.h ../include/ircd_log.h ../include/ircd_reply.h \
+  ../include/ircd_string.h ../include/ircd_chattr.h ../include/msg.h \
+  ../include/numeric.h ../include/numnicks.h ../include/send.h
+m_hidehost.o: m_hidehost.c ../config.h ../include/client.h \
+  ../include/ircd_defs.h ../include/handlers.h \
+  ../include/hash.h ../include/ircd.h \
+  ../include/ircd_features.h ../include/ircd_log.h \
+  ../include/ircd_reply.h ../include/ircd_string.h \
+  ../include/match.h ../include/msg.h \
+  ../include/numeric.h ../include/numnicks.h ../include/s_conf.h \
+  ../include/s_misc.h ../include/s_user.h ../include/send.h \
+  ../include/sys.h
+m_info.o: m_info.c ../config.h ../include/client.h ../include/ircd_defs.h \
+  ../include/dbuf.h ../include/msgq.h ../include/ircd_events.h \
+  ../config.h ../include/ircd_handler.h ../include/res.h \
+  ../include/capab.h ../include/ircd.h ../include/struct.h \
+  ../include/ircd_log.h ../include/ircd_reply.h ../include/ircd_string.h \
+  ../include/ircd_chattr.h ../include/msg.h ../include/numeric.h \
+  ../include/numnicks.h ../include/s_misc.h ../include/s_user.h \
+  ../include/s_conf.h ../include/client.h ../include/send.h \
+  ../include/version.h
+m_invite.o: m_invite.c ../config.h ../include/channel.h \
+  ../include/ircd_defs.h ../include/res.h ../config.h ../include/client.h \
+  ../include/dbuf.h ../include/msgq.h ../include/ircd_events.h \
+  ../include/ircd_handler.h ../include/capab.h ../include/hash.h \
+  ../include/ircd.h ../include/struct.h ../include/ircd_features.h \
+  ../include/ircd_log.h ../include/ircd_reply.h ../include/ircd_string.h \
+  ../include/ircd_chattr.h ../include/list.h ../include/msg.h \
+  ../include/numeric.h ../include/numnicks.h ../include/s_user.h \
+  ../include/send.h ../include/struct.h
+m_ison.o: m_ison.c ../config.h ../include/client.h ../include/ircd_defs.h \
+  ../include/dbuf.h ../include/msgq.h ../include/ircd_events.h \
+  ../config.h ../include/ircd_handler.h ../include/res.h \
+  ../include/capab.h ../include/hash.h ../include/ircd.h \
+  ../include/struct.h ../include/ircd_log.h ../include/ircd_reply.h \
+  ../include/ircd_string.h ../include/ircd_chattr.h ../include/msgq.h \
+  ../include/numeric.h ../include/send.h
+m_join.o: m_join.c ../config.h ../include/channel.h \
+  ../include/ircd_defs.h ../include/res.h ../config.h ../include/client.h \
+  ../include/dbuf.h ../include/msgq.h ../include/ircd_events.h \
+  ../include/ircd_handler.h ../include/capab.h ../include/gline.h \
+  ../include/hash.h ../include/ircd.h ../include/struct.h \
+  ../include/ircd_chattr.h ../include/ircd_features.h \
+  ../include/ircd_log.h ../include/ircd_reply.h ../include/ircd_string.h \
+  ../include/msg.h ../include/numeric.h ../include/numnicks.h \
+  ../include/s_debug.h ../include/s_user.h ../include/send.h \
+  ../include/sys.h
+m_jupe.o: m_jupe.c ../config.h ../include/client.h ../include/ircd_defs.h \
+  ../include/dbuf.h ../include/msgq.h ../include/ircd_events.h \
+  ../config.h ../include/ircd_handler.h ../include/res.h \
+  ../include/capab.h ../include/jupe.h ../include/hash.h \
+  ../include/ircd.h ../include/struct.h ../include/ircd_features.h \
+  ../include/ircd_log.h ../include/ircd_reply.h ../include/ircd_string.h \
+  ../include/ircd_chattr.h ../include/match.h ../include/msg.h \
+  ../include/numeric.h ../include/numnicks.h ../include/s_conf.h \
+  ../include/client.h ../include/s_misc.h ../include/send.h
+m_kick.o: m_kick.c ../config.h ../include/channel.h \
+  ../include/ircd_defs.h ../include/res.h ../config.h ../include/client.h \
+  ../include/dbuf.h ../include/msgq.h ../include/ircd_events.h \
+  ../include/ircd_handler.h ../include/capab.h ../include/hash.h \
+  ../include/ircd.h ../include/struct.h ../include/ircd_log.h \
+  ../include/ircd_reply.h ../include/ircd_string.h \
+  ../include/ircd_chattr.h ../include/msg.h ../include/numeric.h \
+  ../include/numnicks.h ../include/send.h ../include/ircd_features.h
+m_kill.o: m_kill.c ../config.h ../include/client.h ../include/ircd_defs.h \
+  ../include/dbuf.h ../include/msgq.h ../include/ircd_events.h \
+  ../config.h ../include/ircd_handler.h ../include/res.h \
+  ../include/capab.h ../include/hash.h ../include/ircd.h \
+  ../include/struct.h ../include/ircd_features.h ../include/ircd_log.h \
+  ../include/ircd_reply.h ../include/ircd_snprintf.h \
+  ../include/ircd_string.h ../include/ircd_chattr.h ../include/msg.h \
+  ../include/numeric.h ../include/numnicks.h ../include/s_misc.h \
+  ../include/send.h ../include/whowas.h
+m_links.o: m_links.c ../config.h ../include/client.h \
+  ../include/ircd_defs.h ../include/dbuf.h ../include/msgq.h \
+  ../include/ircd_events.h ../config.h ../include/ircd_handler.h \
+  ../include/res.h ../include/capab.h ../include/ircd.h \
+  ../include/struct.h ../include/ircd_defs.h ../include/ircd_features.h \
+  ../include/ircd_log.h ../include/ircd_reply.h ../include/ircd_string.h \
+  ../include/ircd_chattr.h ../include/match.h ../include/msg.h \
+  ../include/numeric.h ../include/numnicks.h ../include/s_user.h \
+  ../include/send.h ../include/struct.h
+m_list.o: m_list.c ../config.h ../include/channel.h \
+  ../include/ircd_defs.h ../include/res.h ../config.h ../include/client.h \
+  ../include/dbuf.h ../include/msgq.h ../include/ircd_events.h \
+  ../include/ircd_handler.h ../include/capab.h ../include/hash.h \
+  ../include/ircd.h ../include/struct.h ../include/ircd_alloc.h \
+  ../include/ircd_chattr.h ../include/ircd_features.h \
+  ../include/ircd_log.h ../include/ircd_reply.h ../include/ircd_string.h \
+  ../include/msg.h ../include/numeric.h ../include/numnicks.h \
+  ../include/s_bsd.h ../include/send.h
+m_lusers.o: m_lusers.c ../config.h ../include/client.h \
+  ../include/ircd_defs.h ../include/dbuf.h ../include/msgq.h \
+  ../include/ircd_events.h ../config.h ../include/ircd_handler.h \
+  ../include/res.h ../include/capab.h ../include/ircd.h \
+  ../include/struct.h ../include/ircd_features.h ../include/ircd_log.h \
+  ../include/ircd_reply.h ../include/ircd_string.h \
+  ../include/ircd_chattr.h ../include/msg.h ../include/numeric.h \
+  ../include/numnicks.h ../include/querycmds.h ../include/ircd_features.h \
+  ../include/s_user.h ../include/s_serv.h ../include/send.h
+m_map.o: m_map.c ../config.h ../include/client.h ../include/ircd_defs.h \
+  ../include/dbuf.h ../include/msgq.h ../include/ircd_events.h \
+  ../config.h ../include/ircd_handler.h ../include/res.h \
+  ../include/capab.h ../include/ircd.h ../include/struct.h \
+  ../include/ircd_defs.h ../include/ircd_features.h ../include/ircd_log.h \
+  ../include/ircd_reply.h ../include/ircd_snprintf.h \
+  ../include/ircd_string.h ../include/ircd_chattr.h ../include/list.h \
+  ../include/match.h ../include/msg.h ../include/numeric.h \
+  ../include/s_user.h ../include/s_serv.h ../include/send.h \
+  ../include/querycmds.h ../include/ircd_features.h
+m_mode.o: m_mode.c ../config.h ../include/handlers.h ../include/channel.h \
+  ../include/ircd_defs.h ../include/res.h ../config.h ../include/client.h \
+  ../include/dbuf.h ../include/msgq.h ../include/ircd_events.h \
+  ../include/ircd_handler.h ../include/capab.h ../include/hash.h \
+  ../include/ircd.h ../include/struct.h ../include/ircd_log.h \
+  ../include/ircd_reply.h ../include/ircd_string.h \
+  ../include/ircd_chattr.h ../include/msg.h ../include/numeric.h \
+  ../include/numnicks.h ../include/s_conf.h ../include/client.h \
+  ../include/s_debug.h ../include/s_user.h ../include/send.h
+m_motd.o: m_motd.c ../config.h ../include/client.h ../include/ircd_defs.h \
+  ../include/dbuf.h ../include/msgq.h ../include/ircd_events.h \
+  ../config.h ../include/ircd_handler.h ../include/res.h \
+  ../include/capab.h ../include/ircd.h ../include/struct.h \
+  ../include/ircd_features.h ../include/ircd_log.h \
+  ../include/ircd_reply.h ../include/ircd_string.h \
+  ../include/ircd_chattr.h ../include/match.h ../include/motd.h \
+  ../include/msg.h ../include/numeric.h ../include/numnicks.h \
+  ../include/s_conf.h ../include/client.h ../include/class.h \
+  ../include/s_user.h ../include/send.h
+m_names.o: m_names.c ../config.h ../include/channel.h \
+  ../include/ircd_defs.h ../include/res.h ../config.h ../include/client.h \
+  ../include/dbuf.h ../include/msgq.h ../include/ircd_events.h \
+  ../include/ircd_handler.h ../include/capab.h ../include/hash.h \
+  ../include/ircd.h ../include/struct.h ../include/ircd_log.h \
+  ../include/ircd_reply.h ../include/ircd_string.h \
+  ../include/ircd_chattr.h ../include/msg.h ../include/numeric.h \
+  ../include/numnicks.h ../include/s_user.h ../include/send.h
+m_nick.o: m_nick.c ../config.h ../include/IPcheck.h ../include/client.h \
+  ../include/ircd_defs.h ../include/dbuf.h ../include/msgq.h \
+  ../include/ircd_events.h ../config.h ../include/ircd_handler.h \
+  ../include/res.h ../include/capab.h ../include/hash.h ../include/ircd.h \
+  ../include/struct.h ../include/ircd_chattr.h ../include/ircd_features.h \
+  ../include/ircd_log.h ../include/ircd_reply.h ../include/ircd_string.h \
+  ../include/msg.h ../include/numeric.h ../include/numnicks.h \
+  ../include/s_debug.h ../include/s_misc.h ../include/s_user.h \
+  ../include/send.h ../include/sys.h
+m_notice.o: m_notice.c ../config.h ../include/client.h \
+  ../include/ircd_defs.h ../include/dbuf.h ../include/msgq.h \
+  ../include/ircd_events.h ../config.h ../include/ircd_handler.h \
+  ../include/res.h ../include/capab.h ../include/ircd_chattr.h \
+  ../include/ircd_log.h ../include/ircd_relay.h ../include/ircd_reply.h \
+  ../include/ircd_string.h ../include/match.h ../include/msg.h \
+  ../include/numeric.h ../include/send.h ../include/handlers.h
+m_oper.o: m_oper.c ../config.h ../include/client.h ../include/ircd_defs.h \
+  ../include/dbuf.h ../include/msgq.h ../include/ircd_events.h \
+  ../config.h ../include/ircd_handler.h ../include/res.h \
+  ../include/capab.h ../include/hash.h ../include/ircd.h \
+  ../include/struct.h ../include/ircd_alloc.h ../include/ircd_features.h \
+  ../include/ircd_log.h ../include/ircd_reply.h ../include/ircd_string.h \
+  ../include/ircd_chattr.h ../include/ircd_crypt.h ../include/msg.h \
+  ../include/numeric.h ../include/numnicks.h ../include/querycmds.h \
+  ../include/ircd_features.h ../include/s_conf.h ../include/client.h \
+  ../include/s_debug.h ../include/s_user.h ../include/s_misc.h \
+  ../include/send.h
+m_opmode.o: m_opmode.c ../config.h ../include/client.h \
+  ../include/ircd_defs.h ../include/dbuf.h ../include/msgq.h \
+  ../include/ircd_events.h ../config.h ../include/ircd_handler.h \
+  ../include/res.h ../include/capab.h ../include/channel.h \
+  ../include/hash.h ../include/ircd.h ../include/struct.h \
+  ../include/ircd_features.h ../include/ircd_log.h \
+  ../include/ircd_reply.h ../include/ircd_string.h \
+  ../include/ircd_chattr.h ../include/msg.h ../include/numeric.h \
+  ../include/numnicks.h ../include/send.h ../include/s_conf.h \
+  ../include/client.h
+m_part.o: m_part.c ../config.h ../include/channel.h \
+  ../include/ircd_defs.h ../include/res.h ../config.h ../include/client.h \
+  ../include/dbuf.h ../include/msgq.h ../include/ircd_events.h \
+  ../include/ircd_handler.h ../include/capab.h ../include/hash.h \
+  ../include/ircd.h ../include/struct.h ../include/ircd_log.h \
+  ../include/ircd_reply.h ../include/ircd_string.h \
+  ../include/ircd_chattr.h ../include/numeric.h ../include/numnicks.h \
+  ../include/send.h
+m_pass.o: m_pass.c ../config.h ../include/client.h ../include/ircd_defs.h \
+  ../include/dbuf.h ../include/msgq.h ../include/ircd_events.h \
+  ../config.h ../include/ircd_handler.h ../include/res.h \
+  ../include/capab.h ../include/ircd_log.h ../include/ircd_reply.h \
+  ../include/ircd_string.h ../include/ircd_chattr.h ../include/s_auth.h \
+  ../include/send.h
+m_ping.o: m_ping.c ../config.h ../include/client.h ../include/ircd_defs.h \
+  ../include/dbuf.h ../include/msgq.h ../include/ircd_events.h \
+  ../config.h ../include/ircd_handler.h ../include/res.h \
+  ../include/capab.h ../include/hash.h ../include/ircd_log.h \
+  ../include/ircd_reply.h ../include/ircd_string.h \
+  ../include/ircd_chattr.h ../include/ircd.h ../include/struct.h \
+  ../include/msg.h ../include/numeric.h ../include/numnicks.h \
+  ../include/opercmds.h ../include/s_debug.h ../include/send.h
+m_pong.o: m_pong.c ../config.h ../include/client.h ../include/ircd_defs.h \
+  ../include/dbuf.h ../include/msgq.h ../include/ircd_events.h \
+  ../config.h ../include/ircd_handler.h ../include/res.h \
+  ../include/capab.h ../include/hash.h ../include/ircd.h \
+  ../include/struct.h ../include/ircd_log.h ../include/ircd_reply.h \
+  ../include/ircd_string.h ../include/ircd_chattr.h ../include/msg.h \
+  ../include/numeric.h ../include/numnicks.h ../include/opercmds.h \
+  ../include/s_auth.h ../include/s_user.h ../include/send.h
+m_privmsg.o: m_privmsg.c ../config.h ../include/client.h \
+  ../include/ircd_defs.h ../include/dbuf.h ../include/msgq.h \
+  ../include/ircd_events.h ../config.h ../include/ircd_handler.h \
+  ../include/res.h ../include/capab.h ../include/ircd.h \
+  ../include/struct.h ../include/ircd_chattr.h ../include/ircd_features.h \
+  ../include/ircd_log.h ../include/ircd_relay.h ../include/ircd_reply.h \
+  ../include/ircd_string.h ../include/match.h ../include/msg.h \
+  ../include/numeric.h ../include/send.h
+m_privs.o: m_privs.c ../config.h ../include/client.h \
+  ../include/ircd_defs.h ../include/dbuf.h ../include/msgq.h \
+  ../include/ircd_events.h ../config.h ../include/ircd_handler.h \
+  ../include/res.h ../include/capab.h ../include/hash.h ../include/ircd.h \
+  ../include/struct.h ../include/ircd_log.h ../include/ircd_reply.h \
+  ../include/ircd_string.h ../include/ircd_chattr.h ../include/msg.h \
+  ../include/numeric.h ../include/numnicks.h ../include/send.h
+m_proto.o: m_proto.c ../config.h ../include/client.h \
+  ../include/ircd_defs.h ../include/dbuf.h ../include/msgq.h \
+  ../include/ircd_events.h ../config.h ../include/ircd_handler.h \
+  ../include/res.h ../include/capab.h ../include/ircd.h \
+  ../include/struct.h ../include/ircd_alloc.h ../include/ircd_chattr.h \
+  ../include/ircd_log.h ../include/ircd_reply.h ../include/ircd_string.h \
+  ../include/msg.h ../include/numeric.h ../include/numnicks.h \
+  ../include/s_debug.h ../include/s_misc.h ../include/send.h \
+  ../include/supported.h ../include/channel.h ../include/version.h
+m_pseudo.o: m_pseudo.c ../config.h ../include/client.h \
+  ../include/ircd_defs.h ../include/dbuf.h ../include/msgq.h \
+  ../include/ircd_events.h ../config.h ../include/ircd_handler.h \
+  ../include/res.h ../include/capab.h ../include/hash.h ../include/ircd.h \
+  ../include/struct.h ../include/ircd_features.h ../include/ircd_log.h \
+  ../include/ircd_relay.h ../include/ircd_reply.h \
+  ../include/ircd_string.h ../include/ircd_chattr.h \
+  ../include/ircd_snprintf.h ../include/msg.h ../include/numeric.h \
+  ../include/numnicks.h ../include/s_conf.h ../include/client.h \
+  ../include/s_user.h
+m_quit.o: m_quit.c ../config.h ../include/channel.h \
+  ../include/ircd_defs.h ../include/res.h ../config.h ../include/client.h \
+  ../include/dbuf.h ../include/msgq.h ../include/ircd_events.h \
+  ../include/ircd_handler.h ../include/capab.h ../include/ircd.h \
+  ../include/struct.h ../include/ircd_log.h ../include/ircd_string.h \
+  ../include/ircd_chattr.h ../include/struct.h ../include/s_misc.h \
+  ../include/ircd_reply.h
+m_rehash.o: m_rehash.c ../config.h ../include/client.h \
+  ../include/ircd_defs.h ../include/dbuf.h ../include/msgq.h \
+  ../include/ircd_events.h ../config.h ../include/ircd_handler.h \
+  ../include/res.h ../include/capab.h ../include/ircd.h \
+  ../include/struct.h ../include/ircd_log.h ../include/ircd_reply.h \
+  ../include/ircd_string.h ../include/ircd_chattr.h ../include/motd.h \
+  ../include/numeric.h ../include/s_conf.h ../include/client.h \
+  ../include/send.h
+m_relay.o: m_relay.c ../config.h ../include/IPcheck.h \
+ ../include/client.h ../include/ircd_defs.h ../include/dbuf.h \
+ ../include/msgq.h ../include/ircd_events.h ../include/ircd_handler.h \
+ ../include/hash.h ../include/ircd.h ../include/struct.h \
+ ../include/ircd_features.h ../include/ircd_chattr.h \
+ ../include/ircd_reply.h ../include/ircd_string.h ../include/msg.h \
+ ../include/numeric.h ../include/numnicks.h ../include/s_debug.h \
+ ../include/s_misc.h ../include/s_user.h ../include/send.h
+m_reset.o: m_reset.c ../config.h ../include/client.h \
+  ../include/ircd_defs.h ../include/dbuf.h ../include/msgq.h \
+  ../include/ircd_events.h ../config.h ../include/ircd_handler.h \
+  ../include/res.h ../include/capab.h ../include/hash.h ../include/ircd.h \
+  ../include/struct.h ../include/ircd_features.h ../include/ircd_log.h \
+  ../include/ircd_reply.h ../include/ircd_string.h \
+  ../include/ircd_chattr.h ../include/numeric.h ../include/numnicks.h \
+  ../include/send.h
+m_restart.o: m_restart.c ../config.h ../include/client.h \
+  ../include/ircd_defs.h ../include/dbuf.h ../include/msgq.h \
+  ../include/ircd_events.h ../config.h ../include/ircd_handler.h \
+  ../include/res.h ../include/capab.h ../include/ircd.h \
+  ../include/struct.h ../include/ircd_log.h ../include/ircd_reply.h \
+  ../include/ircd_string.h ../include/ircd_chattr.h ../include/numeric.h \
+  ../include/numnicks.h ../include/send.h ../include/msg.h
+m_rping.o: m_rping.c ../config.h ../include/client.h \
+  ../include/ircd_defs.h ../include/dbuf.h ../include/msgq.h \
+  ../include/ircd_events.h ../config.h ../include/ircd_handler.h \
+  ../include/res.h ../include/capab.h ../include/hash.h ../include/ircd.h \
+  ../include/struct.h ../include/ircd_log.h ../include/ircd_reply.h \
+  ../include/ircd_string.h ../include/ircd_chattr.h ../include/msg.h \
+  ../include/numeric.h ../include/numnicks.h ../include/opercmds.h \
+  ../include/s_user.h ../include/send.h
+m_rpong.o: m_rpong.c ../config.h ../include/client.h \
+  ../include/ircd_defs.h ../include/dbuf.h ../include/msgq.h \
+  ../include/ircd_events.h ../config.h ../include/ircd_handler.h \
+  ../include/res.h ../include/capab.h ../include/hash.h ../include/ircd.h \
+  ../include/struct.h ../include/ircd_log.h ../include/ircd_reply.h \
+  ../include/ircd_string.h ../include/ircd_chattr.h ../include/msg.h \
+  ../include/numeric.h ../include/numnicks.h ../include/opercmds.h \
+  ../include/send.h
+m_server.o: m_server.c ../config.h ../include/client.h \
+  ../include/ircd_defs.h ../include/dbuf.h ../include/msgq.h \
+  ../include/ircd_events.h ../config.h ../include/ircd_handler.h \
+  ../include/res.h ../include/capab.h ../include/hash.h ../include/ircd.h \
+  ../include/struct.h ../include/ircd_log.h ../include/ircd_features.h \
+  ../include/ircd_reply.h ../include/ircd_string.h \
+  ../include/ircd_chattr.h ../include/jupe.h ../include/list.h \
+  ../include/match.h ../include/msg.h ../include/numeric.h \
+  ../include/numnicks.h ../include/querycmds.h ../include/ircd_features.h \
+  ../include/s_bsd.h ../include/s_conf.h ../include/client.h \
+  ../include/s_debug.h ../include/s_misc.h ../include/s_serv.h \
+  ../include/send.h ../include/userload.h
+m_set.o: m_set.c ../config.h ../include/client.h ../include/ircd_defs.h \
+  ../include/dbuf.h ../include/msgq.h ../include/ircd_events.h \
+  ../config.h ../include/ircd_handler.h ../include/res.h \
+  ../include/capab.h ../include/hash.h ../include/ircd.h \
+  ../include/struct.h ../include/ircd_features.h ../include/ircd_log.h \
+  ../include/ircd_reply.h ../include/ircd_string.h \
+  ../include/ircd_chattr.h ../include/numeric.h ../include/numnicks.h \
+  ../include/send.h
+m_settime.o: m_settime.c ../config.h ../include/client.h \
+  ../include/ircd_defs.h ../include/dbuf.h ../include/msgq.h \
+  ../include/ircd_events.h ../config.h ../include/ircd_handler.h \
+  ../include/res.h ../include/capab.h ../include/hash.h ../include/ircd.h \
+  ../include/struct.h ../include/ircd_features.h ../include/ircd_log.h \
+  ../include/ircd_reply.h ../include/ircd_snprintf.h \
+  ../include/ircd_string.h ../include/ircd_chattr.h ../include/list.h \
+  ../include/msg.h ../include/numeric.h ../include/numnicks.h \
+  ../include/s_user.h ../include/send.h ../include/struct.h
+m_silence.o: m_silence.c ../config.h ../include/channel.h \
+  ../include/ircd_defs.h ../include/res.h ../config.h ../include/client.h \
+  ../include/dbuf.h ../include/msgq.h ../include/ircd_events.h \
+  ../include/ircd_handler.h ../include/capab.h ../include/hash.h \
+  ../include/ircd.h ../include/struct.h ../include/ircd_features.h \
+  ../include/ircd_log.h ../include/ircd_reply.h \
+  ../include/ircd_snprintf.h ../include/ircd_string.h \
+  ../include/ircd_chattr.h ../include/list.h ../include/msg.h \
+  ../include/numeric.h ../include/numnicks.h ../include/s_user.h \
+  ../include/send.h ../include/struct.h
+m_squit.o: m_squit.c ../config.h ../include/client.h \
+  ../include/ircd_defs.h ../include/dbuf.h ../include/msgq.h \
+  ../include/ircd_events.h ../config.h ../include/ircd_handler.h \
+  ../include/res.h ../include/capab.h ../include/hash.h ../include/ircd.h \
+  ../include/struct.h ../include/ircd_chattr.h ../include/ircd_log.h \
+  ../include/ircd_reply.h ../include/ircd_string.h ../include/numeric.h \
+  ../include/numnicks.h ../include/match.h ../include/s_debug.h \
+  ../include/s_misc.h ../include/s_user.h ../include/send.h
+m_stats.o: m_stats.c ../config.h ../include/client.h \
+  ../include/ircd_defs.h ../include/dbuf.h ../include/msgq.h \
+  ../include/ircd_events.h ../config.h ../include/ircd_handler.h \
+  ../include/res.h ../include/capab.h ../include/ircd.h \
+  ../include/struct.h ../include/ircd_features.h ../include/ircd_log.h \
+  ../include/ircd_reply.h ../include/ircd_string.h \
+  ../include/ircd_chattr.h ../include/msg.h ../include/numeric.h \
+  ../include/s_stats.h ../include/s_user.h ../include/send.h \
+  ../include/struct.h
+m_svsmode.o: m_svsmode.c ../config.h ../include/IPcheck.h \
+ ../include/client.h ../include/ircd_defs.h ../include/dbuf.h \
+ ../include/msgq.h ../include/ircd_events.h ../include/ircd_handler.h \
+ ../include/hash.h ../include/ircd.h ../include/struct.h \
+ ../include/ircd_features.h ../include/ircd_chattr.h \
+ ../include/ircd_reply.h ../include/ircd_string.h ../include/msg.h \
+ ../include/numeric.h ../include/numnicks.h ../include/s_debug.h \
+ ../include/s_misc.h ../include/s_user.h ../include/send.h
+m_svsnick.o: m_svsnick.c ../config.h ../include/IPcheck.h \
+ ../include/client.h ../include/ircd_defs.h ../include/dbuf.h \
+ ../include/msgq.h ../include/ircd_events.h ../include/ircd_handler.h \
+ ../include/hash.h ../include/ircd.h ../include/struct.h \
+ ../include/ircd_features.h ../include/ircd_chattr.h \
+ ../include/ircd_reply.h ../include/ircd_string.h ../include/msg.h \
+ ../include/numeric.h ../include/numnicks.h ../include/s_debug.h \
+ ../include/s_misc.h ../include/s_user.h ../include/send.h
+m_svsjoin.o: m_svsjoin.c ../config.h ../include/IPcheck.h \
+ ../include/client.h ../include/ircd_defs.h ../include/dbuf.h \
+ ../include/msgq.h ../include/ircd_events.h ../include/ircd_handler.h \
+ ../include/hash.h ../include/ircd.h ../include/struct.h \
+ ../include/ircd_features.h ../include/ircd_chattr.h \
+ ../include/ircd_reply.h ../include/ircd_string.h ../include/msg.h \
+ ../include/numeric.h ../include/numnicks.h ../include/s_debug.h \
+ ../include/s_misc.h ../include/s_user.h ../include/send.h 
+m_time.o: m_time.c ../config.h ../include/client.h ../include/ircd_defs.h \
+  ../include/dbuf.h ../include/msgq.h ../include/ircd_events.h \
+  ../config.h ../include/ircd_handler.h ../include/res.h \
+  ../include/capab.h ../include/ircd.h ../include/struct.h \
+  ../include/ircd_features.h ../include/ircd_log.h \
+  ../include/ircd_reply.h ../include/ircd_string.h \
+  ../include/ircd_chattr.h ../include/msg.h ../include/numeric.h \
+  ../include/numnicks.h ../include/s_misc.h ../include/s_user.h \
+  ../include/send.h
+m_topic.o: m_topic.c ../config.h ../include/channel.h \
+  ../include/ircd_defs.h ../include/res.h ../config.h ../include/client.h \
+  ../include/dbuf.h ../include/msgq.h ../include/ircd_events.h \
+  ../include/ircd_handler.h ../include/capab.h ../include/hash.h \
+  ../include/ircd.h ../include/struct.h ../include/ircd_features.h \
+  ../include/ircd_log.h ../include/ircd_reply.h ../include/ircd_string.h \
+  ../include/ircd_chattr.h ../include/msg.h ../include/numeric.h \
+  ../include/numnicks.h ../include/send.h
+m_trace.o: m_trace.c ../config.h ../include/class.h ../include/client.h \
+  ../include/ircd_defs.h ../include/dbuf.h ../include/msgq.h \
+  ../include/ircd_events.h ../config.h ../include/ircd_handler.h \
+  ../include/res.h ../include/capab.h ../include/client.h \
+  ../include/hash.h ../include/ircd.h ../include/struct.h \
+  ../include/ircd_features.h ../include/ircd_log.h \
+  ../include/ircd_reply.h ../include/ircd_string.h \
+  ../include/ircd_chattr.h ../include/match.h ../include/msg.h \
+  ../include/numeric.h ../include/numnicks.h ../include/s_bsd.h \
+  ../include/s_conf.h ../include/s_user.h ../include/send.h \
+  ../include/version.h
+m_uping.o: m_uping.c ../config.h ../include/client.h \
+  ../include/ircd_defs.h ../include/dbuf.h ../include/msgq.h \
+  ../include/ircd_events.h ../config.h ../include/ircd_handler.h \
+  ../include/res.h ../include/capab.h ../include/hash.h ../include/ircd.h \
+  ../include/struct.h ../include/ircd_log.h ../include/ircd_reply.h \
+  ../include/ircd_string.h ../include/ircd_chattr.h ../include/match.h \
+  ../include/msg.h ../include/numeric.h ../include/numnicks.h \
+  ../include/s_conf.h ../include/client.h ../include/s_user.h \
+  ../include/send.h ../include/uping.h
+m_user.o: m_user.c ../config.h ../include/handlers.h ../include/client.h \
+  ../include/ircd_defs.h ../include/dbuf.h ../include/msgq.h \
+  ../include/ircd_events.h ../config.h ../include/ircd_handler.h \
+  ../include/res.h ../include/capab.h ../include/ircd.h \
+  ../include/struct.h ../include/ircd_chattr.h ../include/ircd_log.h \
+  ../include/ircd_reply.h ../include/ircd_string.h ../include/numeric.h \
+  ../include/numnicks.h ../include/s_auth.h ../include/s_debug.h \
+  ../include/s_misc.h ../include/s_user.h ../include/send.h
+m_userhost.o: m_userhost.c ../config.h ../include/client.h \
+  ../include/ircd_defs.h ../include/dbuf.h ../include/msgq.h \
+  ../include/ircd_events.h ../config.h ../include/ircd_handler.h \
+  ../include/res.h ../include/capab.h ../include/ircd_log.h \
+  ../include/ircd_reply.h ../include/ircd_string.h \
+  ../include/ircd_chattr.h ../include/msgq.h ../include/numeric.h \
+  ../include/s_user.h ../include/struct.h
+m_userip.o: m_userip.c ../config.h ../include/client.h \
+  ../include/ircd_defs.h ../include/dbuf.h ../include/msgq.h \
+  ../include/ircd_events.h ../config.h ../include/ircd_handler.h \
+  ../include/res.h ../include/capab.h ../include/ircd_reply.h \
+  ../include/ircd_string.h ../include/ircd_chattr.h \
+  ../include/ircd_features.h ../include/ircd_log.h ../include/msgq.h \
+  ../include/numeric.h ../include/s_user.h ../include/struct.h
+m_version.o: m_version.c ../config.h ../include/client.h \
+  ../include/ircd_defs.h ../include/dbuf.h ../include/msgq.h \
+  ../include/ircd_events.h ../config.h ../include/ircd_handler.h \
+  ../include/res.h ../include/capab.h ../include/hash.h ../include/ircd.h \
+  ../include/struct.h ../include/ircd_features.h ../include/ircd_log.h \
+  ../include/ircd_reply.h ../include/ircd_snprintf.h \
+  ../include/ircd_string.h ../include/ircd_chattr.h ../include/msg.h \
+  ../include/numeric.h ../include/numnicks.h ../include/s_debug.h \
+  ../include/s_user.h ../include/send.h ../include/supported.h \
+  ../include/channel.h ../include/version.h
+m_wallchops.o: m_wallchops.c ../config.h ../include/channel.h \
+  ../include/ircd_defs.h ../include/res.h ../config.h ../include/client.h \
+  ../include/dbuf.h ../include/msgq.h ../include/ircd_events.h \
+  ../include/ircd_handler.h ../include/capab.h ../include/hash.h \
+  ../include/ircd.h ../include/struct.h ../include/ircd_log.h \
+  ../include/ircd_reply.h ../include/ircd_string.h \
+  ../include/ircd_chattr.h ../include/msg.h ../include/numeric.h \
+  ../include/numnicks.h ../include/s_user.h ../include/send.h
+m_wallops.o: m_wallops.c ../config.h ../include/client.h \
+  ../include/ircd_defs.h ../include/dbuf.h ../include/msgq.h \
+  ../include/ircd_events.h ../config.h ../include/ircd_handler.h \
+  ../include/res.h ../include/capab.h ../include/ircd_log.h \
+  ../include/ircd_reply.h ../include/ircd_string.h \
+  ../include/ircd_chattr.h ../include/msg.h ../include/numeric.h \
+  ../include/send.h
+m_wallusers.o: m_wallusers.c ../config.h ../include/client.h \
+  ../include/ircd_defs.h ../include/dbuf.h ../include/msgq.h \
+  ../include/ircd_events.h ../config.h ../include/ircd_handler.h \
+  ../include/res.h ../include/capab.h ../include/ircd_log.h \
+  ../include/ircd_reply.h ../include/ircd_string.h \
+  ../include/ircd_chattr.h ../include/msg.h ../include/numeric.h \
+  ../include/send.h
+m_wallvoices.o: m_wallvoices.c ../config.h ../include/channel.h \
+  ../include/ircd_defs.h ../include/res.h ../config.h ../include/client.h \
+  ../include/dbuf.h ../include/msgq.h ../include/ircd_events.h \
+  ../include/ircd_handler.h ../include/capab.h ../include/hash.h \
+  ../include/ircd.h ../include/struct.h ../include/ircd_log.h \
+  ../include/ircd_reply.h ../include/ircd_string.h \
+  ../include/ircd_chattr.h ../include/msg.h ../include/numeric.h \
+  ../include/numnicks.h ../include/s_user.h ../include/send.h
+m_webirc.o: m_webirc.c ../config.h ../include/client.h ../include/ircd_crypt.h \
+  ../include/hash.h ../include/ircd.h ../include/ircd_log.h \
+  ../include/ircd_reply.h ../include/ircd_string.h ../include/IPcheck.h \
+  ../include/numeric.h ../include/s_conf.h ../include/numnicks.h ../include/send.h \
+  ../include/s_misc.h ../include/ircd_features.h ../include/match.h ../include/res.h \
+  ../include/ircd_alloc.h
+m_who.o: m_who.c ../config.h ../include/channel.h ../include/ircd_defs.h \
+  ../include/res.h ../config.h ../include/client.h ../include/dbuf.h \
+  ../include/msgq.h ../include/ircd_events.h ../include/ircd_handler.h \
+  ../include/capab.h ../include/hash.h ../include/ircd.h \
+  ../include/struct.h ../include/ircd_chattr.h ../include/ircd_features.h \
+  ../include/ircd_log.h ../include/ircd_reply.h ../include/ircd_string.h \
+  ../include/match.h ../include/numeric.h ../include/numnicks.h \
+  ../include/send.h ../include/whocmds.h
+m_whois.o: m_whois.c ../config.h ../include/channel.h \
+  ../include/ircd_defs.h ../include/res.h ../config.h ../include/client.h \
+  ../include/dbuf.h ../include/msgq.h ../include/ircd_events.h \
+  ../include/ircd_handler.h ../include/capab.h ../include/hash.h \
+  ../include/ircd.h ../include/struct.h ../include/ircd_features.h \
+  ../include/ircd_log.h ../include/ircd_reply.h ../include/ircd_string.h \
+  ../include/ircd_chattr.h ../include/match.h ../include/msg.h \
+  ../include/numeric.h ../include/numnicks.h ../include/s_user.h \
+  ../include/send.h ../include/whocmds.h
+m_whowas.o: m_whowas.c ../config.h ../include/client.h \
+  ../include/ircd_defs.h ../include/dbuf.h ../include/msgq.h \
+  ../include/ircd_events.h ../config.h ../include/ircd_handler.h \
+  ../include/res.h ../include/capab.h ../include/hash.h ../include/ircd.h \
+  ../include/struct.h ../include/ircd_features.h ../include/ircd_log.h \
+  ../include/ircd_reply.h ../include/ircd_string.h \
+  ../include/ircd_chattr.h ../include/msg.h ../include/numeric.h \
+  ../include/numnicks.h ../include/s_user.h ../include/s_misc.h \
+  ../include/send.h ../include/whowas.h
+match.o: match.c ../config.h ../include/match.h ../include/res.h \
+  ../config.h ../include/ircd_chattr.h ../include/ircd_string.h \
+  ../include/ircd_snprintf.h
+memdebug.o: memdebug.c ../include/ircd.h ../include/struct.h \
+  ../include/ircd_defs.h ../include/ircd_alloc.h ../include/ircd_log.h \
+  ../include/client.h ../include/dbuf.h ../include/msgq.h \
+  ../include/ircd_events.h ../config.h ../include/ircd_handler.h \
+  ../include/res.h ../include/capab.h ../include/s_debug.h \
+  ../include/send.h
+motd.o: motd.c ../config.h ../include/motd.h ../include/res.h ../config.h \
+  ../include/class.h ../include/client.h ../include/ircd_defs.h \
+  ../include/dbuf.h ../include/msgq.h ../include/ircd_events.h \
+  ../include/ircd_handler.h ../include/capab.h ../include/client.h \
+  ../include/fileio.h ../include/ircd.h ../include/struct.h \
+  ../include/ircd_alloc.h ../include/ircd_features.h \
+  ../include/ircd_log.h ../include/ircd_reply.h ../include/ircd_string.h \
+  ../include/ircd_chattr.h ../include/match.h ../include/msg.h \
+  ../include/numeric.h ../include/numnicks.h ../include/s_conf.h \
+  ../include/s_debug.h ../include/s_user.h ../include/s_stats.h \
+  ../include/send.h
+msgq.o: msgq.c ../config.h ../include/msgq.h ../include/ircd_defs.h \
+  ../include/ircd.h ../include/struct.h ../include/ircd_alloc.h \
+  ../include/ircd_defs.h ../include/ircd_features.h ../include/ircd_log.h \
+  ../include/ircd_reply.h ../include/ircd_snprintf.h ../include/numeric.h \
+  ../include/send.h ../include/s_debug.h ../config.h ../include/s_stats.h
+numnicks.o: numnicks.c ../config.h ../include/numnicks.h \
+  ../include/client.h ../include/ircd_defs.h ../include/dbuf.h \
+  ../include/msgq.h ../include/ircd_events.h ../config.h \
+  ../include/ircd_handler.h ../include/res.h ../include/capab.h \
+  ../include/client.h ../include/ircd.h ../include/struct.h \
+  ../include/ircd_alloc.h ../include/ircd_log.h ../include/ircd_string.h \
+  ../include/ircd_chattr.h ../include/match.h ../include/s_bsd.h \
+  ../include/s_debug.h ../include/s_misc.h ../include/struct.h
+opercmds.o: opercmds.c ../config.h ../include/opercmds.h \
+  ../include/class.h ../include/client.h ../include/ircd_defs.h \
+  ../include/dbuf.h ../include/msgq.h ../include/ircd_events.h \
+  ../config.h ../include/ircd_handler.h ../include/res.h \
+  ../include/capab.h ../include/client.h ../include/ircd.h \
+  ../include/struct.h ../include/ircd_chattr.h ../include/ircd_reply.h \
+  ../include/ircd_string.h ../include/listener.h ../include/match.h \
+  ../include/msg.h ../include/numeric.h ../include/numnicks.h \
+  ../include/s_conf.h ../include/send.h ../include/struct.h
+os_generic.o: os_generic.c ../config.h ../include/ircd_osdep.h \
+  ../include/msgq.h ../include/ircd_defs.h ../include/ircd_log.h \
+  ../include/res.h ../config.h ../include/s_bsd.h ../include/sys.h
+packet.o: packet.c ../config.h ../include/packet.h ../include/client.h \
+  ../include/ircd_defs.h ../include/dbuf.h ../include/msgq.h \
+  ../include/ircd_events.h ../config.h ../include/ircd_handler.h \
+  ../include/res.h ../include/capab.h ../include/ircd.h \
+  ../include/struct.h ../include/ircd_chattr.h ../include/ircd_log.h \
+  ../include/parse.h ../include/s_bsd.h ../include/s_misc.h \
+  ../include/send.h
+parse.o: parse.c ../config.h ../include/parse.h ../include/client.h \
+  ../include/ircd_defs.h ../include/dbuf.h ../include/msgq.h \
+  ../include/ircd_events.h ../config.h ../include/ircd_handler.h \
+  ../include/res.h ../include/capab.h ../include/channel.h \
+  ../include/handlers.h ../include/hash.h ../include/ircd.h \
+  ../include/struct.h ../include/ircd_alloc.h ../include/ircd_chattr.h \
+  ../include/ircd_features.h ../include/ircd_log.h \
+  ../include/ircd_reply.h ../include/ircd_string.h ../include/msg.h \
+  ../include/numeric.h ../include/numnicks.h ../include/opercmds.h \
+  ../include/querycmds.h ../include/ircd_features.h ../include/res.h \
+  ../include/s_bsd.h ../include/s_conf.h ../include/client.h \
+  ../include/s_debug.h ../include/s_misc.h ../include/s_numeric.h \
+  ../include/s_user.h ../include/send.h ../include/struct.h \
+  ../include/sys.h ../include/whocmds.h ../include/whowas.h
+querycmds.o: querycmds.c ../config.h ../include/querycmds.h \
+  ../include/ircd_features.h
+random.o: random.c ../config.h ../include/random.h ../include/client.h \
+  ../include/ircd_defs.h ../include/dbuf.h ../include/msgq.h \
+  ../include/ircd_events.h ../config.h ../include/ircd_handler.h \
+  ../include/res.h ../include/capab.h ../include/ircd_log.h \
+  ../include/ircd_md5.h ../include/ircd_reply.h ../include/send.h
+s_auth.o: s_auth.c ../config.h ../include/s_auth.h \
+  ../include/ircd_events.h ../config.h ../include/class.h \
+  ../include/client.h ../include/ircd_defs.h ../include/dbuf.h \
+  ../include/msgq.h ../include/ircd_handler.h ../include/res.h \
+  ../include/capab.h ../include/client.h ../include/IPcheck.h \
+  ../include/ircd.h ../include/struct.h ../include/ircd_alloc.h \
+  ../include/ircd_chattr.h ../include/ircd_events.h \
+  ../include/ircd_features.h ../include/ircd_log.h \
+  ../include/ircd_osdep.h ../include/ircd_reply.h \
+  ../include/ircd_snprintf.h ../include/ircd_string.h ../include/list.h \
+  ../include/numeric.h ../include/querycmds.h ../include/ircd_features.h \
+  ../include/random.h ../include/res.h ../include/s_bsd.h \
+  ../include/s_conf.h ../include/s_debug.h ../include/s_misc.h \
+  ../include/s_user.h ../include/send.h
+s_bsd.o: s_bsd.c ../config.h ../include/s_bsd.h ../include/client.h \
+  ../include/ircd_defs.h ../include/dbuf.h ../include/msgq.h \
+  ../include/ircd_events.h ../config.h ../include/ircd_handler.h \
+  ../include/res.h ../include/capab.h ../include/IPcheck.h \
+  ../include/channel.h ../include/class.h ../include/client.h \
+  ../include/hash.h ../include/ircd_alloc.h ../include/ircd_log.h \
+  ../include/ircd_features.h ../include/ircd_osdep.h \
+  ../include/ircd_reply.h ../include/ircd_snprintf.h \
+  ../include/ircd_string.h ../include/ircd_chattr.h ../include/ircd.h \
+  ../include/struct.h ../include/list.h ../include/listener.h \
+  ../include/msg.h ../include/msgq.h ../include/numeric.h \
+  ../include/numnicks.h ../include/packet.h ../include/parse.h \
+  ../include/querycmds.h ../include/ircd_features.h ../include/res.h \
+  ../include/s_auth.h ../include/s_conf.h ../include/s_debug.h \
+  ../include/s_misc.h ../include/s_user.h ../include/send.h \
+  ../include/struct.h ../include/sys.h ../include/uping.h \
+  ../include/version.h
+s_conf.o: s_conf.c ../config.h ../include/s_conf.h ../include/client.h \
+  ../include/ircd_defs.h ../include/dbuf.h ../include/msgq.h \
+  ../include/ircd_events.h ../config.h ../include/ircd_handler.h \
+  ../include/res.h ../include/capab.h ../include/IPcheck.h \
+  ../include/class.h ../include/client.h ../include/crule.h \
+  ../include/ircd_features.h ../include/fileio.h ../include/gline.h \
+  ../include/hash.h ../include/ircd.h ../include/struct.h \
+  ../include/ircd_alloc.h ../include/ircd_chattr.h ../include/ircd_log.h \
+  ../include/ircd_reply.h ../include/ircd_snprintf.h \
+  ../include/ircd_string.h ../include/list.h ../include/listener.h \
+  ../include/match.h ../include/motd.h ../include/numeric.h \
+  ../include/numnicks.h ../include/opercmds.h ../include/parse.h \
+  ../include/res.h ../include/s_auth.h ../include/s_bsd.h \
+  ../include/s_debug.h ../include/s_misc.h ../include/send.h \
+  ../include/struct.h ../include/sys.h
+s_debug.o: s_debug.c ../config.h ../include/s_debug.h ../config.h \
+  ../include/ircd_defs.h ../include/channel.h ../include/res.h \
+  ../include/class.h ../include/client.h ../include/dbuf.h \
+  ../include/msgq.h ../include/ircd_events.h ../include/ircd_handler.h \
+  ../include/capab.h ../include/client.h ../include/gline.h \
+  ../include/hash.h ../include/ircd_alloc.h ../include/ircd_features.h \
+  ../include/ircd_log.h ../include/ircd_osdep.h ../include/ircd_reply.h \
+  ../include/ircd.h ../include/struct.h ../include/jupe.h \
+  ../include/list.h ../include/listener.h ../include/motd.h \
+  ../include/msgq.h ../include/numeric.h ../include/numnicks.h \
+  ../include/res.h ../include/s_bsd.h ../include/s_conf.h \
+  ../include/s_user.h ../include/s_stats.h ../include/send.h \
+  ../include/struct.h ../include/sys.h ../include/whowas.h
+s_err.o: s_err.c ../config.h ../include/numeric.h ../include/ircd_log.h \
+  ../include/s_debug.h ../config.h ../include/ircd_defs.h
+s_misc.o: s_misc.c ../config.h ../include/s_misc.h ../include/IPcheck.h \
+  ../include/channel.h ../include/ircd_defs.h ../include/res.h \
+  ../config.h ../include/client.h ../include/dbuf.h ../include/msgq.h \
+  ../include/ircd_events.h ../include/ircd_handler.h ../include/capab.h \
+  ../include/hash.h ../include/ircd.h ../include/struct.h \
+  ../include/ircd_alloc.h ../include/ircd_features.h \
+  ../include/ircd_log.h ../include/ircd_reply.h \
+  ../include/ircd_snprintf.h ../include/ircd_string.h \
+  ../include/ircd_chattr.h ../include/list.h ../include/match.h \
+  ../include/msg.h ../include/numeric.h ../include/numnicks.h \
+  ../include/parse.h ../include/querycmds.h ../include/ircd_features.h \
+  ../include/res.h ../include/s_auth.h ../include/s_bsd.h \
+  ../include/s_conf.h ../include/client.h ../include/s_debug.h \
+  ../include/s_stats.h ../include/s_user.h ../include/send.h \
+  ../include/struct.h ../include/sys.h ../include/uping.h \
+  ../include/userload.h
+s_numeric.o: s_numeric.c ../config.h ../include/s_numeric.h \
+  ../include/channel.h ../include/ircd_defs.h ../include/res.h \
+  ../config.h ../include/client.h ../include/dbuf.h ../include/msgq.h \
+  ../include/ircd_events.h ../include/ircd_handler.h ../include/capab.h \
+  ../include/hash.h ../include/ircd.h ../include/struct.h \
+  ../include/ircd_features.h ../include/ircd_snprintf.h \
+  ../include/numnicks.h ../include/send.h ../include/struct.h
+s_serv.o: s_serv.c ../config.h ../include/s_serv.h ../include/IPcheck.h \
+  ../include/channel.h ../include/ircd_defs.h ../include/res.h \
+  ../config.h ../include/client.h ../include/dbuf.h ../include/msgq.h \
+  ../include/ircd_events.h ../include/ircd_handler.h ../include/capab.h \
+  ../include/gline.h ../include/hash.h ../include/ircd.h \
+  ../include/struct.h ../include/ircd_alloc.h ../include/ircd_log.h \
+  ../include/ircd_reply.h ../include/ircd_string.h \
+  ../include/ircd_chattr.h ../include/ircd_snprintf.h \
+  ../include/ircd_crypt.h ../include/jupe.h ../include/list.h \
+  ../include/match.h ../include/msg.h ../include/msgq.h \
+  ../include/numeric.h ../include/numnicks.h ../include/parse.h \
+  ../include/querycmds.h ../include/ircd_features.h ../include/s_bsd.h \
+  ../include/s_conf.h ../include/client.h ../include/s_debug.h \
+  ../include/s_misc.h ../include/s_user.h ../include/send.h \
+  ../include/struct.h ../include/sys.h ../include/userload.h
+s_stats.o: s_stats.c ../config.h ../include/class.h ../include/client.h \
+  ../include/ircd_defs.h ../include/dbuf.h ../include/msgq.h \
+  ../include/ircd_events.h ../config.h ../include/ircd_handler.h \
+  ../include/res.h ../include/capab.h ../include/client.h \
+  ../include/gline.h ../include/hash.h ../include/ircd.h \
+  ../include/struct.h ../include/ircd_chattr.h ../include/ircd_events.h \
+  ../include/ircd_features.h ../include/ircd_crypt.h \
+  ../include/ircd_log.h ../include/ircd_reply.h ../include/ircd_string.h \
+  ../include/listener.h ../include/list.h ../include/match.h \
+  ../include/motd.h ../include/msg.h ../include/msgq.h \
+  ../include/numeric.h ../include/numnicks.h ../include/querycmds.h \
+  ../include/ircd_features.h ../include/res.h ../include/s_auth.h \
+  ../include/s_bsd.h ../include/s_conf.h ../include/s_debug.h \
+  ../include/s_misc.h ../include/s_serv.h ../include/s_stats.h \
+  ../include/s_user.h ../include/send.h ../include/struct.h \
+  ../include/userload.h
+s_user.o: s_user.c ../config.h ../include/s_user.h ../include/IPcheck.h \
+  ../include/channel.h ../include/ircd_defs.h ../include/res.h \
+  ../config.h ../include/class.h ../include/client.h ../include/dbuf.h \
+  ../include/msgq.h ../include/ircd_events.h ../include/ircd_handler.h \
+  ../include/capab.h ../include/client.h ../include/hash.h \
+  ../include/ircd.h ../include/struct.h ../include/ircd_alloc.h \
+  ../include/ircd_chattr.h ../include/ircd_features.h \
+  ../include/ircd_log.h ../include/ircd_reply.h \
+  ../include/ircd_snprintf.h ../include/ircd_string.h ../include/list.h \
+  ../include/match.h ../include/motd.h ../include/msg.h ../include/msgq.h \
+  ../include/numeric.h ../include/numnicks.h ../include/parse.h \
+  ../include/querycmds.h ../include/ircd_features.h ../include/random.h \
+  ../include/s_auth.h ../include/s_bsd.h ../include/s_conf.h \
+  ../include/s_debug.h ../include/s_misc.h ../include/s_serv.h \
+  ../include/send.h ../include/struct.h ../include/supported.h \
+  ../include/channel.h ../include/sys.h ../include/userload.h \
+  ../include/version.h ../include/whowas.h ../include/handlers.h
+send.o: send.c ../config.h ../include/send.h ../include/channel.h \
+  ../include/ircd_defs.h ../include/res.h ../config.h ../include/class.h \
+  ../include/client.h ../include/dbuf.h ../include/msgq.h \
+  ../include/ircd_events.h ../include/ircd_handler.h ../include/capab.h \
+  ../include/client.h ../include/ircd.h ../include/struct.h \
+  ../include/ircd_features.h ../include/ircd_log.h \
+  ../include/ircd_snprintf.h ../include/ircd_string.h \
+  ../include/ircd_chattr.h ../include/list.h ../include/match.h \
+  ../include/msg.h ../include/numnicks.h ../include/parse.h \
+  ../include/s_bsd.h ../include/s_debug.h ../include/s_misc.h \
+  ../include/s_user.h ../include/struct.h ../include/sys.h
+uping.o: uping.c ../config.h ../include/uping.h ../include/ircd_defs.h \
+  ../include/ircd_events.h ../config.h ../include/res.h \
+  ../include/client.h ../include/dbuf.h ../include/msgq.h \
+  ../include/ircd_handler.h ../include/capab.h ../include/ircd.h \
+  ../include/struct.h ../include/ircd_alloc.h ../include/ircd_events.h \
+  ../include/ircd_log.h ../include/ircd_osdep.h ../include/ircd_string.h \
+  ../include/ircd_chattr.h ../include/match.h ../include/msg.h \
+  ../include/numeric.h ../include/numnicks.h ../include/s_bsd.h \
+  ../include/s_conf.h ../include/client.h ../include/s_debug.h \
+  ../include/s_misc.h ../include/s_user.h ../include/send.h \
+  ../include/sys.h
+userload.o: userload.c ../config.h ../include/userload.h \
+  ../include/client.h ../include/ircd_defs.h ../include/dbuf.h \
+  ../include/msgq.h ../include/ircd_events.h ../config.h \
+  ../include/ircd_handler.h ../include/res.h ../include/capab.h \
+  ../include/ircd.h ../include/struct.h ../include/msg.h \
+  ../include/numnicks.h ../include/querycmds.h ../include/ircd_features.h \
+  ../include/s_misc.h ../include/s_stats.h ../include/send.h \
+  ../include/struct.h ../include/sys.h
+whocmds.o: whocmds.c ../config.h ../include/whocmds.h \
+  ../include/channel.h ../include/ircd_defs.h ../include/res.h \
+  ../config.h ../include/client.h ../include/dbuf.h ../include/msgq.h \
+  ../include/ircd_events.h ../include/ircd_handler.h ../include/capab.h \
+  ../include/hash.h ../include/ircd.h ../include/struct.h \
+  ../include/ircd_chattr.h ../include/ircd_features.h \
+  ../include/ircd_reply.h ../include/ircd_snprintf.h \
+  ../include/ircd_string.h ../include/list.h ../include/match.h \
+  ../include/numeric.h ../include/numnicks.h ../include/querycmds.h \
+  ../include/ircd_features.h ../include/random.h ../include/s_bsd.h \
+  ../include/s_conf.h ../include/client.h ../include/s_misc.h \
+  ../include/s_user.h ../include/send.h ../include/struct.h \
+  ../include/sys.h ../include/userload.h ../include/version.h \
+  ../include/whowas.h ../include/msg.h
+whowas.o: whowas.c ../config.h ../include/whowas.h ../include/client.h \
+  ../include/ircd_defs.h ../include/dbuf.h ../include/msgq.h \
+  ../include/ircd_events.h ../config.h ../include/ircd_handler.h \
+  ../include/res.h ../include/capab.h ../include/ircd.h \
+  ../include/struct.h ../include/ircd_alloc.h ../include/ircd_chattr.h \
+  ../include/ircd_features.h ../include/ircd_log.h \
+  ../include/ircd_string.h ../include/list.h ../include/numeric.h \
+  ../include/s_debug.h ../include/s_misc.h ../include/s_user.h \
+  ../include/send.h ../include/struct.h ../include/sys.h ../include/msg.h
+y.tab.o: y.tab.c ../config.h ../include/s_conf.h ../include/client.h \
+  ../include/ircd_defs.h ../include/dbuf.h ../include/msgq.h \
+  ../include/ircd_events.h ../config.h ../include/ircd_handler.h \
+  ../include/res.h ../include/capab.h ../include/class.h \
+  ../include/client.h ../include/crule.h ../include/ircd_features.h \
+  ../include/fileio.h ../include/gline.h ../include/hash.h \
+  ../include/ircd.h ../include/struct.h ../include/ircd_alloc.h \
+  ../include/ircd_chattr.h ../include/ircd_log.h ../include/ircd_reply.h \
+  ../include/ircd_snprintf.h ../include/ircd_string.h ../include/list.h \
+  ../include/listener.h ../include/match.h ../include/motd.h \
+  ../include/numeric.h ../include/numnicks.h ../include/opercmds.h \
+  ../include/parse.h ../include/res.h ../include/s_auth.h \
+  ../include/s_bsd.h ../include/s_debug.h ../include/s_misc.h \
+  ../include/send.h ../include/struct.h ../include/sys.h
+engine_devpoll.o: engine_devpoll.c ../config.h ../include/ircd_events.h \
+  ../config.h ../include/ircd.h ../include/struct.h \
+  ../include/ircd_defs.h ../include/ircd_alloc.h \
+  ../include/ircd_features.h ../include/ircd_log.h ../include/s_debug.h
+engine_poll.o: engine_poll.c ../config.h ../include/ircd_events.h \
+  ../config.h ../include/ircd.h ../include/struct.h \
+  ../include/ircd_defs.h ../include/ircd_alloc.h ../include/ircd_log.h \
+  ../include/s_debug.h
+engine_kqueue.o: engine_kqueue.c ../config.h ../include/ircd_events.h \
+  ../config.h ../include/ircd.h ../include/struct.h \
+  ../include/ircd_defs.h ../include/ircd_alloc.h \
+  ../include/ircd_features.h ../include/ircd_log.h ../include/s_debug.h
+engine_select.o: engine_select.c ../config.h ../include/ircd_events.h \
+  ../config.h ../include/ircd.h ../include/struct.h \
+  ../include/ircd_defs.h ../include/ircd_log.h ../include/s_debug.h
+ircd_md5.o: ircd_md5.c ../include/ircd_md5.h
+ircd_crypt_plain.o: ircd_crypt_plain.c ../config.h \
+  ../include/ircd_crypt.h ../include/ircd_crypt_plain.h \
+  ../include/ircd_log.h ../include/s_debug.h ../config.h \
+  ../include/ircd_defs.h ../include/ircd_alloc.h
+ircd_crypt_smd5.o: ircd_crypt_smd5.c ../config.h ../include/ircd_crypt.h \
+  ../include/ircd_crypt_smd5.h ../include/ircd_log.h \
+  ../include/ircd_md5.h ../include/s_debug.h ../config.h \
+  ../include/ircd_defs.h ../include/ircd_alloc.h
+ircd_crypt_native.o: ircd_crypt_native.c ../config.h \
+  ../include/ircd_crypt.h ../include/ircd_crypt_native.h \
+  ../include/ircd_log.h ../include/s_debug.h ../config.h \
+  ../include/ircd_defs.h ../include/ircd_alloc.h
diff --git a/ircd/channel.c b/ircd/channel.c
new file mode 100644 (file)
index 0000000..01d2507
--- /dev/null
@@ -0,0 +1,4113 @@
+/*
+ * IRC - Internet Relay Chat, ircd/channel.c
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ *                    University of Oulu, Co Center
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+/** @file
+ * @brief Channel management and maintenance
+ * @version $Id: channel.c 1906 2009-02-09 03:39:42Z entrope $
+ */
+#include "config.h"
+
+#include "channel.h"
+#include "class.h"
+#include "client.h"
+#include "destruct_event.h"
+#include "hash.h"
+#include "ircd.h"
+#include "ircd_alloc.h"
+#include "ircd_chattr.h"
+#include "ircd_defs.h"
+#include "ircd_features.h"
+#include "ircd_log.h"
+#include "ircd_reply.h"
+#include "ircd_snprintf.h"
+#include "ircd_string.h"
+#include "list.h"
+#include "match.h"
+#include "msg.h"
+#include "msgq.h"
+#include "numeric.h"
+#include "numnicks.h"
+#include "querycmds.h"
+#include "s_bsd.h"
+#include "s_conf.h"
+#include "s_debug.h"
+#include "s_misc.h"
+#include "s_user.h"
+#include "send.h"
+#include "struct.h"
+#include "sys.h"
+#include "whowas.h"
+
+/* #include <assert.h> -- Now using assert in ircd_log.h */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+/** Linked list containing the full list of all channels */
+struct Channel* GlobalChannelList = 0;
+
+/** Number of struct Membership*'s allocated */
+static unsigned int membershipAllocCount;
+/** Freelist for struct Membership*'s */
+static struct Membership* membershipFreeList;
+/** Freelist for struct Ban*'s */
+static struct Ban* free_bans;
+/** Number of ban structures allocated. */
+static size_t bans_alloc;
+/** Number of ban structures in use. */
+static size_t bans_inuse;
+
+#if !defined(NDEBUG)
+/** return the length (>=0) of a chain of links.
+ * @param lp   pointer to the start of the linked list
+ * @return the number of items in the list
+ */
+static int list_length(struct SLink *lp)
+{
+  int count = 0;
+
+  for (; lp; lp = lp->next)
+    ++count;
+  return count;
+}
+#endif
+
+/** Set the mask for a ban, checking for IP masks.
+ * @param[in,out] ban Ban structure to modify.
+ * @param[in] banstr Mask to ban.
+ */
+static void
+set_ban_mask(struct Ban *ban, const char *banstr)
+{
+  char *sep;
+  assert(banstr != NULL);
+  ircd_strncpy(ban->banstr, banstr, sizeof(ban->banstr) - 1);
+  sep = strrchr(banstr, '@');
+  if (sep) {
+    ban->nu_len = sep - banstr;
+    if (ipmask_parse(sep + 1, &ban->address, &ban->addrbits))
+      ban->flags |= BAN_IPMASK;
+  }
+}
+
+/** Allocate a new Ban structure.
+ * @param[in] banstr Ban mask to use.
+ * @return Newly allocated ban.
+ */
+struct Ban *
+make_ban(const char *banstr)
+{
+  struct Ban *ban;
+  if (free_bans) {
+    ban = free_bans;
+    free_bans = free_bans->next;
+  }
+  else if (!(ban = MyMalloc(sizeof(*ban))))
+    return NULL;
+  else
+    bans_alloc++;
+  bans_inuse++;
+  memset(ban, 0, sizeof(*ban));
+  set_ban_mask(ban, banstr);
+  return ban;
+}
+
+/** Deallocate a ban structure.
+ * @param[in] ban Ban to deallocate.
+ */
+void
+free_ban(struct Ban *ban)
+{
+  ban->next = free_bans;
+  free_bans = ban;
+  bans_inuse--;
+}
+
+/** Report ban usage to \a cptr.
+ * @param[in] cptr Client requesting information.
+ */
+void bans_send_meminfo(struct Client *cptr)
+{
+  struct Ban *ban;
+  size_t num_free;
+  for (num_free = 0, ban = free_bans; ban; ban = ban->next)
+    num_free++;
+  send_reply(cptr, SND_EXPLICIT | RPL_STATSDEBUG, ":Bans: inuse %zu(%zu) free %zu alloc %zu",
+            bans_inuse, bans_inuse * sizeof(*ban), num_free, bans_alloc);
+}
+
+/** return the struct Membership* that represents a client on a channel
+ * This function finds a struct Membership* which holds the state about
+ * a client on a specific channel.  The code is smart enough to iterate
+ * over the channels a user is in, or the users in a channel to find the
+ * user depending on which is likely to be more efficient.
+ *
+ * @param chptr        pointer to the channel struct
+ * @param cptr pointer to the client struct
+ *
+ * @returns pointer to the struct Membership representing this client on 
+ *          this channel.  Returns NULL if the client is not on the channel.
+ *          Returns NULL if the client is actually a server.
+ * @see find_channel_member()
+ */
+struct Membership* find_member_link(struct Channel* chptr, const struct Client* cptr)
+{
+  struct Membership *m;
+  assert(0 != cptr);
+  assert(0 != chptr);
+  
+  /* Servers don't have member links */
+  if (IsServer(cptr)||IsMe(cptr))
+     return 0;
+  
+  /* +k users are typically on a LOT of channels.  So we iterate over who
+   * is in the channel.  X/W are +k and are in about 5800 channels each.
+   * however there are typically no more than 1000 people in a channel
+   * at a time.
+   */
+  if (IsChannelService(cptr)) {
+    m = chptr->members;
+    while (m) {
+      assert(m->channel == chptr);
+      if (m->user == cptr)
+        return m;
+      m = m->next_member;
+    }
+  }
+  /* Users on the other hand aren't allowed on more than 15 channels.  50%
+   * of users that are on channels are on 2 or less, 95% are on 7 or less,
+   * and 99% are on 10 or less.
+   */
+  else {
+   m = (cli_user(cptr))->channel;
+   while (m) {
+     assert(m->user == cptr);
+     if (m->channel == chptr)
+       return m;
+     m = m->next_channel;
+   }
+  }
+  return 0;
+}
+
+/** Find the client structure for a nick name (user) 
+ * Find the client structure for a nick name (user)
+ * using history mechanism if necessary. If the client is not found, an error
+ * message (NO SUCH NICK) is generated. If the client was found
+ * through the history, chasing will be 1 and otherwise 0.
+ *
+ * This function was used extensively in the P09 days, and since we now have
+ * numeric nicks is no longer quite as important.
+ *
+ * @param sptr Pointer to the client that has requested the search
+ * @param user a string representing the client to be found
+ * @param chasing a variable set to 0 if the user was found directly, 
+ *             1 otherwise
+ * @returns a pointer the client, or NULL if the client wasn't found.
+ */
+struct Client* find_chasing(struct Client* sptr, const char* user, int* chasing)
+{
+  struct Client* who = FindClient(user);
+  
+  if (chasing)
+    *chasing = 0;
+  if (who)
+    return who;
+
+  if (!(who = get_history(user, feature_int(FEAT_KILLCHASETIMELIMIT)))) {
+    send_reply(sptr, ERR_NOSUCHNICK, user);
+    return 0;
+  }
+  if (chasing)
+    *chasing = 1;
+  return who;
+}
+
+/** Decrement the count of users, and free if empty.
+ * Subtract one user from channel i (and free channel * block, if channel 
+ * became empty).
+ *
+ * @param chptr The channel to subtract one from.
+ *
+ * @returns true  (1) if channel still has members.
+ *          false (0) if the channel is now empty.
+ */
+int sub1_from_channel(struct Channel* chptr)
+{
+  if (chptr->users > 1)         /* Can be 0, called for an empty channel too */
+  {
+    assert(0 != chptr->members);
+    --chptr->users;
+    return 1;
+  }
+
+  chptr->users = 0;
+
+  if(chptr->mode.mode & MODE_PERSIST)
+    return 0;
+
+  /*
+   * Also channels without Apass set need to be kept alive,
+   * otherwise Bad Guys(tm) would be able to takeover
+   * existing channels too easily, and then set an Apass!
+   * However, if a channel without Apass becomes empty
+   * then we try to be kind to them and remove possible
+   * limiting modes.
+   */
+  chptr->mode.mode &= ~MODE_INVITEONLY;
+  chptr->mode.limit = 0;
+  /*
+   * We do NOT reset a possible key or bans because when
+   * the 'channel owners' can't get in because of a key
+   * or ban then apparently there was a fight/takeover
+   * on the channel and we want them to contact IRC opers
+   * who then will educate them on the use of Apass/Upass.
+   */
+  if (!chptr->mode.apass[0])                   /* If no Apass, reset all modes. */
+  {
+    struct Ban *link, *next;
+    chptr->mode.mode = 0;
+    *chptr->mode.key = '\0';
+    while (chptr->invites)
+      del_invite(chptr->invites->value.cptr, chptr);
+    for (link = chptr->banlist; link; link = next) {
+      next = link->next;
+      free_ban(link);
+    }
+    chptr->banlist = NULL;
+
+    /* Immediately destruct empty -A channels if not using apass. */
+    if (!feature_bool(FEAT_OPLEVELS))
+    {
+      destruct_channel(chptr);
+      return 0;
+    }
+  }
+  if (TStime() - chptr->creationtime < 172800) /* Channel younger than 48 hours? */
+    schedule_destruct_event_1m(chptr);         /* Get rid of it in approximately 4-5 minutes */
+  else
+    schedule_destruct_event_48h(chptr);                /* Get rid of it in approximately 48 hours */
+
+  return 0;
+}
+
+/** Destroy an empty channel
+ * This function destroys an empty channel, removing it from hashtables,
+ * and removing any resources it may have consumed.
+ *
+ * @param chptr The channel to destroy
+ *
+ * @returns 0 (success)
+ *
+ * FIXME: Change to return void, this function never fails.
+ */
+int destruct_channel(struct Channel* chptr)
+{
+  struct Ban *ban, *next;
+
+  assert(0 == chptr->members);
+
+  /*
+   * Now, find all invite links from channel structure
+   */
+  while (chptr->invites)
+    del_invite(chptr->invites->value.cptr, chptr);
+
+  for (ban = chptr->banlist; ban; ban = next)
+  {
+    next = ban->next;
+    free_ban(ban);
+  }
+  if (chptr->prev)
+    chptr->prev->next = chptr->next;
+  else
+    GlobalChannelList = chptr->next;
+  if (chptr->next)
+    chptr->next->prev = chptr->prev;
+  hRemChannel(chptr);
+  --UserStats.channels;
+  /*
+   * make sure that channel actually got removed from hash table
+   */
+  assert(chptr->hnext == chptr);
+  MyFree(chptr);
+  return 0;
+}
+
+/** returns Membership * if a person is joined and not a zombie
+ * @param cptr Client
+ * @param chptr Channel
+ * @returns pointer to the client's struct Membership * on the channel if that
+ *          user is a full member of the channel, or NULL otherwise.
+ *
+ * @see find_member_link()
+ */
+struct Membership* find_channel_member(struct Client* cptr, struct Channel* chptr)
+{
+  struct Membership* member;
+  assert(0 != chptr);
+
+  member = find_member_link(chptr, cptr);
+  return (member && !IsZombie(member)) ? member : 0;
+}
+
+/** Searches for a ban from a ban list that matches a user.
+ * @param[in] cptr The client to test.
+ * @param[in] banlist The list of bans to test.
+ * @return Pointer to a matching ban, or NULL if none exit.
+ */
+struct Ban *find_ban(struct Client *cptr, struct Ban *banlist)
+{
+  char        nu[NICKLEN + USERLEN + 2];
+  char        tmphost[HOSTLEN + 1];
+  char        iphost[SOCKIPLEN + 1];
+  char       *hostmask;
+  char       *sr = NULL;
+  char       *account_host = NULL;
+  struct Ban *found;
+
+  /* Build nick!user and alternate host names. */
+  ircd_snprintf(0, nu, sizeof(nu), "%s!%s",
+                cli_name(cptr), cli_user(cptr)->username);
+  ircd_ntoa_r(iphost, &cli_ip(cptr));
+
+  /* Check for all three possible hosts:
+   *   - account host
+   *   - fakehost
+   *   - real host
+   * But only if they are set.
+   *  --gix */
+  if(IsAccount(cptr)) {
+    ircd_snprintf(0, tmphost, HOSTLEN, "%s.%s", cli_user(cptr)->account, feature_str(FEAT_HIDDEN_HOST));
+    account_host = tmphost;
+  }
+  if(IsFakeHost(cptr)) {
+    if(HasHiddenHost(cptr)) {
+      sr = cli_user(cptr)->realhost;
+    }
+    else sr = cli_user(cptr)->fakehost;
+  }
+  else if(HasHiddenHost(cptr)) {
+    account_host = NULL;
+    sr = cli_user(cptr)->realhost;
+  }
+
+  /* Walk through ban list. */
+  for (found = NULL; banlist; banlist = banlist->next) {
+    int res;
+    /* If we have found a positive ban already, only consider exceptions. */
+    if (found && !(banlist->flags & BAN_EXCEPTION))
+      continue;
+    /* Compare nick!user portion of ban. */
+    banlist->banstr[banlist->nu_len] = '\0';
+    res = match(banlist->banstr, nu);
+    banlist->banstr[banlist->nu_len] = '@';
+    if (res)
+      continue;
+    /* Compare host portion of ban. */
+    hostmask = banlist->banstr + banlist->nu_len + 1;
+    if (!((banlist->flags & BAN_IPMASK)
+         && ipmask_check(&cli_ip(cptr), &banlist->address, banlist->addrbits))
+        && match(hostmask, cli_user(cptr)->host)
+        && !(account_host && !match(hostmask, account_host))
+        && !(sr && !match(hostmask, sr)))
+        continue;
+    /* If an exception matches, no ban can match. */
+    if (banlist->flags & BAN_EXCEPTION)
+      return NULL;
+    /* Otherwise, remember this ban but keep searching for an exception. */
+    found = banlist;
+  }
+  return found;
+}
+
+/**
+ * This function returns true if the user is banned on the said channel.
+ * This function will check the ban cache if applicable, otherwise will
+ * do the comparisons and cache the result.
+ *
+ * @param[in] member The Membership to test for banned-ness.
+ * @return Non-zero if the member is banned, zero if not.
+ */
+static int is_banned(struct Membership* member)
+{
+  if (IsBanValid(member))
+    return IsBanned(member);
+
+  SetBanValid(member);
+  if (find_ban(member->user, member->channel->banlist)) {
+    SetBanned(member);
+    return 1;
+  } else {
+    ClearBanned(member);
+    return 0;
+  }
+}
+
+/** add a user to a channel.
+ * adds a user to a channel by adding another link to the channels member
+ * chain.
+ *
+ * @param chptr The channel to add to.
+ * @param who   The user to add.
+ * @param flags The flags the user gets initially.
+ * @param oplevel The oplevel the user starts with.
+ */
+void add_user_to_channel(struct Channel* chptr, struct Client* who,
+                                unsigned int flags, int oplevel)
+{
+  assert(0 != chptr);
+  assert(0 != who);
+
+  if (cli_user(who)) {
+   
+    struct Membership* member = membershipFreeList;
+    if (member)
+      membershipFreeList = member->next_member;
+    else {
+      member = (struct Membership*) MyMalloc(sizeof(struct Membership));
+      ++membershipAllocCount;
+    }
+
+    assert(0 != member);
+    member->user         = who;
+    member->channel      = chptr;
+    member->status       = flags;
+    SetOpLevel(member, oplevel);
+
+    member->next_member  = chptr->members;
+    if (member->next_member)
+      member->next_member->prev_member = member;
+    member->prev_member  = 0; 
+    chptr->members       = member;
+
+    member->next_channel = (cli_user(who))->channel;
+    if (member->next_channel)
+      member->next_channel->prev_channel = member;
+    member->prev_channel = 0;
+    (cli_user(who))->channel = member;
+
+    if (chptr->destruct_event)
+      remove_destruct_event(chptr);
+    ++chptr->users;
+    ++((cli_user(who))->joined);
+  }
+}
+
+/** Remove a person from a channel, given their Membership*
+ *
+ * @param member A member of a channel.
+ *
+ * @returns true if there are more people in the channel.
+ */
+static int remove_member_from_channel(struct Membership* member)
+{
+  struct Channel* chptr;
+  assert(0 != member);
+  chptr = member->channel;
+  /*
+   * unlink channel member list
+   */
+  if (member->next_member)
+    member->next_member->prev_member = member->prev_member;
+  if (member->prev_member)
+    member->prev_member->next_member = member->next_member;
+  else
+    member->channel->members = member->next_member; 
+
+  /*
+   * If this is the last delayed-join user, may have to clear WASDELJOINS.
+   */
+  if (IsDelayedJoin(member))
+    CheckDelayedJoins(chptr);
+
+  /*
+   * unlink client channel list
+   */
+  if (member->next_channel)
+    member->next_channel->prev_channel = member->prev_channel;
+  if (member->prev_channel)
+    member->prev_channel->next_channel = member->next_channel;
+  else
+    (cli_user(member->user))->channel = member->next_channel;
+
+  --(cli_user(member->user))->joined;
+
+  member->next_member = membershipFreeList;
+  membershipFreeList = member;
+
+  return sub1_from_channel(chptr);
+}
+
+/** Check if all the remaining members on the channel are zombies
+ *
+ * @returns False if the channel has any non zombie members, True otherwise.
+ * @see \ref zombie
+ */
+static int channel_all_zombies(struct Channel* chptr)
+{
+  struct Membership* member;
+
+  /* Though, there are no real users we pretend this channel to have members
+   * to protect it from being destroyed.
+   */
+  if(chptr->mode.mode & MODE_PERSIST)
+    return 0;
+
+  for (member = chptr->members; member; member = member->next_member) {
+    if (!IsZombie(member))
+      return 0;
+  }
+  return 1;
+}
+      
+
+/** Remove a user from a channel
+ * This is the generic entry point for removing a user from a channel, this
+ * function will remove the client from the channel, and destroy the channel
+ * if there are no more normal users left.
+ *
+ * @param cptr         The client
+ * @param chptr                The channel
+ */
+void remove_user_from_channel(struct Client* cptr, struct Channel* chptr)
+{
+  
+  struct Membership* member;
+  assert(0 != chptr);
+
+  if ((member = find_member_link(chptr, cptr))) {
+    if (remove_member_from_channel(member)) {
+      if (channel_all_zombies(chptr)) {
+        /*
+         * XXX - this looks dangerous but isn't if we got the referential
+         * integrity right for channels
+         */
+        while (remove_member_from_channel(chptr->members))
+          ;
+      }
+    }
+  }
+}
+
+/** Remove a user from all channels they are on.
+ *
+ * This function removes a user from all channels they are on.
+ *
+ * @param cptr The client to remove.
+ */
+void remove_user_from_all_channels(struct Client* cptr)
+{
+  struct Membership* chan;
+  assert(0 != cptr);
+  assert(0 != cli_user(cptr));
+
+  while ((chan = (cli_user(cptr))->channel))
+    remove_user_from_channel(cptr, chan->channel);
+}
+
+/** Check if this user is a legitimate chanop
+ *
+ * @param cptr Client to check
+ * @param chptr        Channel to check
+ *
+ * @returns True if the user is a chanop (And not a zombie), False otherwise.
+ * @see \ref zombie
+ */
+int is_chan_op(struct Client *cptr, struct Channel *chptr)
+{
+  struct Membership* member;
+  assert(chptr);
+  if ((member = find_member_link(chptr, cptr)))
+    return (!IsZombie(member) && IsChanOp(member));
+
+  return 0;
+}
+
+/** Check if a user is a Zombie on a specific channel.
+ *
+ * @param cptr         The client to check.
+ * @param chptr                The channel to check.
+ *
+ * @returns True if the client (cptr) is a zombie on the channel (chptr),
+ *         False otherwise.
+ *
+ * @see \ref zombie
+ */
+int is_zombie(struct Client *cptr, struct Channel *chptr)
+{
+  struct Membership* member;
+
+  assert(0 != chptr);
+
+  if ((member = find_member_link(chptr, cptr)))
+      return IsZombie(member);
+  return 0;
+}
+
+/** Returns if a user has voice on a channel.
+ *
+ * @param cptr         The client
+ * @param chptr        The channel
+ *
+ * @returns True if the client (cptr) is voiced on (chptr) and is not a zombie.
+ * @see \ref zombie
+ */
+int has_voice(struct Client* cptr, struct Channel* chptr)
+{
+  struct Membership* member;
+
+  assert(0 != chptr);
+  if ((member = find_member_link(chptr, cptr)))
+    return (!IsZombie(member) && HasVoice(member));
+
+  return 0;
+}
+
+/** Can this member send to a channel
+ *
+ * A user can speak on a channel iff:
+ * <ol>
+ *  <li> They didn't use the Apass to gain ops.
+ *  <li> They are op'd or voice'd.
+ *  <li> You aren't banned.
+ *  <li> The channel isn't +m
+ *  <li> The channel isn't +n or you are on the channel.
+ * </ol>
+ *
+ * This function will optionally reveal a user on a delayed join channel if
+ * they are allowed to send to the channel.
+ *
+ * @param member       The membership of the user
+ * @param reveal       If true, the user will be "revealed" on a delayed
+ *                     joined channel.
+ *
+ * @returns True if the client can speak on the channel.
+ */
+int member_can_send_to_channel(struct Membership* member, int reveal)
+{
+  assert(0 != member);
+
+  /* Do not check for users on other servers: This should be a
+   * temporary desynch, or maybe they are on an older server, but
+   * we do not want to send ERR_CANNOTSENDTOCHAN more than once.
+   * Also allow XtraOps to be always able to speak.
+   */
+  if (!MyUser(member->user) || IsXtraOp(member->user))
+  {
+    if (IsDelayedJoin(member) && !IsInvisibleJoin(member) && reveal)
+      RevealDelayedJoin(member);
+    return 1;
+  }
+
+  /* Discourage using the Apass to get op.  They should use the Upass. */
+  if (IsChannelManager(member) && member->channel->mode.apass[0])
+    return 0;
+
+  /* If you have voice or ops, you can speak. */
+  if (IsVoicedOrOpped(member))
+    return 1;
+
+  /*
+   * If it's moderated, and you aren't a privileged user, you can't
+   * speak.
+   */
+  if (member->channel->mode.mode & MODE_MODERATED)
+    return 0;
+
+  /* If only logged in users may join and you're not one, you can't speak. */
+  if (member->channel->mode.mode & MODE_REGONLY && !IsAccount(member->user))
+    return 0;
+
+  /* If you're banned then you can't speak either. */
+  if (is_banned(member))
+    return 0;
+
+  if (IsDelayedJoin(member) && reveal && !IsInvisibleJoin(member))
+    RevealDelayedJoin(member);
+
+  return 1;
+}
+
+/** Check if a client can send to a channel.
+ *
+ * Has the added check over member_can_send_to_channel() of servers can
+ * always speak.
+ *
+ * @param cptr The client to check
+ * @param chptr        The channel to check
+ * @param reveal If the user should be revealed (see 
+ *             member_can_send_to_channel())
+ *
+ * @returns true if the client is allowed to speak on the channel, false 
+ *             otherwise
+ *
+ * @see member_can_send_to_channel()
+ */
+int client_can_send_to_channel(struct Client *cptr, struct Channel *chptr, int reveal)
+{
+  struct Membership *member;
+  assert(0 != cptr); 
+  /*
+   * Servers and extra ops can always speak on channels.
+   */
+  if (IsServer(cptr) || IsXtraOp(cptr))
+    return 1;
+
+  member = find_channel_member(cptr, chptr);
+
+  /*
+   * You can't speak if you're off channel, and it is +n (no external messages)
+   * or +m (moderated).
+   */
+  if (!member) {
+    if ((chptr->mode.mode & (MODE_NOPRIVMSGS|MODE_MODERATED)) ||
+       ((chptr->mode.mode & MODE_REGONLY) && !IsAccount(cptr)))
+      return 0;
+    else
+      return !find_ban(cptr, chptr->banlist);
+  }
+  return member_can_send_to_channel(member, reveal);
+}
+
+/** Returns the name of a channel that prevents the user from changing nick.
+ * if a member and not (opped or voiced) and (banned or moderated), return
+ * the name of the first channel banned on.
+ *
+ * @param cptr         The client
+ *
+ * @returns the name of the first channel banned on, or NULL if the user
+ *          can change nicks.
+ */
+const char* find_no_nickchange_channel(struct Client* cptr)
+{
+  if (MyUser(cptr)) {
+    struct Membership* member;
+    for (member = (cli_user(cptr))->channel; member;
+        member = member->next_channel) {
+      if (IsVoicedOrOpped(member))
+        continue;
+      if ((member->channel->mode.mode & MODE_MODERATED)
+          || (member->channel->mode.mode & MODE_REGONLY && !IsAccount(cptr))
+          || is_banned(member))
+        return member->channel->chname;
+    }
+  }
+  return 0;
+}
+
+
+/** Fill mbuf/pbuf with modes from chptr
+ * write the "simple" list of channel modes for channel chptr onto buffer mbuf
+ * with the parameters in pbuf as visible by cptr.
+ *
+ * This function will hide keys from non-op'd, non-server clients.
+ *
+ * @param cptr The client to generate the mode for.
+ * @param mbuf The buffer to write the modes into.
+ * @param pbuf  The buffer to write the mode parameters into.
+ * @param buflen The length of the buffers.
+ * @param chptr        The channel to get the modes from.
+ * @param member The membership of this client on this channel (or NULL
+ *             if this client isn't on this channel)
+ *
+ */
+void channel_modes(struct Client *cptr, char *mbuf, char *pbuf, int buflen,
+                          struct Channel *chptr, struct Membership *member)
+{
+  int previous_parameter = 0;
+
+  assert(0 != mbuf);
+  assert(0 != pbuf);
+  assert(0 != chptr);
+
+  *mbuf++ = '+';
+  if (chptr->mode.mode & MODE_SECRET)
+    *mbuf++ = 's';
+  else if (chptr->mode.mode & MODE_PRIVATE)
+    *mbuf++ = 'p';
+  if (chptr->mode.mode & MODE_MODERATED)
+    *mbuf++ = 'm';
+  if (chptr->mode.mode & MODE_TOPICLIMIT)
+    *mbuf++ = 't';
+  if (chptr->mode.mode & MODE_INVITEONLY)
+    *mbuf++ = 'i';
+  if (chptr->mode.mode & MODE_NOPRIVMSGS)
+    *mbuf++ = 'n';
+  if (chptr->mode.mode & MODE_REGONLY)
+    *mbuf++ = 'r';
+  if (chptr->mode.mode & MODE_DELJOINS)
+    *mbuf++ = 'D';
+  else if (MyUser(cptr) && (chptr->mode.mode & MODE_WASDELJOINS))
+    *mbuf++ = 'd';
+  if (chptr->mode.mode & MODE_NOCOLOUR)
+    *mbuf++ = 'c';
+  if (chptr->mode.mode & MODE_NOCTCP)
+    *mbuf++ = 'C';
+  if (chptr->mode.mode & MODE_PERSIST)
+    *mbuf++ = 'z';
+  if (chptr->mode.mode & MODE_REGISTERED)
+    *mbuf++ = 'R';
+  if (chptr->mode.mode & MODE_NONOTICE)
+    *mbuf++ = 'N';
+  if (chptr->mode.mode & MODE_NOAMSGS)
+    *mbuf++ = 'M';
+  if (chptr->mode.mode & MODE_QUARANTINE)
+    *mbuf++ = 'Q';
+  if (chptr->mode.limit) {
+    *mbuf++ = 'l';
+    ircd_snprintf(0, pbuf, buflen, "%u", chptr->mode.limit);
+    previous_parameter = 1;
+  }
+  if (chptr->mode.access) {
+    *mbuf++ = 'a';
+    if (previous_parameter)
+      strcat(pbuf, " ");
+    ircd_snprintf(0, pbuf, buflen, "%u", chptr->mode.access);
+    previous_parameter = 1;
+  }
+  if (*chptr->mode.altchan) {
+    *mbuf++ = 'F';
+    if (previous_parameter)
+      strcat(pbuf, " ");
+    strcat(pbuf, chptr->mode.altchan);
+    previous_parameter = 1;
+  }
+  if (*chptr->mode.key) {
+    *mbuf++ = 'k';
+    if (previous_parameter)
+      strcat(pbuf, " ");
+    if (is_chan_op(cptr, chptr) || IsServer(cptr) || IsOper(cptr)) {
+      strcat(pbuf, chptr->mode.key);
+    } else
+      strcat(pbuf, "*");
+    previous_parameter = 1;
+  }
+  if (*chptr->mode.apass) {
+    *mbuf++ = 'A';
+    if (previous_parameter)
+      strcat(pbuf, " ");
+    if (IsServer(cptr) || IsOper(cptr)) {
+      strcat(pbuf, chptr->mode.apass);
+    } else
+      strcat(pbuf, "*");
+    previous_parameter = 1;
+  }
+  if (*chptr->mode.upass) {
+    *mbuf++ = 'U';
+    if (previous_parameter)
+      strcat(pbuf, " ");
+    if (IsServer(cptr) || (member && IsChanOp(member) && OpLevel(member) == 0) || IsOper(cptr)) {
+      strcat(pbuf, chptr->mode.upass);
+    } else
+      strcat(pbuf, "*");
+  }
+  *mbuf = '\0';
+}
+
+/** Compare two members oplevel
+ *
+ * @param mp1  Pointer to a pointer to a membership
+ * @param mp2  Pointer to a pointer to a membership
+ *
+ * @returns 0 if equal, -1 if mp1 is lower, +1 otherwise.
+ *
+ * Used for qsort(3).
+ */
+int compare_member_oplevel(const void *mp1, const void *mp2)
+{
+  struct Membership const* member1 = *(struct Membership const**)mp1;
+  struct Membership const* member2 = *(struct Membership const**)mp2;
+  if (member1->oplevel == member2->oplevel)
+    return 0;
+  return (member1->oplevel < member2->oplevel) ? -1 : 1;
+}
+
+/* send "cptr" a full list of the modes for channel chptr.
+ *
+ * Sends a BURST line to cptr, bursting all the modes for the channel.
+ *
+ * @param cptr Client pointer
+ * @param chptr        Channel pointer
+ */
+void send_channel_modes(struct Client *cptr, struct Channel *chptr)
+{
+  /* The order in which modes are generated is now mandatory */
+  static unsigned int current_flags[4] =
+      { 0, CHFL_VOICE, CHFL_CHANOP, CHFL_CHANOP | CHFL_VOICE };
+  int                first = 1;
+  int                full  = 1;
+  int                flag_cnt = 0;
+  int                new_mode = 0;
+  size_t             len;
+  struct Membership* member;
+  struct Ban*        lp2;
+  char modebuf[MODEBUFLEN];
+  char parabuf[MODEBUFLEN];
+  struct MsgBuf *mb;
+  int                 number_of_ops = 0;
+  int                 opped_members_index = 0;
+  struct Membership** opped_members = NULL;
+  int                 last_oplevel = 0;
+  int                 send_oplevels = 0;
+
+  assert(0 != cptr);
+  assert(0 != chptr); 
+
+  if (IsLocalChannel(chptr->chname))
+    return;
+
+  member = chptr->members;
+  lp2 = chptr->banlist;
+
+  *modebuf = *parabuf = '\0';
+  channel_modes(cptr, modebuf, parabuf, sizeof(parabuf), chptr, 0);
+
+  for (first = 1; full; first = 0)      /* Loop for multiple messages */
+  {
+    full = 0;                   /* Assume by default we get it
+                                 all in one message */
+
+    /* (Continued) prefix: "<Y> B <channel> <TS>" */
+    /* is there any better way we can do this? */
+    mb = msgq_make(&me, "%C " TOK_BURST " %H %Tu", &me, chptr,
+                  chptr->creationtime);
+
+    if (first && modebuf[1])    /* Add simple modes (Aiklmnpstu)
+                                 if first message */
+    {
+      /* prefix: "<Y> B <channel> <TS>[ <modes>[ <params>]]" */
+      msgq_append(&me, mb, " %s", modebuf);
+
+      if (*parabuf)
+       msgq_append(&me, mb, " %s", parabuf);
+    }
+
+    /*
+     * Attach nicks, comma separated " nick[:modes],nick[:modes],..."
+     *
+     * First find all opless members.
+     * Run 2 times over all members, to group the members with
+     * and without voice together.
+     * Then run 2 times over all opped members (which are ordered
+     * by op-level) to also group voice and non-voice together.
+     */
+    for (first = 1; flag_cnt < 4; new_mode = 1, ++flag_cnt)
+    {
+      while (member)
+      {
+       if (flag_cnt < 2 && IsChanOp(member))
+       {
+         /*
+          * The first loop (to find all non-voice/op), we count the ops.
+          * The second loop (to find all voiced non-ops), store the ops
+          * in a dynamic array.
+          */
+         if (flag_cnt == 0)
+           ++number_of_ops;
+         else
+           opped_members[opped_members_index++] = member;
+          /* We also send oplevels if anyone is below the weakest level.  */
+          if (OpLevel(member) < MAXOPLEVEL)
+            send_oplevels = 1;
+       }
+       /* Only handle the members with the flags that we are interested in. */
+        if ((member->status & CHFL_VOICED_OR_OPPED) == current_flags[flag_cnt])
+       {
+         if (msgq_bufleft(mb) < NUMNICKLEN + 3 + MAXOPLEVELDIGITS)
+           /* The 3 + MAXOPLEVELDIGITS is a possible ",:v999". */
+         {
+           full = 1;           /* Make sure we continue after
+                                  sending it so far */
+           /* Ensure the new BURST line contains the current
+            * ":mode", except when there is no mode yet. */
+           new_mode = (flag_cnt > 0) ? 1 : 0;
+           break;              /* Do not add this member to this message */
+         }
+         msgq_append(&me, mb, "%c%C", first ? ' ' : ',', member->user);
+         first = 0;              /* From now on, use commas to add new nicks */
+
+         /*
+          * Do we have a nick with a new mode ?
+          * Or are we starting a new BURST line?
+          */
+         if (new_mode)
+         {
+           /*
+            * This means we are at the _first_ member that has only
+            * voice, or the first member that has only ops, or the
+            * first member that has voice and ops (so we get here
+            * at most three times, plus once for every start of
+            * a continued BURST line where only these modes is current.
+            * In the two cases where the current mode includes ops,
+            * we need to add the _absolute_ value of the oplevel to the mode.
+            */
+           char tbuf[3 + MAXOPLEVELDIGITS] = ":";
+           int loc = 1;
+
+           if (HasVoice(member))       /* flag_cnt == 1 or 3 */
+             tbuf[loc++] = 'v';
+           if (IsChanOp(member))       /* flag_cnt == 2 or 3 */
+           {
+              /* append the absolute value of the oplevel */
+              if (send_oplevels)
+                loc += ircd_snprintf(0, tbuf + loc, sizeof(tbuf) - loc, "%u", last_oplevel = member->oplevel);
+              else
+                tbuf[loc++] = 'o';
+           }
+           tbuf[loc] = '\0';
+           msgq_append(&me, mb, tbuf);
+           new_mode = 0;
+         }
+         else if (send_oplevels && flag_cnt > 1 && last_oplevel != member->oplevel)
+         {
+           /*
+            * This can't be the first member of a (continued) BURST
+            * message because then either flag_cnt == 0 or new_mode == 1
+            * Now we need to append the incremental value of the oplevel.
+            */
+            char tbuf[2 + MAXOPLEVELDIGITS];
+           ircd_snprintf(0, tbuf, sizeof(tbuf), ":%u", member->oplevel - last_oplevel);
+           last_oplevel = member->oplevel;
+           msgq_append(&me, mb, tbuf);
+         }
+       }
+       /* Go to the next `member'. */
+       if (flag_cnt < 2)
+         member = member->next_member;
+       else
+         member = opped_members[++opped_members_index];
+      }
+      if (full)
+       break;
+
+      /* Point `member' at the start of the list again. */
+      if (flag_cnt == 0)
+      {
+       member = chptr->members;
+       /* Now, after one loop, we know the number of ops and can
+        * allocate the dynamic array with pointer to the ops. */
+       opped_members = (struct Membership**)
+         MyMalloc((number_of_ops + 1) * sizeof(struct Membership*));
+       opped_members[number_of_ops] = NULL;    /* Needed for loop termination */
+      }
+      else
+      {
+       /* At the end of the second loop, sort the opped members with
+        * increasing op-level, so that we will output them in the
+        * correct order (and all op-level increments stay positive) */
+       if (flag_cnt == 1)
+         qsort(opped_members, number_of_ops,
+               sizeof(struct Membership*), compare_member_oplevel);
+       /* The third and fourth loop run only over the opped members. */
+       member = opped_members[(opped_members_index = 0)];
+      }
+
+    } /* loop over 0,+v,+o,+ov */
+
+    if (!full)
+    {
+      /* Attach all bans, space separated " :%ban ban ..." */
+      for (first = 2; lp2; lp2 = lp2->next)
+      {
+        len = strlen(lp2->banstr);
+       if (msgq_bufleft(mb) < len + 1 + first)
+          /* The +1 stands for the added ' '.
+           * The +first stands for the added ":%".
+           */
+        {
+          full = 1;
+          break;
+        }
+       msgq_append(&me, mb, " %s%s", first ? ":%" : "",
+                   lp2->banstr);
+       first = 0;
+      }
+    }
+
+    send_buffer(cptr, mb, 0);  /* Send this message */
+    msgq_clean(mb);
+  }                             /* Continue when there was something
+                                 that didn't fit (full==1) */
+  if (opped_members)
+    MyFree(opped_members);
+  if (feature_bool(FEAT_TOPIC_BURST) && (chptr->topic[0] != '\0'))
+      sendcmdto_one(&me, CMD_TOPIC, cptr, "%H %Tu %Tu :%s", chptr,
+                    chptr->creationtime, chptr->topic_time, chptr->topic);
+}
+
+/** Canonify a mask.
+ * pretty_mask
+ *
+ * @author Carlo Wood (Run), 
+ * 05 Oct 1998.
+ *
+ * When the nick is longer then NICKLEN, it is cut off (its an error of course).
+ * When the user name or host name are too long (USERLEN and HOSTLEN
+ * respectively) then they are cut off at the start with a '*'.
+ *
+ * The following transformations are made:
+ *
+ * 1)   xxx             -> nick!*@*
+ * 2)   xxx.xxx         -> *!*\@host
+ * 3)   xxx\!yyy         -> nick!user\@*
+ * 4)   xxx\@yyy         -> *!user\@host
+ * 5)   xxx!yyy\@zzz     -> nick!user\@host
+ *
+ * @param mask The uncanonified mask.
+ * @returns The updated mask in a static buffer.
+ */
+char *pretty_mask(char *mask)
+{
+  static char star[2] = { '*', 0 };
+  static char retmask[NICKLEN + USERLEN + HOSTLEN + 3];
+  char *last_dot = NULL;
+  char *ptr;
+
+  /* Case 1: default */
+  char *nick = mask;
+  char *user = star;
+  char *host = star;
+
+  /* Do a _single_ pass through the characters of the mask: */
+  for (ptr = mask; *ptr; ++ptr)
+  {
+    if (*ptr == '!')
+    {
+      /* Case 3 or 5: Found first '!' (without finding a '@' yet) */
+      user = ++ptr;
+      host = star;
+    }
+    else if (*ptr == '@')
+    {
+      /* Case 4: Found last '@' (without finding a '!' yet) */
+      nick = star;
+      user = mask;
+      host = ++ptr;
+    }
+    else if (*ptr == '.' || *ptr == ':')
+    {
+      /* Case 2: Found character specific to IP or hostname (without
+       * finding a '!' or '@' yet) */
+      last_dot = ptr;
+      continue;
+    }
+    else
+      continue;
+    for (; *ptr; ++ptr)
+    {
+      if (*ptr == '@')
+      {
+        /* Case 4 or 5: Found last '@' */
+        host = ptr + 1;
+      }
+    }
+    break;
+  }
+  if (user == star && last_dot)
+  {
+    /* Case 2: */
+    nick = star;
+    user = star;
+    host = mask;
+  }
+  /* Check lengths */
+  if (nick != star)
+  {
+    char *nick_end = (user != star) ? user - 1 : ptr;
+    if (nick_end - nick > NICKLEN)
+      nick[NICKLEN] = 0;
+    *nick_end = 0;
+  }
+  if (user != star)
+  {
+    char *user_end = (host != star) ? host - 1 : ptr;
+    if (user_end - user > USERLEN)
+    {
+      user = user_end - USERLEN;
+      *user = '*';
+    }
+    *user_end = 0;
+  }
+  if (host != star && ptr - host > HOSTLEN)
+  {
+    host = ptr - HOSTLEN;
+    *host = '*';
+  }
+  ircd_snprintf(0, retmask, sizeof(retmask), "%s!%s@%s", nick, user, host);
+  return retmask;
+}
+
+/** send a banlist to a client for a channel
+ *
+ * @param cptr Client to send the banlist to.
+ * @param chptr        Channel whose banlist to send.
+ */
+static void send_ban_list(struct Client* cptr, struct Channel* chptr)
+{
+  struct Ban* lp;
+
+  assert(0 != cptr);
+  assert(0 != chptr);
+
+  for (lp = chptr->banlist; lp; lp = lp->next) {
+    if(!(lp->flags & BAN_EXCEPTION))
+        send_reply(cptr, RPL_BANLIST, chptr->chname, lp->banstr,
+                   lp->who, lp->when);
+  }
+
+  send_reply(cptr, RPL_ENDOFBANLIST, chptr->chname);
+}
+
+/** send an exceptionlist to a client for a channel
+ *
+ * @param cptr Client to send the exceptionlist to.
+ * @param chptr        Channel whose exceptionlist to send.
+ */
+static void send_exception_list(struct Client* cptr, struct Channel* chptr)
+{
+  struct Ban* lp;
+
+  assert(0 != cptr);
+  assert(0 != chptr);
+
+  for (lp = chptr->banlist; lp; lp = lp->next) {
+    if(lp->flags & BAN_EXCEPTION)
+        send_reply(cptr, RPL_EXCEPTIONLIST, chptr->chname, lp->banstr,
+                   lp->who, lp->when);
+  }
+
+  send_reply(cptr, RPL_ENDOFEXCEPTIONLIST, chptr->chname);
+}
+
+/** Get a channel block, creating if necessary.
+ *  Get Channel block for chname (and allocate a new channel
+ *  block, if it didn't exists before).
+ *
+ * @param cptr         Client joining the channel.
+ * @param chname       The name of the channel to join.
+ * @param flag         set to CGT_CREATE to create the channel if it doesn't 
+ *                     exist
+ *
+ * @returns NULL if the channel is invalid, doesn't exist and CGT_CREATE 
+ *     wasn't specified or a pointer to the channel structure
+ */
+struct Channel *get_channel(struct Client *cptr, char *chname, ChannelGetType flag)
+{
+  struct Channel *chptr;
+  int len;
+
+  if (EmptyString(chname))
+    return NULL;
+
+  len = strlen(chname);
+  if (MyUser(cptr) && len > CHANNELLEN)
+  {
+    len = CHANNELLEN;
+    *(chname + CHANNELLEN) = '\0';
+  }
+  if ((chptr = FindChannel(chname)))
+    return (chptr);
+  if (flag == CGT_CREATE)
+  {
+    chptr = (struct Channel*) MyMalloc(sizeof(struct Channel) + len);
+    assert(0 != chptr);
+    ++UserStats.channels;
+    memset(chptr, 0, sizeof(struct Channel));
+    strcpy(chptr->chname, chname);
+    if (GlobalChannelList)
+      GlobalChannelList->prev = chptr;
+    chptr->prev = NULL;
+    chptr->next = GlobalChannelList;
+    chptr->creationtime = MyUser(cptr) ? TStime() : (time_t) 0;
+    GlobalChannelList = chptr;
+    hAddChannel(chptr);
+  }
+  return chptr;
+}
+
+/** invite a user to a channel.
+ *
+ * Adds an invite for a user to a channel.  Limits the number of invites
+ * to FEAT_MAXCHANNELSPERUSER.  Does not sent notification to the user.
+ *
+ * @param cptr The client to be invited.
+ * @param chptr        The channel to be invited to.
+ */
+void add_invite(struct Client *cptr, struct Channel *chptr)
+{
+  struct SLink *inv, **tmp;
+  unsigned int maxchans;
+
+  del_invite(cptr, chptr);
+  /*
+   * Delete last link in chain if the list is max length
+   */
+  assert(list_length((cli_user(cptr))->invited) == (cli_user(cptr))->invites);
+  maxchans = cli_confs(cptr)->value.aconf ? ConfMaxChannels(cli_confs(cptr)->value.aconf) : feature_int(FEAT_MAXCHANNELSPERUSER);
+  if (((cli_user(cptr))->invites >= maxchans && !HasPriv(cptr, PRIV_CHAN_LIMIT)) || cli_user(cptr)->invites > 100) /* Hard limit of 100. */
+    del_invite(cptr, (cli_user(cptr))->invited->value.chptr);
+  /*
+   * Add client to channel invite list
+   */
+  inv = make_link();
+  inv->value.cptr = cptr;
+  inv->next = chptr->invites;
+  chptr->invites = inv;
+  /*
+   * Add channel to the end of the client invite list
+   */
+  for (tmp = &((cli_user(cptr))->invited); *tmp; tmp = &((*tmp)->next));
+  inv = make_link();
+  inv->value.chptr = chptr;
+  inv->next = NULL;
+  (*tmp) = inv;
+  (cli_user(cptr))->invites++;
+}
+
+/** Delete an invite
+ * Delete Invite block from channel invite list and client invite list
+ *
+ * @param cptr Client pointer
+ * @param chptr        Channel pointer
+ */
+void del_invite(struct Client *cptr, struct Channel *chptr)
+{
+  struct SLink **inv, *tmp;
+
+  for (inv = &(chptr->invites); (tmp = *inv); inv = &tmp->next)
+    if (tmp->value.cptr == cptr)
+    {
+      *inv = tmp->next;
+      free_link(tmp);
+      tmp = 0;
+      (cli_user(cptr))->invites--;
+      break;
+    }
+
+  for (inv = &((cli_user(cptr))->invited); (tmp = *inv); inv = &tmp->next)
+    if (tmp->value.chptr == chptr)
+    {
+      *inv = tmp->next;
+      free_link(tmp);
+      tmp = 0;
+      break;
+    }
+}
+
+/** @page zombie Explanation of Zombies
+ *
+ * Synopsis:
+ *
+ * A channel member is turned into a zombie when he is kicked from a
+ * channel but his server has not acknowledged the kick.  Servers that
+ * see the member as a zombie can accept actions he performed before
+ * being kicked, without allowing chanop operations from outsiders or
+ * desyncing the network.
+ *
+ * Consider:
+ * <pre>
+ *                     client
+ *                       |
+ *                       c
+ *                       |
+ *     X --a--> A --b--> B --d--> D
+ *                       |
+ *                      who
+ * </pre>
+ *
+ * Where `who' is being KICK-ed by a "KICK" message received by server 'A'
+ * via 'a', or on server 'B' via either 'b' or 'c', or on server D via 'd'.
+ *
+ * a) On server A : set CHFL_ZOMBIE for `who' (lp) and pass on the KICK.
+ *    Remove the user immediately when no users are left on the channel.
+ * b) On server B : remove the user (who/lp) from the channel, send a
+ *    PART upstream (to A) and pass on the KICK.
+ * c) KICKed by `client'; On server B : remove the user (who/lp) from the
+ *    channel, and pass on the KICK.
+ * d) On server D : remove the user (who/lp) from the channel, and pass on
+ *    the KICK.
+ *
+ * Note:
+ * - Setting the ZOMBIE flag never hurts, we either remove the
+ *   client after that or we don't.
+ * - The KICK message was already passed on, as should be in all cases.
+ * - `who' is removed in all cases except case a) when users are left.
+ * - A PART is only sent upstream in case b).
+ *
+ * 2 aug 97:
+ * <pre>
+ *              6
+ *              |
+ *  1 --- 2 --- 3 --- 4 --- 5
+ *        |           |
+ *      kicker       who
+ * </pre>
+ *
+ * We also need to turn 'who' into a zombie on servers 1 and 6,
+ * because a KICK from 'who' (kicking someone else in that direction)
+ * can arrive there afterward - which should not be bounced itself.
+ * Therefore case a) also applies for servers 1 and 6.
+ *
+ * --Run
+ */
+
+/** Turn a user on a channel into a zombie
+ * This function turns a user into a zombie (see \ref zombie)
+ *
+ * @param member  The structure representing this user on this channel.
+ * @param who    The client that is being kicked.
+ * @param cptr   The connection the kick came from.
+ * @param sptr    The client that is doing the kicking.
+ * @param chptr          The channel the user is being kicked from.
+ */
+void make_zombie(struct Membership* member, struct Client* who, 
+               struct Client* cptr, struct Client* sptr, struct Channel* chptr)
+{
+  assert(0 != member);
+  assert(0 != who);
+  assert(0 != cptr);
+  assert(0 != chptr);
+
+  /* Default for case a): */
+  SetZombie(member);
+
+  /* Case b) or c) ?: */
+  if (MyUser(who))      /* server 4 */
+  {
+    if (IsServer(cptr)) /* Case b) ? */
+      sendcmdto_one(who, CMD_PART, cptr, "%H", chptr);
+    remove_user_from_channel(who, chptr);
+    return;
+  }
+  if (cli_from(who) == cptr)        /* True on servers 1, 5 and 6 */
+  {
+    struct Client *acptr = IsServer(sptr) ? sptr : (cli_user(sptr))->server;
+    for (; acptr != &me; acptr = (cli_serv(acptr))->up)
+      if (acptr == (cli_user(who))->server)   /* Case d) (server 5) */
+      {
+        remove_user_from_channel(who, chptr);
+        return;
+      }
+  }
+
+  /* Case a) (servers 1, 2, 3 and 6) */
+  if (channel_all_zombies(chptr))
+    remove_user_from_channel(who, chptr);
+
+  /* XXX Can't actually call Debug here; if the channel is all zombies,
+   * chptr will no longer exist when we get here.
+  Debug((DEBUG_INFO, "%s is now a zombie on %s", who->name, chptr->chname));
+  */
+}
+
+/** returns the number of zombies on a channel
+ * @param chptr        Channel to count zombies in.
+ *
+ * @returns The number of zombies on the channel.
+ */
+int number_of_zombies(struct Channel *chptr)
+{
+  struct Membership* member;
+  int                count = 0;
+
+  assert(0 != chptr);
+  for (member = chptr->members; member; member = member->next_member) {
+    if (IsZombie(member))
+      ++count;
+  }
+  return count;
+}
+
+/** Concatenate some strings together.
+ * This helper function builds an argument string in strptr, consisting
+ * of the original string, a space, and str1 and str2 concatenated (if,
+ * of course, str2 is not NULL)
+ *
+ * @param strptr       The buffer to concatenate into
+ * @param strptr_i     modified offset to the position to modify
+ * @param str1         The string to concatenate from.
+ * @param str2         The second string to contatenate from.
+ * @param c            Charactor to separate the string from str1 and str2.
+ */
+static void
+build_string(char *strptr, int *strptr_i, const char *str1,
+             const char *str2, char c)
+{
+  if (c)
+    strptr[(*strptr_i)++] = c;
+
+  while (*str1)
+    strptr[(*strptr_i)++] = *(str1++);
+
+  if (str2)
+    while (*str2)
+      strptr[(*strptr_i)++] = *(str2++);
+
+  strptr[(*strptr_i)] = '\0';
+}
+
+/** Flush out the modes
+ * This is the workhorse of our ModeBuf suite; this actually generates the
+ * output MODE commands, HACK notices, or whatever.  It's pretty complicated.
+ *
+ * @param mbuf The mode buffer to flush
+ * @param all  If true, flush all modes, otherwise leave partial modes in the
+ *             buffer.
+ *
+ * @returns 0
+ */
+static int
+modebuf_flush_int(struct ModeBuf *mbuf, int all)
+{
+  /* we only need the flags that don't take args right now */
+  static int flags[] = {
+/*  MODE_CHANOP,       'o', */
+/*  MODE_VOICE,                'v', */
+    MODE_PRIVATE,      'p',
+    MODE_SECRET,       's',
+    MODE_MODERATED,    'm',
+    MODE_TOPICLIMIT,   't',
+    MODE_INVITEONLY,   'i',
+    MODE_NOPRIVMSGS,   'n',
+    MODE_REGONLY,      'r',
+    MODE_DELJOINS,      'D',
+    MODE_REGISTERED,   'R',
+/*  MODE_KEY,          'k', */
+/*  MODE_BAN,          'b', */
+    MODE_LIMIT,                'l',
+/*  MODE_APASS,                'A', */
+/*  MODE_UPASS,                'U', */
+    MODE_PERSIST,      'z',
+    MODE_NOCOLOUR,  'c',
+    MODE_NOCTCP,    'C',
+/*  MODE_EXCEPTION, 'e', */
+/*  MODE_ALTCHAN,   'F', */
+    MODE_ACCESS,    'a',
+    MODE_NOAMSGS,   'M',
+       MODE_NONOTICE,  'N',
+       MODE_QUARANTINE,  'Q',
+    0x0, 0x0
+  };
+  static int local_flags[] = {
+    MODE_WASDELJOINS,   'd',
+    0x0, 0x0
+  };
+  int i;
+  int *flag_p;
+
+  struct Client *app_source; /* where the MODE appears to come from */
+
+  char addbuf[20], addbuf_local[20]; /* accumulates +psmtin, etc. */
+  int addbuf_i = 0, addbuf_local_i = 0;
+  char rembuf[20], rembuf_local[20]; /* accumulates -psmtin, etc. */
+  int rembuf_i = 0, rembuf_local_i = 0;
+  char *bufptr; /* we make use of indirection to simplify the code */
+  int *bufptr_i;
+
+  char addstr[BUFSIZE]; /* accumulates MODE parameters to add */
+  int addstr_i;
+  char remstr[BUFSIZE]; /* accumulates MODE parameters to remove */
+  int remstr_i;
+  char *strptr; /* more indirection to simplify the code */
+  int *strptr_i;
+
+  int totalbuflen = BUFSIZE - 200; /* fuzz factor -- don't overrun buffer! */
+  int tmp;
+
+  char limitbuf[20],accessbuf[20]; /* convert limits to strings */
+
+  unsigned int limitdel = MODE_LIMIT;
+  unsigned int accessdel = MODE_ACCESS;
+
+  assert(0 != mbuf);
+
+  /* If the ModeBuf is empty, we have nothing to do */
+  if (mbuf->mb_add == 0 && mbuf->mb_rem == 0 && mbuf->mb_count == 0)
+    return 0;
+
+  /* Ok, if we were given the OPMODE flag, or its a server, hide the source.
+   */
+  if (feature_bool(FEAT_HIS_MODEWHO) &&
+      (mbuf->mb_dest & MODEBUF_DEST_OPMODE ||
+       IsServer(mbuf->mb_source) ||
+       IsMe(mbuf->mb_source)))
+    app_source = &his;
+  else
+    app_source = mbuf->mb_source;
+
+  /*
+   * Account for user we're bouncing; we have to get it in on the first
+   * bounced MODE, or we could have problems
+   */
+  if (mbuf->mb_dest & MODEBUF_DEST_DEOP)
+    totalbuflen -= 6; /* numeric nick == 5, plus one space */
+
+  /* Calculate the simple flags */
+  for (flag_p = flags; flag_p[0]; flag_p += 2) {
+    if (*flag_p & mbuf->mb_add)
+      addbuf[addbuf_i++] = flag_p[1];
+    else if (*flag_p & mbuf->mb_rem)
+      rembuf[rembuf_i++] = flag_p[1];
+  }
+
+  /* Some flags may be for local display only. */
+  for (flag_p = local_flags; flag_p[0]; flag_p += 2) {
+    if (*flag_p & mbuf->mb_add)
+      addbuf_local[addbuf_local_i++] = flag_p[1];
+    else if (*flag_p & mbuf->mb_rem)
+      rembuf_local[rembuf_local_i++] = flag_p[1];
+  }
+
+  /* Now go through the modes with arguments... */
+  for (i = 0; i < mbuf->mb_count; i++) {
+    if (MB_TYPE(mbuf, i) & MODE_ADD) { /* adding or removing? */
+      bufptr = addbuf;
+      bufptr_i = &addbuf_i;
+    } else {
+      bufptr = rembuf;
+      bufptr_i = &rembuf_i;
+    }
+
+    if (MB_TYPE(mbuf, i) & (MODE_CHANOP | MODE_VOICE)) {
+      tmp = strlen(cli_name(MB_CLIENT(mbuf, i)));
+
+      if ((totalbuflen - IRCD_MAX(9, tmp)) <= 0) /* don't overflow buffer */
+       MB_TYPE(mbuf, i) |= MODE_SAVE; /* save for later */
+      else {
+       bufptr[(*bufptr_i)++] = MB_TYPE(mbuf, i) & MODE_CHANOP ? 'o' : 'v';
+       totalbuflen -= IRCD_MAX(9, tmp) + 1;
+      }
+    } else if (MB_TYPE(mbuf, i) & (MODE_BAN | MODE_EXCEPTION | MODE_APASS | MODE_UPASS | MODE_ALTCHAN)) {
+      tmp = strlen(MB_STRING(mbuf, i));
+
+      if ((totalbuflen - tmp) <= 0) /* don't overflow buffer */
+       MB_TYPE(mbuf, i) |= MODE_SAVE; /* save for later */
+      else {
+       char mode_char;
+       switch(MB_TYPE(mbuf, i) & (MODE_BAN | MODE_EXCEPTION | MODE_APASS | MODE_UPASS | MODE_ALTCHAN))
+       {
+         case MODE_APASS:
+           mode_char = 'A';
+           break;
+         case MODE_UPASS:
+           mode_char = 'U';
+           break;
+      case MODE_EXCEPTION:
+        mode_char = 'e';
+        break;
+      case MODE_ALTCHAN:
+               mode_char = 'F';
+               break;
+         default:
+           mode_char = 'b';
+           break;
+       }
+       bufptr[(*bufptr_i)++] = mode_char;
+       totalbuflen -= tmp + 1;
+      }
+    } else if (MB_TYPE(mbuf, i) & MODE_KEY) {
+      tmp = (mbuf->mb_dest & MODEBUF_DEST_NOKEY ? 1 :
+            strlen(MB_STRING(mbuf, i)));
+
+      if ((totalbuflen - tmp) <= 0) /* don't overflow buffer */
+       MB_TYPE(mbuf, i) |= MODE_SAVE; /* save for later */
+      else {
+       bufptr[(*bufptr_i)++] = 'k';
+       totalbuflen -= tmp + 1;
+      }
+    } else if (MB_TYPE(mbuf, i) & (MODE_LIMIT)) {
+      /* if it's a limit, we also format the number */
+      ircd_snprintf(0, limitbuf, sizeof(limitbuf), "%u", MB_UINT(mbuf, i));
+
+      tmp = strlen(limitbuf);
+
+      if ((totalbuflen - tmp) <= 0) /* don't overflow buffer */
+       MB_TYPE(mbuf, i) |= MODE_SAVE; /* save for later */
+      else {
+       bufptr[(*bufptr_i)++] = 'l';
+       totalbuflen -= tmp + 1;
+      }
+    } else if (MB_TYPE(mbuf, i) & (MODE_ACCESS)) {
+      /* if it's a limit, we also format the number */
+      ircd_snprintf(0, accessbuf, sizeof(accessbuf), "%u", MB_UINT(mbuf, i));
+
+      tmp = strlen(accessbuf);
+
+      if ((totalbuflen - tmp) <= 0) /* don't overflow buffer */
+       MB_TYPE(mbuf, i) |= MODE_SAVE; /* save for later */
+      else {
+       bufptr[(*bufptr_i)++] = 'a';
+       totalbuflen -= tmp + 1;
+      }
+    }
+  }
+
+  /* terminate the mode strings */
+  addbuf[addbuf_i] = '\0';
+  rembuf[rembuf_i] = '\0';
+  addbuf_local[addbuf_local_i] = '\0';
+  rembuf_local[rembuf_local_i] = '\0';
+
+  /* If we're building a user visible MODE or HACK... */
+  if (mbuf->mb_dest & (MODEBUF_DEST_CHANNEL | MODEBUF_DEST_HACK2 |
+                      MODEBUF_DEST_HACK3   | MODEBUF_DEST_HACK4 |
+                      MODEBUF_DEST_LOG)) {
+    /* Set up the parameter strings */
+    addstr[0] = '\0';
+    addstr_i = 0;
+    remstr[0] = '\0';
+    remstr_i = 0;
+
+    for (i = 0; i < mbuf->mb_count; i++) {
+      if (MB_TYPE(mbuf, i) & MODE_SAVE)
+       continue;
+
+      if (MB_TYPE(mbuf, i) & MODE_ADD) { /* adding or removing? */
+       strptr = addstr;
+       strptr_i = &addstr_i;
+      } else {
+       strptr = remstr;
+       strptr_i = &remstr_i;
+      }
+
+      /* deal with clients... */
+      if (MB_TYPE(mbuf, i) & (MODE_CHANOP | MODE_VOICE))
+       build_string(strptr, strptr_i, cli_name(MB_CLIENT(mbuf, i)), 0, ' ');
+
+      /* deal with bans... */
+      else if (MB_TYPE(mbuf, i) & (MODE_BAN | MODE_EXCEPTION))
+       build_string(strptr, strptr_i, MB_STRING(mbuf, i), 0, ' ');
+
+      /* deal with keys... */
+      else if (MB_TYPE(mbuf, i) & MODE_KEY)
+       build_string(strptr, strptr_i, mbuf->mb_dest & MODEBUF_DEST_NOKEY ?
+                    "*" : MB_STRING(mbuf, i), 0, ' ');
+
+      /* deal with invisible passwords */
+      else if (MB_TYPE(mbuf, i) & (MODE_APASS | MODE_UPASS))
+       build_string(strptr, strptr_i, "*", 0, ' ');
+
+      /*
+       * deal with limit; note we cannot include the limit parameter if we're
+       * removing it
+       */
+      else if ((MB_TYPE(mbuf, i) & (MODE_ADD | MODE_LIMIT)) ==
+              (MODE_ADD | MODE_LIMIT))
+       build_string(strptr, strptr_i, limitbuf, 0, ' ');
+         else if ((MB_TYPE(mbuf, i) & (MODE_ADD | MODE_ACCESS)) ==
+              (MODE_ADD | MODE_ACCESS))
+       build_string(strptr, strptr_i, accessbuf, 0, ' ');
+       
+         else if (MB_TYPE(mbuf, i) & MODE_ALTCHAN)
+       build_string(strptr, strptr_i, MB_STRING(mbuf, i), 0, ' ');
+    }
+
+    /* send the messages off to their destination */
+    if (mbuf->mb_dest & MODEBUF_DEST_HACK2)
+      sendto_opmask_butone(0, SNO_HACK2, "HACK(2): %s MODE %s %s%s%s%s%s%s "
+                          "[%Tu]",
+                           cli_name(feature_bool(FEAT_HIS_SNOTICES) ?
+                                    mbuf->mb_source : app_source),
+                          mbuf->mb_channel->chname,
+                          rembuf_i ? "-" : "", rembuf, addbuf_i ? "+" : "",
+                          addbuf, remstr, addstr,
+                          mbuf->mb_channel->creationtime);
+
+    if (mbuf->mb_dest & MODEBUF_DEST_HACK3)
+      sendto_opmask_butone(0, SNO_HACK3, "BOUNCE or HACK(3): %s MODE %s "
+                          "%s%s%s%s%s%s [%Tu]",
+                           cli_name(feature_bool(FEAT_HIS_SNOTICES) ? 
+                                    mbuf->mb_source : app_source),
+                          mbuf->mb_channel->chname, rembuf_i ? "-" : "",
+                          rembuf, addbuf_i ? "+" : "", addbuf, remstr, addstr,
+                          mbuf->mb_channel->creationtime);
+
+    if (mbuf->mb_dest & MODEBUF_DEST_HACK4)
+      sendto_opmask_butone(0, SNO_HACK4, "HACK(4): %s MODE %s %s%s%s%s%s%s "
+                          "[%Tu]",
+                          cli_name(feature_bool(FEAT_HIS_SNOTICES) ?
+                                    mbuf->mb_source : app_source),
+                          mbuf->mb_channel->chname,
+                          rembuf_i ? "-" : "", rembuf, addbuf_i ? "+" : "",
+                          addbuf, remstr, addstr,
+                          mbuf->mb_channel->creationtime);
+
+    if (mbuf->mb_dest & MODEBUF_DEST_LOG)
+      log_write(LS_OPERMODE, L_INFO, LOG_NOSNOTICE,
+               "%#C OPMODE %H %s%s%s%s%s%s", mbuf->mb_source,
+               mbuf->mb_channel, rembuf_i ? "-" : "", rembuf,
+               addbuf_i ? "+" : "", addbuf, remstr, addstr);
+
+    if (mbuf->mb_dest & MODEBUF_DEST_CHANNEL)
+      sendcmdto_channel_butserv_butone(app_source, CMD_MODE, mbuf->mb_channel, NULL, 0,
+                                       "%H %s%s%s%s%s%s%s%s", mbuf->mb_channel,
+                                       rembuf_i || rembuf_local_i ? "-" : "",
+                                       rembuf, rembuf_local,
+                                       addbuf_i || addbuf_local_i ? "+" : "",
+                                       addbuf, addbuf_local,
+                                       remstr, addstr);
+  }
+
+  /* Now are we supposed to propagate to other servers? */
+  if (mbuf->mb_dest & MODEBUF_DEST_SERVER) {
+    /* set up parameter string */
+    addstr[0] = '\0';
+    addstr_i = 0;
+    remstr[0] = '\0';
+    remstr_i = 0;
+
+    /*
+     * limit is supressed if we're removing it; we have to figure out which
+     * direction is the direction for it to be removed, though...
+     */
+    limitdel |= (mbuf->mb_dest & MODEBUF_DEST_BOUNCE) ? MODE_DEL : MODE_ADD;
+       accessdel |= (mbuf->mb_dest & MODEBUF_DEST_BOUNCE) ? MODE_DEL : MODE_ADD;
+
+    for (i = 0; i < mbuf->mb_count; i++) {
+      if (MB_TYPE(mbuf, i) & MODE_SAVE)
+       continue;
+
+      if (MB_TYPE(mbuf, i) & MODE_ADD) { /* adding or removing? */
+       strptr = addstr;
+       strptr_i = &addstr_i;
+      } else {
+       strptr = remstr;
+       strptr_i = &remstr_i;
+      }
+
+      /* if we're changing oplevels and we know the oplevel, pass it on */
+      if ((MB_TYPE(mbuf, i) & MODE_CHANOP)
+          && MB_OPLEVEL(mbuf, i) < MAXOPLEVEL)
+          *strptr_i += ircd_snprintf(0, strptr + *strptr_i, BUFSIZE - *strptr_i,
+                                     " %s%s:%d",
+                                     NumNick(MB_CLIENT(mbuf, i)),
+                                     MB_OPLEVEL(mbuf, i));
+
+      /* deal with other modes that take clients */
+      else if (MB_TYPE(mbuf, i) & (MODE_CHANOP | MODE_VOICE))
+       build_string(strptr, strptr_i, NumNick(MB_CLIENT(mbuf, i)), ' ');
+
+      /* deal with modes that take strings */
+      else if (MB_TYPE(mbuf, i) & (MODE_KEY | MODE_BAN | MODE_EXCEPTION | MODE_APASS | MODE_UPASS | MODE_ALTCHAN))
+       build_string(strptr, strptr_i, MB_STRING(mbuf, i), 0, ' ');
+
+      /*
+       * deal with the limit.  Logic here is complicated; if HACK2 is set,
+       * we're bouncing the mode, so sense is reversed, and we have to
+       * include the original limit if it looks like it's being removed
+       */
+      else if ((MB_TYPE(mbuf, i) & limitdel) == limitdel)
+       build_string(strptr, strptr_i, limitbuf, 0, ' ');
+         else if ((MB_TYPE(mbuf, i) & accessdel) == accessdel)
+       build_string(strptr, strptr_i, accessbuf, 0, ' ');
+    }
+
+    /* we were told to deop the source */
+    if (mbuf->mb_dest & MODEBUF_DEST_DEOP) {
+      addbuf[addbuf_i++] = 'o'; /* remember, sense is reversed */
+      addbuf[addbuf_i] = '\0'; /* terminate the string... */
+      build_string(addstr, &addstr_i, NumNick(mbuf->mb_source), ' ');
+
+      /* mark that we've done this, so we don't do it again */
+      mbuf->mb_dest &= ~MODEBUF_DEST_DEOP;
+    }
+
+    if (mbuf->mb_dest & MODEBUF_DEST_OPMODE) {
+      /* If OPMODE was set, we're propagating the mode as an OPMODE message */
+      sendcmdto_serv_butone(mbuf->mb_source, CMD_OPMODE, mbuf->mb_connect,
+                           "%H %s%s%s%s%s%s", mbuf->mb_channel,
+                           rembuf_i ? "-" : "", rembuf, addbuf_i ? "+" : "",
+                           addbuf, remstr, addstr);
+    } else if (mbuf->mb_dest & MODEBUF_DEST_BOUNCE) {
+      /*
+       * If HACK2 was set, we're bouncing; we send the MODE back to
+       * the connection we got it from with the senses reversed and
+       * the proper TS; origin is us
+       */
+      sendcmdto_one(&me, CMD_MODE, mbuf->mb_connect, "%H %s%s%s%s%s%s %Tu",
+                   mbuf->mb_channel, addbuf_i ? "-" : "", addbuf,
+                   rembuf_i ? "+" : "", rembuf, addstr, remstr,
+                   mbuf->mb_channel->creationtime);
+    } else {
+      /*
+       * We're propagating a normal (or HACK3 or HACK4) MODE command
+       * to the rest of the network.  We send the actual channel TS.
+       */
+      sendcmdto_serv_butone(mbuf->mb_source, CMD_MODE, mbuf->mb_connect,
+                            "%H %s%s%s%s%s%s %Tu", mbuf->mb_channel,
+                            rembuf_i ? "-" : "", rembuf, addbuf_i ? "+" : "",
+                            addbuf, remstr, addstr,
+                            mbuf->mb_channel->creationtime);
+    }
+  }
+
+  /* We've drained the ModeBuf... */
+  mbuf->mb_add = 0;
+  mbuf->mb_rem = 0;
+  mbuf->mb_count = 0;
+
+  /* reinitialize the mode-with-arg slots */
+  for (i = 0; i < MAXMODEPARAMS; i++) {
+    /* If we saved any, pack them down */
+    if (MB_TYPE(mbuf, i) & MODE_SAVE) {
+      mbuf->mb_modeargs[mbuf->mb_count] = mbuf->mb_modeargs[i];
+      MB_TYPE(mbuf, mbuf->mb_count) &= ~MODE_SAVE; /* don't save anymore */
+
+      if (mbuf->mb_count++ == i) /* don't overwrite our hard work */
+       continue;
+    } else if (MB_TYPE(mbuf, i) & MODE_FREE)
+      MyFree(MB_STRING(mbuf, i)); /* free string if needed */
+
+    MB_TYPE(mbuf, i) = 0;
+    MB_UINT(mbuf, i) = 0;
+  }
+
+  /* If we're supposed to flush it all, do so--all hail tail recursion */
+  if (all && mbuf->mb_count)
+    return modebuf_flush_int(mbuf, 1);
+
+  return 0;
+}
+
+/** Initialise a modebuf
+ * This routine just initializes a ModeBuf structure with the information
+ * needed and the options given.
+ *
+ * @param mbuf         The mode buffer to initialise.
+ * @param source       The client that is performing the mode.
+ * @param connect      ?
+ * @param chan         The channel that the mode is being performed upon.
+ * @param dest         ?
+ */
+void
+modebuf_init(struct ModeBuf *mbuf, struct Client *source,
+            struct Client *connect, struct Channel *chan, unsigned int dest)
+{
+  int i;
+
+  assert(0 != mbuf);
+  assert(0 != source);
+  assert(0 != chan);
+  assert(0 != dest);
+
+  if (IsLocalChannel(chan->chname)) dest &= ~MODEBUF_DEST_SERVER;
+
+  mbuf->mb_add = 0;
+  mbuf->mb_rem = 0;
+  mbuf->mb_source = source;
+  mbuf->mb_connect = connect;
+  mbuf->mb_channel = chan;
+  mbuf->mb_dest = dest;
+  mbuf->mb_count = 0;
+
+  /* clear each mode-with-parameter slot */
+  for (i = 0; i < MAXMODEPARAMS; i++) {
+    MB_TYPE(mbuf, i) = 0;
+    MB_UINT(mbuf, i) = 0;
+  }
+}
+
+/** Append a new mode to a modebuf
+ * This routine simply adds modes to be added or deleted; do a binary OR
+ * with either MODE_ADD or MODE_DEL
+ *
+ * @param mbuf         Mode buffer
+ * @param mode         MODE_ADD or MODE_DEL OR'd with MODE_PRIVATE etc.
+ */
+void
+modebuf_mode(struct ModeBuf *mbuf, unsigned int mode)
+{
+  assert(0 != mbuf);
+  assert(0 != (mode & (MODE_ADD | MODE_DEL)));
+
+  mode &= (MODE_ADD | MODE_DEL | MODE_PRIVATE | MODE_SECRET | MODE_MODERATED |
+          MODE_TOPICLIMIT | MODE_INVITEONLY | MODE_NOPRIVMSGS | MODE_REGONLY |
+           MODE_DELJOINS | MODE_WASDELJOINS | MODE_REGISTERED | MODE_PERSIST |
+           MODE_NOCOLOUR | MODE_NOCTCP | MODE_NOAMSGS | MODE_NONOTICE | MODE_QUARANTINE);
+
+  if (!(mode & ~(MODE_ADD | MODE_DEL))) /* don't add empty modes... */
+    return;
+
+  if (mode & MODE_ADD) {
+    mbuf->mb_rem &= ~mode;
+    mbuf->mb_add |= mode;
+  } else {
+    mbuf->mb_add &= ~mode;
+    mbuf->mb_rem |= mode;
+  }
+}
+
+/** Append a mode that takes an int argument to the modebuf
+ *
+ * This routine adds a mode to be added or deleted that takes a unsigned
+ * int parameter; mode may *only* be the relevant mode flag ORed with one
+ * of MODE_ADD or MODE_DEL
+ *
+ * @param mbuf         The mode buffer to append to.
+ * @param mode         The mode to append.
+ * @param uint         The argument to the mode.
+ */
+void
+modebuf_mode_uint(struct ModeBuf *mbuf, unsigned int mode, unsigned int uint)
+{
+  assert(0 != mbuf);
+  assert(0 != (mode & (MODE_ADD | MODE_DEL)));
+
+  if (mode == (MODE_LIMIT | MODE_DEL)) {
+      mbuf->mb_rem |= mode;
+      return;
+  }
+  if (mode == (MODE_ACCESS | MODE_DEL)) {
+      mbuf->mb_rem |= mode;
+      return;
+  }
+  MB_TYPE(mbuf, mbuf->mb_count) = mode;
+  MB_UINT(mbuf, mbuf->mb_count) = uint;
+
+  /* when we've reached the maximal count, flush the buffer */
+  if (++mbuf->mb_count >=
+      (MAXMODEPARAMS - (mbuf->mb_dest & MODEBUF_DEST_DEOP ? 1 : 0)))
+    modebuf_flush_int(mbuf, 0);
+}
+
+/** append a string mode
+ * This routine adds a mode to be added or deleted that takes a string
+ * parameter; mode may *only* be the relevant mode flag ORed with one of
+ * MODE_ADD or MODE_DEL
+ *
+ * @param mbuf         The mode buffer to append to.
+ * @param mode         The mode to append.
+ * @param string       The string parameter to append.
+ * @param free         If the string should be free'd later.
+ */
+void
+modebuf_mode_string(struct ModeBuf *mbuf, unsigned int mode, char *string,
+                   int free)
+{
+  assert(0 != mbuf);
+  assert(0 != (mode & (MODE_ADD | MODE_DEL)));
+
+  MB_TYPE(mbuf, mbuf->mb_count) = mode | (free ? MODE_FREE : 0);
+  MB_STRING(mbuf, mbuf->mb_count) = string;
+
+  /* when we've reached the maximal count, flush the buffer */
+  if (++mbuf->mb_count >=
+      (MAXMODEPARAMS - (mbuf->mb_dest & MODEBUF_DEST_DEOP ? 1 : 0)))
+    modebuf_flush_int(mbuf, 0);
+}
+
+/** Append a mode on a client to a modebuf.
+ * This routine adds a mode to be added or deleted that takes a client
+ * parameter; mode may *only* be the relevant mode flag ORed with one of
+ * MODE_ADD or MODE_DEL
+ *
+ * @param mbuf         The modebuf to append the mode to.
+ * @param mode         The mode to append.
+ * @param client       The client argument to append.
+ * @param oplevel       The oplevel the user had or will have
+ */
+void
+modebuf_mode_client(struct ModeBuf *mbuf, unsigned int mode,
+                   struct Client *client, int oplevel)
+{
+  assert(0 != mbuf);
+  assert(0 != (mode & (MODE_ADD | MODE_DEL)));
+
+  MB_TYPE(mbuf, mbuf->mb_count) = mode;
+  MB_CLIENT(mbuf, mbuf->mb_count) = client;
+  MB_OPLEVEL(mbuf, mbuf->mb_count) = oplevel;
+
+  /* when we've reached the maximal count, flush the buffer */
+  if (++mbuf->mb_count >=
+      (MAXMODEPARAMS - (mbuf->mb_dest & MODEBUF_DEST_DEOP ? 1 : 0)))
+    modebuf_flush_int(mbuf, 0);
+}
+
+/** Check a channel for join-delayed members.
+ * @param[in] chan Channel to search.
+ * @return Non-zero if any members are join-delayed; false if none are.
+ */
+static int
+find_delayed_joins(const struct Channel *chan)
+{
+  const struct Membership *memb;
+  for (memb = chan->members; memb; memb = memb->next_member)
+    if (IsDelayedJoin(memb) && !IsInvisibleJoin(memb))
+      return 1;
+  return 0;
+}
+
+/** The exported binding for modebuf_flush()
+ *
+ * @param mbuf The mode buffer to flush.
+ * 
+ * @see modebuf_flush_int()
+ */
+int
+modebuf_flush(struct ModeBuf *mbuf)
+{
+  /* Check if MODE_WASDELJOINS should be set: */
+  /* Must be set if going -D and some clients are hidden */
+  if ((mbuf->mb_rem & MODE_DELJOINS)
+      && !(mbuf->mb_channel->mode.mode & (MODE_DELJOINS | MODE_WASDELJOINS))
+      && find_delayed_joins(mbuf->mb_channel)) {
+    mbuf->mb_channel->mode.mode |= MODE_WASDELJOINS;
+    mbuf->mb_add |= MODE_WASDELJOINS;
+    mbuf->mb_rem &= ~MODE_WASDELJOINS;
+  }
+  /* Must be cleared if +D is set */
+  if ((mbuf->mb_add & MODE_DELJOINS)
+      && ((mbuf->mb_channel->mode.mode & (MODE_WASDELJOINS | MODE_WASDELJOINS))
+          == (MODE_WASDELJOINS | MODE_WASDELJOINS))) {
+    mbuf->mb_channel->mode.mode &= ~MODE_WASDELJOINS;
+    mbuf->mb_add &= ~MODE_WASDELJOINS;
+    mbuf->mb_rem |= MODE_WASDELJOINS;
+  }
+
+  return modebuf_flush_int(mbuf, 1);
+}
+
+/* This extracts the simple modes contained in mbuf
+ *
+ * @param mbuf         The mode buffer to extract the modes from.
+ * @param buf          The string buffer to write the modes into.
+ */
+void
+modebuf_extract(struct ModeBuf *mbuf, char *buf)
+{
+  static int flags[] = {
+/*  MODE_CHANOP,       'o', */
+/*  MODE_VOICE,                'v', */
+    MODE_PRIVATE,      'p',
+    MODE_SECRET,       's',
+    MODE_MODERATED,    'm',
+    MODE_TOPICLIMIT,   't',
+    MODE_INVITEONLY,   'i',
+    MODE_NOPRIVMSGS,   'n',
+    MODE_KEY,          'k',
+    MODE_APASS,                'A',
+    MODE_UPASS,                'U',
+    MODE_REGISTERED,   'R',
+/*  MODE_BAN,          'b', */
+    MODE_LIMIT,                'l',
+    MODE_REGONLY,      'r',
+    MODE_DELJOINS,      'D',
+    MODE_PERSIST,       'z',
+    MODE_NOCOLOUR,  'c',
+    MODE_NOCTCP,    'C',
+/*  MODE_EXCEPTION, 'e', */
+    MODE_NOAMSGS,   'M',
+       MODE_NONOTICE,  'N',
+       MODE_QUARANTINE,  'Q',
+       MODE_ALTCHAN,    'F',
+       MODE_ACCESS,    'a',
+    0x0, 0x0
+  };
+  unsigned int add;
+  int i, bufpos = 0, len;
+  int *flag_p;
+  char *key = 0, limitbuf[20], accessbuf[20];
+  char *apass = 0, *upass = 0, *altchan = 0;
+
+  assert(0 != mbuf);
+  assert(0 != buf);
+
+  buf[0] = '\0';
+
+  add = mbuf->mb_add;
+
+  for (i = 0; i < mbuf->mb_count; i++) { /* find keys and limits */
+    if (MB_TYPE(mbuf, i) & MODE_ADD) {
+      add |= MB_TYPE(mbuf, i) & (MODE_KEY | MODE_LIMIT | MODE_APASS | MODE_UPASS | MODE_ALTCHAN | MODE_ACCESS);
+
+      if (MB_TYPE(mbuf, i) & MODE_KEY) /* keep strings */
+       key = MB_STRING(mbuf, i);
+      else if (MB_TYPE(mbuf, i) & MODE_LIMIT)
+       ircd_snprintf(0, limitbuf, sizeof(limitbuf), "%u", MB_UINT(mbuf, i));
+         else if (MB_TYPE(mbuf, i) & MODE_ACCESS)
+       ircd_snprintf(0, accessbuf, sizeof(accessbuf), "%u", MB_UINT(mbuf, i));
+      else if (MB_TYPE(mbuf, i) & MODE_UPASS)
+       upass = MB_STRING(mbuf, i);
+      else if (MB_TYPE(mbuf, i) & MODE_APASS)
+       apass = MB_STRING(mbuf, i);
+      else if (MB_TYPE(mbuf, i) & MODE_ALTCHAN)
+       altchan = MB_STRING(mbuf, i);
+    }
+  }
+
+  if (!add)
+    return;
+
+  buf[bufpos++] = '+'; /* start building buffer */
+
+  for (flag_p = flags; flag_p[0]; flag_p += 2)
+    if (*flag_p & add)
+      buf[bufpos++] = flag_p[1];
+
+  for (i = 0, len = bufpos; i < len; i++) {
+    if (buf[i] == 'k')
+      build_string(buf, &bufpos, key, 0, ' ');
+    else if (buf[i] == 'l')
+      build_string(buf, &bufpos, limitbuf, 0, ' ');
+    else if (buf[i] == 'a')
+      build_string(buf, &bufpos, accessbuf, 0, ' ');
+    else if (buf[i] == 'U')
+      build_string(buf, &bufpos, upass, 0, ' ');
+    else if (buf[i] == 'A')
+      build_string(buf, &bufpos, apass, 0, ' ');
+       else if (buf[i] == 'F')
+      build_string(buf, &bufpos, altchan, 0, ' ');
+  }
+
+  buf[bufpos] = '\0';
+
+  return;
+}
+
+/** Simple function to invalidate a channel's ban cache.
+ *
+ * This function marks all members of the channel as being neither
+ * banned nor banned.
+ *
+ * @param chan The channel to operate on.
+ */
+void
+mode_ban_invalidate(struct Channel *chan)
+{
+  struct Membership *member;
+
+  for (member = chan->members; member; member = member->next_member)
+    ClearBanValid(member);
+}
+
+/** Simple function to drop invite structures
+ *
+ * Remove all the invites on the channel.
+ *
+ * @param chan         Channel to remove invites from.
+ *
+ */
+void
+mode_invite_clear(struct Channel *chan)
+{
+  while (chan->invites)
+    del_invite(chan->invites->value.cptr, chan);
+}
+
+/* What we've done for mode_parse so far... */
+#define DONE_LIMIT     0x01    /**< We've set the limit */
+#define DONE_KEY_ADD   0x02    /**< We've set the key */
+#define DONE_BANLIST   0x04    /**< We've sent the ban list */
+#define DONE_NOTOPER   0x08    /**< We've sent a "Not oper" error */
+#define DONE_BANCLEAN  0x10    /**< We've cleaned bans... */
+#define DONE_UPASS_ADD 0x20    /**< We've set user pass */
+#define DONE_APASS_ADD 0x40    /**< We've set admin pass */
+#define DONE_KEY_DEL    0x80    /**< We've removed the key */
+#define DONE_UPASS_DEL  0x100   /**< We've removed the user pass */
+#define DONE_APASS_DEL  0x200   /**< We've removed the admin pass */
+#define DONE_EXCEPTIONLIST 0x400 /**< We've sent the exception list */
+#define DONE_ALTCHAN   0x800   /**< We've set the altchan */
+#define DONE_ACCESS    0x1000  /**< We've set the access */
+
+struct ParseState {
+  struct ModeBuf *mbuf;
+  struct Client *cptr;
+  struct Client *sptr;
+  struct Channel *chptr;
+  struct Membership *member;
+  int parc;
+  char **parv;
+  unsigned int flags;
+  unsigned int dir;
+  unsigned int done;
+  unsigned int add;
+  unsigned int del;
+  int args_used;
+  int max_args;
+  int numbans;
+  struct Ban banlist[MAXPARA];
+  struct {
+    unsigned int flag;
+    unsigned short oplevel;
+    struct Client *client;
+  } cli_change[MAXPARA];
+};
+
+/** Helper function to send "Not oper" or "Not member" messages
+ * Here's a helper function to deal with sending along "Not oper" or
+ * "Not member" messages
+ *
+ * @param state        Parsing State object
+ */
+static void
+send_notoper(struct ParseState *state)
+{
+  if (state->done & DONE_NOTOPER)
+    return;
+
+  send_reply(state->sptr, (state->flags & MODE_PARSE_NOTOPER) ?
+            ERR_CHANOPRIVSNEEDED : ERR_NOTONCHANNEL, state->chptr->chname);
+
+  state->done |= DONE_NOTOPER;
+}
+
+/** Parse a limit
+ * Helper function to convert limits
+ *
+ * @param state                Parsing state object.
+ * @param flag_p       ?
+ */
+static void
+mode_parse_limit(struct ParseState *state, int *flag_p)
+{
+  unsigned int t_limit;
+
+  if (state->dir == MODE_ADD) { /* convert arg only if adding limit */
+    if (MyUser(state->sptr) && state->max_args <= 0) /* too many args? */
+      return;
+
+    if (state->parc <= 0) { /* warn if not enough args */
+      if (MyUser(state->sptr))
+       need_more_params(state->sptr, "MODE +l");
+      return;
+    }
+
+    t_limit = strtoul(state->parv[state->args_used++], 0, 10); /* grab arg */
+    state->parc--;
+    state->max_args--;
+
+    if ((int)t_limit<0) /* don't permit a negative limit */
+      return;
+
+    if (!(state->flags & MODE_PARSE_WIPEOUT) &&
+       (!t_limit || t_limit == state->chptr->mode.limit))
+      return;
+  } else
+    t_limit = state->chptr->mode.limit;
+
+  /* If they're not an oper, they can't change modes */
+  if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
+    send_notoper(state);
+    return;
+  }
+
+  /* Can't remove a limit that's not there */
+  if (state->dir == MODE_DEL && !state->chptr->mode.limit)
+    return;
+    
+  /* Skip if this is a burst and a lower limit than this is set already */
+  if ((state->flags & MODE_PARSE_BURST) &&
+      (state->chptr->mode.mode & flag_p[0]) &&
+      (state->chptr->mode.limit < t_limit))
+    return;
+
+  if (state->done & DONE_LIMIT) /* allow limit to be set only once */
+    return;
+  state->done |= DONE_LIMIT;
+
+  if (!state->mbuf)
+    return;
+
+  modebuf_mode_uint(state->mbuf, state->dir | flag_p[0], t_limit);
+
+  if (state->flags & MODE_PARSE_SET) { /* set the limit */
+    if (state->dir & MODE_ADD) {
+      state->chptr->mode.mode |= flag_p[0];
+      state->chptr->mode.limit = t_limit;
+    } else {
+      state->chptr->mode.mode &= ~flag_p[0];
+      state->chptr->mode.limit = 0;
+    }
+  }
+}
+
+
+static void
+mode_parse_access(struct ParseState *state, int *flag_p)
+{
+  unsigned int t_access;
+
+  if (state->dir == MODE_ADD) { /* convert arg only if adding access */
+    if (MyUser(state->sptr) && state->max_args <= 0) /* too many args? */
+      return;
+
+    if (state->parc <= 0) { /* warn if not enough args */
+      if (MyUser(state->sptr))
+       need_more_params(state->sptr, "MODE +a");
+      return;
+    }
+
+    t_access = strtoul(state->parv[state->args_used++], 0, 10); /* grab arg */
+    state->parc--;
+    state->max_args--;
+
+    if ((int)t_access<1 || (int)t_access>500) /* don't permit a negative access or an access over 500 */
+      return;
+    
+    if (!feature_bool(FEAT_CHMODE_A_ENABLE)) { /* don't parse MODE_ACCESS if it's disabled */
+        if (MyUser(state->sptr)) {
+            char mode[1] = "a";
+            send_reply(state->sptr, ERR_UNKNOWNMODE, mode[0]);
+        }
+        return;
+    }
+    
+    if (!(state->flags & MODE_PARSE_WIPEOUT) &&
+       (!t_access || t_access == state->chptr->mode.access))
+      return;
+  } else
+    t_access = state->chptr->mode.access;
+
+  /* If they're not an oper, they can't change modes */
+  if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
+    send_notoper(state);
+    return;
+  }
+
+  /* Can't remove an access that's not there */
+  if (state->dir == MODE_DEL && !state->chptr->mode.access)
+    return;
+    
+  /* Skip if this is a burst and a higher access than this is set already */
+  if ((state->flags & MODE_PARSE_BURST) &&
+      (state->chptr->mode.mode & flag_p[0]) &&
+      (state->chptr->mode.access > t_access))
+    return;
+
+  if (state->done & DONE_ACCESS) /* allow access to be set only once */
+    return;
+  state->done |= DONE_ACCESS;
+
+  if (!state->mbuf)
+    return;
+
+  modebuf_mode_uint(state->mbuf, state->dir | flag_p[0], t_access);
+
+  if (state->flags & MODE_PARSE_SET) { /* set the access */
+    if (state->dir & MODE_ADD) {
+      state->chptr->mode.mode |= flag_p[0];
+      state->chptr->mode.access = t_access;
+    } else {
+      state->chptr->mode.mode &= ~flag_p[0];
+      state->chptr->mode.access = 0;
+    }
+  }
+}
+
+
+static void
+mode_parse_altchan(struct ParseState *state, int *flag_p)
+{
+  char *t_str;
+
+  if (state->dir == MODE_ADD) { /* convert arg only if adding altchan */
+    if (MyUser(state->sptr) && state->max_args <= 0) /* too many args? */
+      return;
+    
+    if (!feature_bool(FEAT_CHMODE_F_ENABLE))
+        return;
+    
+    if (state->parc <= 0) { /* warn if not enough args */
+      if (MyUser(state->sptr))
+       need_more_params(state->sptr, "MODE +F");
+      return;
+    }
+
+    t_str = state->parv[state->args_used++]; /* grab arg */
+    state->parc--;
+    state->max_args--;
+
+    if (!IsChannelName(t_str) || !strIsIrcCh(t_str) || strlen(t_str) > IRCD_MIN(CHANNELLEN, feature_int(FEAT_CHANNELLEN)) || t_str[0] == '&') /* only parse it if it's a valid channel name! */
+      return;
+    
+    struct Channel *chptr;
+    struct Membership *member;
+    if (!(chptr = FindChannel(t_str)))
+        return;
+    if(!(member = find_member_link(chptr, state->sptr)))
+        return;
+    if(!IsChanOp(member)) {
+        send_notoper(state);
+        return;
+    }
+    
+    if (!(state->flags & MODE_PARSE_WIPEOUT) &&
+       (!t_str || t_str == state->chptr->mode.altchan))
+      return;
+  } else
+    t_str = state->chptr->mode.altchan;
+
+  /* If they're not an oper, they can't change modes */
+  if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
+    send_notoper(state);
+    return;
+  }
+
+  /* Can't remove a altchan that's not there */
+  if (state->dir == MODE_DEL && !*state->chptr->mode.altchan)
+    return;
+    
+  /* Skip if this is a burst and a lower altchan than this is set already */
+  if ((state->flags & MODE_PARSE_BURST) &&
+      *(state->chptr->mode.altchan))
+    return;
+
+  if (state->done & DONE_ALTCHAN) /* allow altchan to be set only once */
+    return;
+  state->done |= DONE_ALTCHAN;
+
+  if (!state->mbuf)
+    return;
+
+  if (!(state->flags & MODE_PARSE_WIPEOUT) && state->dir == MODE_ADD &&
+      !ircd_strcmp(state->chptr->mode.altchan, t_str))
+    return; /* no change */
+
+  if (state->flags & MODE_PARSE_BOUNCE) {
+    if (*state->chptr->mode.altchan) /* reset old altchan */
+      modebuf_mode_string(state->mbuf, MODE_DEL | flag_p[0], state->chptr->mode.altchan, 0);
+    else /* remove new bogus altchan */
+      modebuf_mode_string(state->mbuf, MODE_ADD | flag_p[0], t_str, 0);
+  } else /* send new altchan */
+    modebuf_mode_string(state->mbuf, state->dir | flag_p[0], t_str, 0);
+
+  if (state->flags & MODE_PARSE_SET) {
+    if (state->dir == MODE_DEL) /* remove the old altchan */
+      *state->chptr->mode.altchan = '\0';
+    else
+      ircd_strncpy(state->chptr->mode.altchan, t_str, CHANNELLEN);
+  }
+}
+
+static void
+mode_parse_quarantine(struct ParseState *state, int *flag_p)
+{
+    
+}
+
+/** Helper function to validate key-like parameters.
+ *
+ * @param[in] state Parse state for feedback to user.
+ * @param[in] s Key to validate.
+ * @param[in] command String to pass for need_more_params() command.
+ * @return Zero on an invalid key, non-zero if the key was okay.
+ */
+static int
+is_clean_key(struct ParseState *state, char *s, char *command)
+{
+  int ii;
+
+  if (s[0] == '\0') {
+    if (MyUser(state->sptr))
+      need_more_params(state->sptr, command);
+    return 0;
+  }
+  else if (s[0] == ':') {
+    if (MyUser(state->sptr))
+      send_reply(state->sptr, ERR_INVALIDKEY, state->chptr->chname);
+    return 0;
+  }
+  for (ii = 0; (ii <= KEYLEN) && (s[ii] != '\0'); ++ii) {
+    if ((unsigned char)s[ii] <= ' ' || s[ii] == ',') {
+      if (MyUser(state->sptr))
+        send_reply(state->sptr, ERR_INVALIDKEY, state->chptr->chname);
+      return 0;
+    }
+  }
+  if (ii > KEYLEN) {
+    if (MyUser(state->sptr))
+      send_reply(state->sptr, ERR_INVALIDKEY, state->chptr->chname);
+    return 0;
+  }
+  return 1;
+}
+
+/*
+ * Helper function to convert keys
+ */
+static void
+mode_parse_key(struct ParseState *state, int *flag_p)
+{
+  char *t_str;
+
+  if (MyUser(state->sptr) && state->max_args <= 0) /* drop if too many args */
+    return;
+
+  if (state->parc <= 0) { /* warn if not enough args */
+    if (MyUser(state->sptr))
+      need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +k" :
+                      "MODE -k");
+    return;
+  }
+
+  t_str = state->parv[state->args_used++]; /* grab arg */
+  state->parc--;
+  state->max_args--;
+
+  /* If they're not an oper, they can't change modes */
+  if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
+    send_notoper(state);
+    return;
+  }
+
+  /* allow removing and then adding key, but not adding and then removing */
+  if (state->dir == MODE_ADD)
+  {
+    if (state->done & DONE_KEY_ADD)
+      return;
+    state->done |= DONE_KEY_ADD;
+  }
+  else
+  {
+    if (state->done & (DONE_KEY_ADD | DONE_KEY_DEL))
+      return;
+    state->done |= DONE_KEY_DEL;
+  }
+
+  /* If the key is invalid, tell the user and bail. */
+  if (!is_clean_key(state, t_str, state->dir == MODE_ADD ? "MODE +k" :
+                    "MODE -k"))
+    return;
+
+  if (!state->mbuf)
+    return;
+
+  /* Skip if this is a burst, we have a key already and the new key is 
+   * after the old one alphabetically */
+  if ((state->flags & MODE_PARSE_BURST) &&
+      *(state->chptr->mode.key) &&
+      ircd_strcmp(state->chptr->mode.key, t_str) <= 0)
+    return;
+
+  /* can't add a key if one is set, nor can one remove the wrong key */
+  if (!(state->flags & MODE_PARSE_FORCE))
+    if ((state->dir == MODE_ADD && *state->chptr->mode.key) ||
+       (state->dir == MODE_DEL &&
+        ircd_strcmp(state->chptr->mode.key, t_str))) {
+      send_reply(state->sptr, ERR_KEYSET, state->chptr->chname);
+      return;
+    }
+
+  if (!(state->flags & MODE_PARSE_WIPEOUT) && state->dir == MODE_ADD &&
+      !ircd_strcmp(state->chptr->mode.key, t_str))
+    return; /* no key change */
+
+  if (state->flags & MODE_PARSE_BOUNCE) {
+    if (*state->chptr->mode.key) /* reset old key */
+      modebuf_mode_string(state->mbuf, MODE_DEL | flag_p[0],
+                         state->chptr->mode.key, 0);
+    else /* remove new bogus key */
+      modebuf_mode_string(state->mbuf, MODE_ADD | flag_p[0], t_str, 0);
+  } else /* send new key */
+    modebuf_mode_string(state->mbuf, state->dir | flag_p[0], t_str, 0);
+
+  if (state->flags & MODE_PARSE_SET) {
+    if (state->dir == MODE_DEL) /* remove the old key */
+      *state->chptr->mode.key = '\0';
+    else
+      ircd_strncpy(state->chptr->mode.key, t_str, KEYLEN);
+  }
+}
+
+/*
+ * Helper function to convert user passes
+ */
+static void
+mode_parse_upass(struct ParseState *state, int *flag_p)
+{
+  char *t_str;
+
+  if (MyUser(state->sptr) && state->max_args <= 0) /* drop if too many args */
+    return;
+
+  if (state->parc <= 0) { /* warn if not enough args */
+    if (MyUser(state->sptr))
+      need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +U" :
+                      "MODE -U");
+    return;
+  }
+
+  t_str = state->parv[state->args_used++]; /* grab arg */
+  state->parc--;
+  state->max_args--;
+
+  /* If they're not an oper, they can't change modes */
+  if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
+    send_notoper(state);
+    return;
+  }
+
+  /* If a non-service user is trying to force it, refuse. */
+  if (state->flags & MODE_PARSE_FORCE && MyUser(state->sptr)
+      && !HasPriv(state->sptr, PRIV_APASS_OPMODE)) {
+    send_reply(state->sptr, ERR_NOTMANAGER, state->chptr->chname,
+               state->chptr->chname);
+    return;
+  }
+
+  /* If they are not the channel manager, they are not allowed to change it */
+  if (MyUser(state->sptr) && !(state->flags & MODE_PARSE_FORCE || IsChannelManager(state->member))) {
+    if (*state->chptr->mode.apass) {
+      send_reply(state->sptr, ERR_NOTMANAGER, state->chptr->chname,
+                 state->chptr->chname);
+    } else {
+      send_reply(state->sptr, ERR_NOMANAGER, state->chptr->chname,
+          (TStime() - state->chptr->creationtime < 172800) ?
+         "approximately 4-5 minutes" : "approximately 48 hours");
+    }
+    return;
+  }
+
+  /* allow removing and then adding upass, but not adding and then removing */
+  if (state->dir == MODE_ADD)
+  {
+    if (state->done & DONE_UPASS_ADD)
+      return;
+    state->done |= DONE_UPASS_ADD;
+  }
+  else
+  {
+    if (state->done & (DONE_UPASS_ADD | DONE_UPASS_DEL))
+      return;
+    state->done |= DONE_UPASS_DEL;
+  }
+
+  /* If the Upass is invalid, tell the user and bail. */
+  if (!is_clean_key(state, t_str, state->dir == MODE_ADD ? "MODE +U" :
+                    "MODE -U"))
+    return;
+
+  if (!state->mbuf)
+    return;
+
+  if (!(state->flags & MODE_PARSE_FORCE)) {
+    /* can't add the upass while apass is not set */
+    if (state->dir == MODE_ADD && !*state->chptr->mode.apass) {
+      send_reply(state->sptr, ERR_UPASSNOTSET, state->chptr->chname, state->chptr->chname);
+      return;
+    }
+    /* cannot set a +U password that is the same as +A */
+    if (state->dir == MODE_ADD && !ircd_strcmp(state->chptr->mode.apass, t_str)) {
+      send_reply(state->sptr, ERR_UPASS_SAME_APASS, state->chptr->chname);
+      return;
+    }
+    /* can't add a upass if one is set, nor can one remove the wrong upass */
+    if ((state->dir == MODE_ADD && *state->chptr->mode.upass) ||
+       (state->dir == MODE_DEL &&
+        ircd_strcmp(state->chptr->mode.upass, t_str))) {
+      send_reply(state->sptr, ERR_KEYSET, state->chptr->chname);
+      return;
+    }
+  }
+
+  if (!(state->flags & MODE_PARSE_WIPEOUT) && state->dir == MODE_ADD &&
+      !ircd_strcmp(state->chptr->mode.upass, t_str))
+    return; /* no upass change */
+
+  /* Skip if this is a burst, we have a Upass already and the new Upass is
+   * after the old one alphabetically */
+  if ((state->flags & MODE_PARSE_BURST) &&
+      *(state->chptr->mode.upass) &&
+      ircd_strcmp(state->chptr->mode.upass, t_str) <= 0)
+    return;
+
+  if (state->flags & MODE_PARSE_BOUNCE) {
+    if (*state->chptr->mode.upass) /* reset old upass */
+      modebuf_mode_string(state->mbuf, MODE_DEL | flag_p[0],
+                         state->chptr->mode.upass, 0);
+    else /* remove new bogus upass */
+      modebuf_mode_string(state->mbuf, MODE_ADD | flag_p[0], t_str, 0);
+  } else /* send new upass */
+    modebuf_mode_string(state->mbuf, state->dir | flag_p[0], t_str, 0);
+
+  if (state->flags & MODE_PARSE_SET) {
+    if (state->dir == MODE_DEL) /* remove the old upass */
+      *state->chptr->mode.upass = '\0';
+    else
+      ircd_strncpy(state->chptr->mode.upass, t_str, KEYLEN);
+  }
+}
+
+/*
+ * Helper function to convert admin passes
+ */
+static void
+mode_parse_apass(struct ParseState *state, int *flag_p)
+{
+  struct Membership *memb;
+  char *t_str;
+
+  if (MyUser(state->sptr) && state->max_args <= 0) /* drop if too many args */
+    return;
+
+  if (state->parc <= 0) { /* warn if not enough args */
+    if (MyUser(state->sptr))
+      need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +A" :
+                      "MODE -A");
+    return;
+  }
+
+  t_str = state->parv[state->args_used++]; /* grab arg */
+  state->parc--;
+  state->max_args--;
+
+  /* If they're not an oper, they can't change modes */
+  if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
+    send_notoper(state);
+    return;
+  }
+
+  if (MyUser(state->sptr)) {
+    if (state->flags & MODE_PARSE_FORCE) {
+      /* If an unprivileged oper is trying to force it, refuse. */
+      if (!HasPriv(state->sptr, PRIV_APASS_OPMODE)) {
+        send_reply(state->sptr, ERR_NOTMANAGER, state->chptr->chname,
+                   state->chptr->chname);
+        return;
+      }
+    } else {
+      /* If they are not the channel manager, they are not allowed to change it. */
+      if (!IsChannelManager(state->member)) {
+        if (*state->chptr->mode.apass) {
+          send_reply(state->sptr, ERR_NOTMANAGER, state->chptr->chname,
+                     state->chptr->chname);
+        } else {
+          send_reply(state->sptr, ERR_NOMANAGER, state->chptr->chname,
+                     (TStime() - state->chptr->creationtime < 172800) ?
+                     "approximately 4-5 minutes" : "approximately 48 hours");
+        }
+        return;
+      }
+      /* Can't remove the Apass while Upass is still set. */
+      if (state->dir == MODE_DEL && *state->chptr->mode.upass) {
+        send_reply(state->sptr, ERR_UPASSSET, state->chptr->chname, state->chptr->chname);
+        return;
+      }
+      /* Can't add an Apass if one is set, nor can one remove the wrong Apass. */
+      if ((state->dir == MODE_ADD && *state->chptr->mode.apass) ||
+          (state->dir == MODE_DEL && ircd_strcmp(state->chptr->mode.apass, t_str))) {
+        send_reply(state->sptr, ERR_KEYSET, state->chptr->chname);
+        return;
+      }
+    }
+
+    /* Forbid removing the Apass if the channel is older than 48 hours
+     * unless an oper is doing it. */
+    if (TStime() - state->chptr->creationtime >= 172800
+        && state->dir == MODE_DEL
+        && !IsAnOper(state->sptr)) {
+      send_reply(state->sptr, ERR_CHANSECURED, state->chptr->chname);
+      return;
+    }
+  }
+
+  /* allow removing and then adding apass, but not adding and then removing */
+  if (state->dir == MODE_ADD)
+  {
+    if (state->done & DONE_APASS_ADD)
+      return;
+    state->done |= DONE_APASS_ADD;
+  }
+  else
+  {
+    if (state->done & (DONE_APASS_ADD | DONE_APASS_DEL))
+      return;
+    state->done |= DONE_APASS_DEL;
+  }
+
+  /* If the Apass is invalid, tell the user and bail. */
+  if (!is_clean_key(state, t_str, state->dir == MODE_ADD ? "MODE +A" :
+                    "MODE -A"))
+    return;
+
+  if (!state->mbuf)
+    return;
+
+  if (!(state->flags & MODE_PARSE_WIPEOUT) && state->dir == MODE_ADD &&
+      !ircd_strcmp(state->chptr->mode.apass, t_str))
+    return; /* no apass change */
+
+  /* Skip if this is a burst, we have an Apass already and the new Apass is
+   * after the old one alphabetically */
+  if ((state->flags & MODE_PARSE_BURST) &&
+      *(state->chptr->mode.apass) &&
+      ircd_strcmp(state->chptr->mode.apass, t_str) <= 0)
+    return;
+
+  if (state->flags & MODE_PARSE_BOUNCE) {
+    if (*state->chptr->mode.apass) /* reset old apass */
+      modebuf_mode_string(state->mbuf, MODE_DEL | flag_p[0],
+                         state->chptr->mode.apass, 0);
+    else /* remove new bogus apass */
+      modebuf_mode_string(state->mbuf, MODE_ADD | flag_p[0], t_str, 0);
+  } else /* send new apass */
+    modebuf_mode_string(state->mbuf, state->dir | flag_p[0], t_str, 0);
+
+  if (state->flags & MODE_PARSE_SET) {
+    if (state->dir == MODE_ADD) { /* set the new apass */
+      /* Only accept the new apass if there is no current apass or
+       * this is a BURST. */
+      if (state->chptr->mode.apass[0] == '\0' ||
+          (state->flags & MODE_PARSE_BURST))
+        ircd_strncpy(state->chptr->mode.apass, t_str, KEYLEN);
+      /* Make it VERY clear to the user that this is a one-time password */
+      if (MyUser(state->sptr)) {
+       send_reply(state->sptr, RPL_APASSWARN_SET, state->chptr->mode.apass);
+       send_reply(state->sptr, RPL_APASSWARN_SECRET, state->chptr->chname,
+                   state->chptr->mode.apass);
+      }
+      /* Give the channel manager level 0 ops.
+         There should not be tested for IsChannelManager here because
+        on the local server it is impossible to set the apass if one
+        isn't a channel manager and remote servers might need to sync
+        the oplevel here: when someone creates a channel (and becomes
+        channel manager) during a net.break, and only sets the Apass
+        after the net rejoined, they will have oplevel MAXOPLEVEL on
+        all remote servers. */
+      if (state->member)
+        SetOpLevel(state->member, 0);
+    } else { /* remove the old apass */
+      *state->chptr->mode.apass = '\0';
+      /* Clear Upass so that there is never a Upass set when a zannel is burst. */
+      *state->chptr->mode.upass = '\0';
+      if (MyUser(state->sptr))
+        send_reply(state->sptr, RPL_APASSWARN_CLEAR);
+      /* Revert everyone to MAXOPLEVEL. */
+      for (memb = state->chptr->members; memb; memb = memb->next_member) {
+        if (memb->status & MODE_CHANOP)
+          SetOpLevel(memb, MAXOPLEVEL);
+      }
+    }
+  }
+}
+
+/** Compare one ban's extent to another.
+ * This works very similarly to mmatch() but it knows about CIDR masks
+ * and ban exceptions.  If both bans are CIDR-based, compare their
+ * address bits; otherwise, use mmatch().
+ * @param[in] old_ban One ban.
+ * @param[in] new_ban Another ban.
+ * @return Zero if \a old_ban is a superset of \a new_ban, non-zero otherwise.
+ */
+static int
+bmatch(struct Ban *old_ban, struct Ban *new_ban)
+{
+  int res;
+  assert(old_ban != NULL);
+  assert(new_ban != NULL);
+  /* A ban is never treated as a superset of an exception and vice versa. */
+  if(((old_ban->flags & BAN_EXCEPTION) && !(new_ban->flags & BAN_EXCEPTION))
+     || (!(old_ban->flags & BAN_EXCEPTION) && (new_ban->flags & BAN_EXCEPTION)))
+    return 1;
+  /* If either is not an address mask, match the text masks. */
+  if ((old_ban->flags & new_ban->flags & BAN_IPMASK) == 0)
+    return mmatch(old_ban->banstr, new_ban->banstr);
+  /* If the old ban has a longer prefix than new, it cannot be a superset. */
+  if (old_ban->addrbits > new_ban->addrbits)
+    return 1;
+  /* Compare the masks before the hostname part.  */
+  old_ban->banstr[old_ban->nu_len] = new_ban->banstr[new_ban->nu_len] = '\0';
+  res = mmatch(old_ban->banstr, new_ban->banstr);
+  old_ban->banstr[old_ban->nu_len] = new_ban->banstr[new_ban->nu_len] = '@';
+  if (res)
+    return res;
+  /* If the old ban's mask mismatches, cannot be a superset. */
+  if (!ipmask_check(&new_ban->address, &old_ban->address, old_ban->addrbits))
+    return 1;
+  /* Otherwise it depends on whether the old ban's text is a superset
+   * of the new. */
+  return mmatch(old_ban->banstr, new_ban->banstr);
+}
+
+/** Add a ban from a ban list and mark bans that should be removed
+ * because they overlap.
+ *
+ * There are three invariants for a ban list.  First, no ban may be
+ * more specific than another ban.  Second, no exception may be more
+ * specific than another exception.  Finally, no ban may be more
+ * specific than any exception.
+ *
+ * @param[in,out] banlist Pointer to head of list.
+ * @param[in] newban Ban (or exception) to add (or remove).
+ * @param[in] do_free If non-zero, free \a newban on failure.
+ * @return Zero if \a newban could be applied, non-zero if not.
+ */
+int apply_ban(struct Ban **banlist, struct Ban *newban, int do_free)
+{
+  struct Ban *ban;
+  size_t count = 0;
+
+  assert(newban->flags & (BAN_ADD|BAN_DEL));
+  if (newban->flags & BAN_ADD) {
+    size_t totlen = 0;
+    /* If a less specific *active* entry is found, fail.  */
+    for (ban = *banlist; ban; ban = ban->next) {
+      if (!bmatch(ban, newban) && !(ban->flags & BAN_DEL)) {
+        if (do_free)
+          free_ban(newban);
+        return 1;
+      }
+      if (!(ban->flags & (BAN_OVERLAPPED|BAN_DEL))) {
+        count++;
+        totlen += strlen(ban->banstr);
+      }
+    }
+    /* Mark more specific entries and add this one to the end of the list. */
+    while ((ban = *banlist) != NULL) {
+      if (!bmatch(newban, ban)) {
+        ban->flags |= BAN_OVERLAPPED | BAN_DEL;
+      }
+      banlist = &ban->next;
+    }
+    *banlist = newban;
+    return 0;
+  } else if (newban->flags & BAN_DEL) {
+    size_t remove_count = 0;
+    /* Mark more specific entries. */
+    for (ban = *banlist; ban; ban = ban->next) {
+      if (!bmatch(newban, ban)) {
+        ban->flags |= BAN_OVERLAPPED | BAN_DEL;
+        remove_count++;
+      }
+    }
+    if (remove_count)
+        return 0;
+    /* If no matches were found, fail. */
+    if (do_free)
+      free_ban(newban);
+    return 3;
+  }
+  if (do_free)
+    free_ban(newban);
+  return 4;
+}
+
+/* Removes MODE_WASDELJOINS in a channel.
+ * Reveals all hidden users.
+ */
+static void reveal_hidden_chan_users(struct ParseState *state, int *flag_p) {
+    struct Membership *member;
+
+    /* If the channel is not +d, do nothing. */
+    if(!(state->chptr->mode.mode & MODE_WASDELJOINS)) return;
+
+    /* Iterate through all members and reveal them if they are hidden. */
+    for(member = state->chptr->members; member; member = member->next_member) {
+        if(IsDelayedJoin(member) && !IsInvisibleJoin(member)) {
+            RevealDelayedJoin(member);
+        }
+    }
+}
+
+/*
+ * Helper function to convert bans
+ */
+static void
+mode_parse_ban(struct ParseState *state, int *flag_p)
+{
+  char *t_str, *s;
+  struct Ban *ban, *newban;
+
+  if (state->parc <= 0) { /* Not enough args, send ban list */
+    if (MyUser(state->sptr)) {
+      if (*flag_p == MODE_EXCEPTION) {
+        if (!(state->done & DONE_EXCEPTIONLIST)) {
+          send_exception_list(state->sptr, state->chptr);
+          state->done |= DONE_EXCEPTIONLIST;
+        }
+      }
+      else {
+        if (!(state->done & DONE_BANLIST)) {
+          send_ban_list(state->sptr, state->chptr);
+          state->done |= DONE_BANLIST;
+        }
+      }
+    }
+    return;
+  }
+
+  if (MyUser(state->sptr) && state->max_args <= 0) /* drop if too many args */
+    return;
+
+  t_str = state->parv[state->args_used++]; /* grab arg */
+  state->parc--;
+  state->max_args--;
+
+  /* If they're not an oper, they can't change modes */
+  if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
+    send_notoper(state);
+    return;
+  }
+
+  if ((s = strchr(t_str, ' ')))
+    *s = '\0';
+
+  if (!*t_str || *t_str == ':') { /* warn if empty */
+    if (MyUser(state->sptr))
+      need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +b" :
+                      "MODE -b");
+    return;
+  }
+
+  /* Clear all ADD/DEL/OVERLAPPED flags from ban list. */
+  if (!(state->done & DONE_BANCLEAN)) {
+    for (ban = state->chptr->banlist; ban; ban = ban->next)
+      ban->flags &= ~(BAN_ADD | BAN_DEL | BAN_OVERLAPPED);
+    state->done |= DONE_BANCLEAN;
+  }
+
+  /* remember the ban for the moment... */
+  newban = state->banlist + (state->numbans++);
+  newban->next = 0;
+  newban->flags = ((state->dir == MODE_ADD) ? BAN_ADD : BAN_DEL)
+      | (*flag_p == MODE_BAN ? 0 : BAN_EXCEPTION);
+  set_ban_mask(newban, collapse(pretty_mask(t_str)));
+  ircd_strncpy(newban->who, IsUser(state->sptr) ? cli_name(state->sptr) : "*", NICKLEN);
+  newban->when = TStime();
+  apply_ban(&state->chptr->banlist, newban, 0);
+}
+
+/*
+ * This is the bottom half of the ban processor
+ */
+static void
+mode_process_bans(struct ParseState *state)
+{
+  struct Ban *ban, *newban, *prevban, *nextban;
+  int count = 0;
+  int len = 0;
+  int banlen;
+  int changed = 0;
+
+  for (prevban = 0, ban = state->chptr->banlist; ban; ban = nextban) {
+    count++;
+    banlen = strlen(ban->banstr);
+    len += banlen;
+    nextban = ban->next;
+
+    if ((ban->flags & (BAN_DEL | BAN_ADD)) == (BAN_DEL | BAN_ADD)) {
+      if (prevban)
+       prevban->next = 0; /* Break the list; ban isn't a real ban */
+      else
+       state->chptr->banlist = 0;
+
+      count--;
+      len -= banlen;
+
+      continue;
+    } else if (ban->flags & BAN_DEL) { /* Deleted a ban? */
+      char *bandup;
+      DupString(bandup, ban->banstr);
+      modebuf_mode_string(state->mbuf, MODE_DEL | ((ban->flags & BAN_EXCEPTION) ? MODE_EXCEPTION : MODE_BAN),
+                         bandup, 1);
+
+      if (state->flags & MODE_PARSE_SET) { /* Ok, make it take effect */
+       if (prevban) /* clip it out of the list... */
+         prevban->next = ban->next;
+       else
+         state->chptr->banlist = ban->next;
+
+       count--;
+       len -= banlen;
+        free_ban(ban);
+
+       changed++;
+       continue; /* next ban; keep prevban like it is */
+      } else
+       ban->flags &= BAN_IPMASK; /* unset other flags */
+    } else if (ban->flags & BAN_ADD) { /* adding a ban? */
+      if (prevban)
+       prevban->next = 0; /* Break the list; ban isn't a real ban */
+      else
+       state->chptr->banlist = 0;
+
+      /* If we're supposed to ignore it, do so. */
+      if (ban->flags & BAN_OVERLAPPED &&
+         !(state->flags & MODE_PARSE_BOUNCE)) {
+       count--;
+       len -= banlen;
+      } else {
+       if (state->flags & MODE_PARSE_SET && MyUser(state->sptr) &&
+           (len > (feature_int(FEAT_AVBANLEN) * feature_int(FEAT_MAXBANS)) ||
+            count > feature_int(FEAT_MAXBANS))) {
+         send_reply(state->sptr, ERR_BANLISTFULL, state->chptr->chname,
+                    ban->banstr);
+         count--;
+         len -= banlen;
+       } else {
+          char *bandup;
+         /* add the ban to the buffer */
+          DupString(bandup, ban->banstr);
+          modebuf_mode_string(state->mbuf, MODE_ADD | ((ban->flags & BAN_EXCEPTION) ? MODE_EXCEPTION : MODE_BAN),
+                             bandup, 1);
+
+         if (state->flags & MODE_PARSE_SET) { /* create a new ban */
+           newban = make_ban(ban->banstr);
+            strcpy(newban->who, ban->who);
+           newban->when = ban->when;
+           newban->flags = ban->flags & (BAN_IPMASK | BAN_EXCEPTION);
+
+           newban->next = state->chptr->banlist; /* and link it in */
+           state->chptr->banlist = newban;
+
+           changed++;
+         }
+       }
+      }
+    }
+
+    prevban = ban;
+  } /* for (prevban = 0, ban = state->chptr->banlist; ban; ban = nextban) { */
+
+  if (changed) /* if we changed the ban list, we must invalidate the bans */
+    mode_ban_invalidate(state->chptr);
+}
+
+/*
+ * Helper function to process client changes
+ */
+static void
+mode_parse_client(struct ParseState *state, int *flag_p)
+{
+  char *t_str;
+  char *colon;
+  struct Client *acptr;
+  struct Membership *member;
+  int oplevel = MAXOPLEVEL + 1;
+  int req_oplevel;
+  int i;
+
+  if (MyUser(state->sptr) && state->max_args <= 0) /* drop if too many args */
+    return;
+
+  if (state->parc <= 0) /* return if not enough args */
+    return;
+
+  t_str = state->parv[state->args_used++]; /* grab arg */
+  state->parc--;
+  state->max_args--;
+
+  /* If they're not an oper, they can't change modes */
+  if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
+    send_notoper(state);
+    return;
+  }
+
+  if (MyUser(state->sptr)) {
+    colon = strchr(t_str, ':');
+    if (colon != NULL) {
+      *colon++ = '\0';
+      req_oplevel = atoi(colon);
+      if (*flag_p == CHFL_VOICE || state->dir == MODE_DEL) {
+        /* Ignore the colon and its argument. */
+      } else if (!(state->flags & MODE_PARSE_FORCE)
+          && state->member
+          && (req_oplevel < OpLevel(state->member)
+              || (req_oplevel == OpLevel(state->member)
+                  && OpLevel(state->member) < MAXOPLEVEL)
+              || req_oplevel > MAXOPLEVEL)) {
+        send_reply(state->sptr, ERR_NOTLOWEROPLEVEL,
+                   t_str, state->chptr->chname,
+                   OpLevel(state->member), req_oplevel, "op",
+                   OpLevel(state->member) == req_oplevel ? "the same" : "a higher");
+      } else if (req_oplevel <= MAXOPLEVEL)
+        oplevel = req_oplevel;
+    }
+    /* find client we're manipulating */
+    acptr = find_chasing(state->sptr, t_str, NULL);
+  } else {
+    if (t_str[5] == ':') {
+      t_str[5] = '\0';
+      oplevel = atoi(t_str + 6);
+    }
+    acptr = findNUser(t_str);
+  }
+
+  if (!acptr)
+    return; /* find_chasing() already reported an error to the user */
+
+  for (i = 0; i < MAXPARA; i++) /* find an element to stick them in */
+    if (!state->cli_change[i].flag || (state->cli_change[i].client == acptr &&
+                                      state->cli_change[i].flag & flag_p[0]))
+      break; /* found a slot */
+
+  /* If we are going to bounce this deop, mark the correct oplevel. */
+  if (state->flags & MODE_PARSE_BOUNCE
+      && state->dir == MODE_DEL
+      && flag_p[0] == MODE_CHANOP
+      && (member = find_member_link(state->chptr, acptr)))
+      oplevel = OpLevel(member);
+
+  /* Store what we're doing to them */
+  state->cli_change[i].flag = state->dir | flag_p[0];
+  state->cli_change[i].oplevel = oplevel;
+  state->cli_change[i].client = acptr;
+}
+
+/*
+ * Helper function to process the changed client list
+ */
+static void
+mode_process_clients(struct ParseState *state)
+{
+  int i;
+  struct Membership *member;
+
+  for (i = 0; state->cli_change[i].flag; i++) {
+    assert(0 != state->cli_change[i].client);
+
+    /* look up member link */
+    if (!(member = find_member_link(state->chptr,
+                                   state->cli_change[i].client)) ||
+       (MyUser(state->sptr) && IsZombie(member))) {
+      if (MyUser(state->sptr))
+       send_reply(state->sptr, ERR_USERNOTINCHANNEL,
+                  cli_name(state->cli_change[i].client),
+                  state->chptr->chname);
+      continue;
+    }
+       if (member && (IsInvisibleJoin(member) &&  state->cli_change[i].client != state->sptr) && IsDelayedJoin(member)) {
+       if (MyUser(state->sptr))
+       send_reply(state->sptr, ERR_USERNOTINCHANNEL,
+                  cli_name(state->cli_change[i].client),
+                  state->chptr->chname);
+      continue;
+       }
+
+    if ((state->cli_change[i].flag & MODE_ADD &&
+        (state->cli_change[i].flag & member->status)) ||
+       (state->cli_change[i].flag & MODE_DEL &&
+        !(state->cli_change[i].flag & member->status)))
+      continue; /* no change made, don't do anything */
+
+    /* see if the deop is allowed */
+    if ((state->cli_change[i].flag & (MODE_DEL | MODE_CHANOP)) ==
+       (MODE_DEL | MODE_CHANOP)) {
+      /* Prevent +k users from being deopped, but allow extra ops to deop
+       * +k users. We do not prevent deopping _REAL_ services because /opmode
+       * will always allow this.
+       */
+      if(IsChannelService(state->cli_change[i].client) && !IsXtraOp(state->sptr) && state->sptr != state->cli_change[i].client) {
+       if (state->flags & MODE_PARSE_FORCE) /* it was forced */
+         sendto_opmask_butone(0, SNO_HACK4, "Deop of +k user on %H by %s",
+                              state->chptr,
+                              (IsServer(state->sptr) ? cli_name(state->sptr) :
+                               cli_name((cli_user(state->sptr))->server)));
+
+       else if (MyUser(state->sptr) && state->flags & MODE_PARSE_SET) {
+         send_reply(state->sptr, ERR_ISCHANSERVICE,
+                    cli_name(state->cli_change[i].client),
+                    state->chptr->chname);
+         continue;
+       }
+      }
+
+      /* check deop for local user */
+      if (MyUser(state->sptr)) {
+
+       /* don't allow local opers to be deopped on local channels */
+       if (state->cli_change[i].client != state->sptr &&
+           IsLocalChannel(state->chptr->chname) &&
+           HasPriv(state->cli_change[i].client, PRIV_DEOP_LCHAN)) {
+         send_reply(state->sptr, ERR_ISOPERLCHAN,
+                    cli_name(state->cli_change[i].client),
+                    state->chptr->chname);
+         continue;
+        }
+
+       /* Forbid deopping other members with an oplevel less than
+         * one's own level, and other members with an oplevel the same
+         * as one's own unless both are at MAXOPLEVEL. */
+       if (state->sptr != state->cli_change[i].client
+            && state->member
+            && ((OpLevel(member) < OpLevel(state->member))
+                || (OpLevel(member) == OpLevel(state->member)
+                    && OpLevel(member) < MAXOPLEVEL))) {
+           int equal = (OpLevel(member) == OpLevel(state->member));
+           send_reply(state->sptr, ERR_NOTLOWEROPLEVEL,
+                      cli_name(state->cli_change[i].client),
+                      state->chptr->chname,
+                      OpLevel(state->member), OpLevel(member),
+                      "deop", equal ? "the same" : "a higher");
+         continue;
+       }
+      }
+    }
+
+    /* set op-level of member being opped */
+    if ((state->cli_change[i].flag & (MODE_ADD | MODE_CHANOP)) ==
+       (MODE_ADD | MODE_CHANOP)) {
+      /* If a valid oplevel was specified, use it.
+       * Otherwise, if being opped by an outsider, get MAXOPLEVEL.
+       * Otherwise, if not an apass channel, or state->member has
+       *   MAXOPLEVEL, get oplevel MAXOPLEVEL.
+       * Otherwise, get state->member's oplevel+1.
+       */
+      if (state->cli_change[i].oplevel <= MAXOPLEVEL)
+        SetOpLevel(member, state->cli_change[i].oplevel);
+      else if (!state->member)
+        SetOpLevel(member, MAXOPLEVEL);
+      else if (OpLevel(state->member) >= MAXOPLEVEL)
+          SetOpLevel(member, OpLevel(state->member));
+      else
+        SetOpLevel(member, OpLevel(state->member) + 1);
+    }
+
+    /* actually effect the change */
+    if (state->flags & MODE_PARSE_SET) {
+      if (state->cli_change[i].flag & MODE_ADD) {
+        if (IsDelayedJoin(member) && !IsZombie(member))
+          RevealDelayedJoin(member);
+       member->status |= (state->cli_change[i].flag &
+                          (MODE_CHANOP | MODE_VOICE));
+       if (state->cli_change[i].flag & MODE_CHANOP)
+         ClearDeopped(member);
+      } else
+       member->status &= ~(state->cli_change[i].flag &
+                           (MODE_CHANOP | MODE_VOICE));
+    }
+
+    /* accumulate the change */
+    modebuf_mode_client(state->mbuf, state->cli_change[i].flag,
+                       state->cli_change[i].client,
+                        state->cli_change[i].oplevel);
+  } /* for (i = 0; state->cli_change[i].flags; i++) */
+}
+
+/*
+ * Helper function to process the simple modes
+ */
+static void
+mode_parse_mode(struct ParseState *state, int *flag_p)
+{
+  /* If they're not an oper, they can't change modes */
+  if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
+    send_notoper(state);
+    return;
+  }
+
+  if (!state->mbuf)
+    return;
+
+  /* Local users are not permitted to change registration status */
+  if (flag_p[0] == MODE_REGISTERED && !(state->flags & MODE_PARSE_FORCE) && MyUser(state->sptr))
+    return;
+
+  if (state->dir == MODE_ADD) {
+    state->add |= flag_p[0];
+    state->del &= ~flag_p[0];
+
+    if (flag_p[0] & MODE_SECRET) {
+      state->add &= ~MODE_PRIVATE;
+      state->del |= MODE_PRIVATE;
+    } else if (flag_p[0] & MODE_PRIVATE) {
+      state->add &= ~MODE_SECRET;
+      state->del |= MODE_SECRET;
+    }
+  } else {
+    state->add &= ~flag_p[0];
+    state->del |= flag_p[0];
+  }
+
+  assert(0 == (state->add & state->del));
+  assert((MODE_SECRET | MODE_PRIVATE) !=
+        (state->add & (MODE_SECRET | MODE_PRIVATE)));
+}
+
+/**
+ * This routine is intended to parse MODE or OPMODE commands and effect the
+ * changes (or just build the bounce buffer).
+ *
+ * \param[out] mbuf Receives parsed representation of mode change.
+ * \param[in] cptr Connection that sent the message to this server.
+ * \param[in] sptr Original source of the message.
+ * \param[in] chptr Channel whose modes are being changed.
+ * \param[in] parc Number of valid strings in \a parv.
+ * \param[in] parv Text arguments representing mode change, with the
+ *   zero'th element containing a string like "+m" or "-o".
+ * \param[in] flags Set of bitwise MODE_PARSE_* flags.
+ * \param[in] member If non-null, the channel member attempting to change the modes.
+ */
+int
+mode_parse(struct ModeBuf *mbuf, struct Client *cptr, struct Client *sptr,
+          struct Channel *chptr, int parc, char *parv[], unsigned int flags,
+          struct Membership* member)
+{
+  static int chan_flags[] = {
+    MODE_CHANOP,       'o',
+    MODE_VOICE,                'v',
+    MODE_PRIVATE,      'p',
+    MODE_SECRET,       's',
+    MODE_MODERATED,    'm',
+    MODE_TOPICLIMIT,   't',
+    MODE_INVITEONLY,   'i',
+    MODE_NOPRIVMSGS,   'n',
+    MODE_KEY,          'k',
+    MODE_APASS,                'A',
+    MODE_UPASS,                'U',
+    MODE_REGISTERED,   'R',
+    MODE_BAN,          'b',
+    MODE_LIMIT,                'l',
+    MODE_REGONLY,      'r',
+    MODE_DELJOINS,      'D',
+    MODE_WASDELJOINS,   'd',
+    MODE_PERSIST,       'z',
+    MODE_NOCOLOUR,      'c',
+    MODE_NOCTCP,        'C',
+/*    MODE_EXCEPTION,     'e',*/
+    MODE_NOAMSGS,       'M',
+       MODE_NONOTICE,      'N',
+       MODE_QUARANTINE,      'Q',
+       MODE_ALTCHAN,        'F',
+    MODE_ACCESS,        'a',
+    MODE_ADD,          '+',
+    MODE_DEL,          '-',
+    0x0, 0x0
+  };
+  int i;
+  int *flag_p;
+  unsigned int t_mode;
+  char *modestr;
+  struct ParseState state;
+
+  assert(0 != cptr);
+  assert(0 != sptr);
+  assert(0 != chptr);
+  assert(0 != parc);
+  assert(0 != parv);
+
+  state.mbuf = mbuf;
+  state.cptr = cptr;
+  state.sptr = sptr;
+  state.chptr = chptr;
+  state.member = member;
+  state.parc = parc;
+  state.parv = parv;
+  state.flags = flags;
+  state.dir = MODE_ADD;
+  state.done = 0;
+  state.add = 0;
+  state.del = 0;
+  state.args_used = 0;
+  state.max_args = MAXMODEPARAMS;
+  state.numbans = 0;
+
+  for (i = 0; i < MAXPARA; i++) { /* initialize ops/voices arrays */
+    state.banlist[i].next = 0;
+    state.banlist[i].who[0] = '\0';
+    state.banlist[i].when = 0;
+    state.banlist[i].flags = 0;
+    state.cli_change[i].flag = 0;
+    state.cli_change[i].client = 0;
+  }
+
+  modestr = state.parv[state.args_used++];
+  state.parc--;
+
+  while (*modestr) {
+    for (; *modestr; modestr++) {
+      for (flag_p = chan_flags; flag_p[0]; flag_p += 2) /* look up flag */
+       if (flag_p[1] == *modestr)
+         break;
+
+      if (!flag_p[0]) { /* didn't find it?  complain and continue */
+       if (MyUser(state.sptr))
+         send_reply(state.sptr, ERR_UNKNOWNMODE, *modestr);
+       continue;
+      }
+
+      switch (*modestr) {
+      case '+': /* switch direction to MODE_ADD */
+      case '-': /* switch direction to MODE_DEL */
+       state.dir = flag_p[0];
+       break;
+
+      case 'l': /* deal with limits */
+       mode_parse_limit(&state, flag_p);
+       break;
+      case 'a': /* deal with limits */
+       mode_parse_access(&state, flag_p);
+       break;
+         case 'F':
+       mode_parse_altchan(&state, flag_p);
+       break;
+      case 'Q':
+      if(IsNetServ(state.sptr) && IsSecurityServ(state.sptr))
+        mode_parse_mode(&state, flag_p);
+       break;
+      case 'k': /* deal with keys */
+       mode_parse_key(&state, flag_p);
+       break;
+      case 'A': /* deal with Admin passes */
+        if (IsServer(cptr) || feature_bool(FEAT_OPLEVELS))
+       mode_parse_apass(&state, flag_p);
+       break;
+      case 'U': /* deal with user passes */
+        if (IsServer(cptr) || feature_bool(FEAT_OPLEVELS))
+       mode_parse_upass(&state, flag_p);
+       break;
+
+/*      case 'e':
+        if(MyUser(state.sptr) && !(state.flags & MODE_PARSE_FORCE) && !feature_bool(FEAT_EXCEPT_ENABLE)) break;*/
+      case 'b': /* deal with bans */
+       mode_parse_ban(&state, flag_p);
+        break;
+
+      case 'd': /* deal with hidden members */
+        reveal_hidden_chan_users(&state, flag_p);
+        break;
+
+      case 'o': /* deal with ops/voice */
+      case 'v':
+       mode_parse_client(&state, flag_p);
+       break;
+
+      case 'z': /* remote clients are allowed to change +z */
+        if(!MyUser(state.sptr) || (state.flags & MODE_PARSE_FORCE))
+          mode_parse_mode(&state, flag_p);
+        break;
+         case 'O': /* remote clients are allowed to change +z */
+           //struct User* user = cli_user(cptr);
+               //|| (chptr.chanowner && IsAccount(cptr) && chptr.chanowner == user->account)
+        if(!MyUser(state.sptr) || (state.flags & MODE_PARSE_FORCE) )
+          mode_parse_mode(&state, flag_p);
+        break;
+
+      default: /* deal with other modes */
+       mode_parse_mode(&state, flag_p);
+       break;
+      } /* switch (*modestr) */
+    } /* for (; *modestr; modestr++) */
+
+    if (state.flags & MODE_PARSE_BURST)
+      break; /* don't interpret any more arguments */
+
+    if (state.parc > 0) { /* process next argument in string */
+      modestr = state.parv[state.args_used++];
+      state.parc--;
+
+      /* is it a TS? */
+      if (IsServer(state.cptr) && !state.parc && IsDigit(*modestr)) {
+       time_t recv_ts;
+
+       if (!(state.flags & MODE_PARSE_SET))      /* don't set earlier TS if */
+         break;                     /* we're then going to bounce the mode! */
+
+       recv_ts = atoi(modestr);
+
+       if (recv_ts && recv_ts < state.chptr->creationtime)
+         state.chptr->creationtime = recv_ts; /* respect earlier TS */
+        else if (recv_ts > state.chptr->creationtime) {
+          struct Client *sserv;
+
+          /* Check whether the originating server has fully processed
+           * the burst to it. */
+          sserv = state.cptr;
+          if (!IsServer(sserv))
+              sserv = cli_user(sserv)->server;
+          if (IsBurstOrBurstAck(sserv)) {
+            /* This is a legal but unusual case; the source server
+             * probably just has not processed the BURST for this
+             * channel.  It SHOULD wipe out all its modes soon, so
+             * silently ignore the mode change rather than send a
+             * bounce that could desync modes from our side (that
+             * have already been sent).
+             */
+            state.mbuf->mb_add = 0;
+            state.mbuf->mb_rem = 0;
+            state.mbuf->mb_count = 0;
+            return state.args_used;
+          } else {
+            /* Server is desynced; bounce the mode and deop the source
+             * to fix it. */
+            state.flags &= ~MODE_PARSE_SET;
+            state.flags |= MODE_PARSE_BOUNCE;
+            state.mbuf->mb_dest &= ~(MODEBUF_DEST_CHANNEL | MODEBUF_DEST_HACK4);
+            state.mbuf->mb_dest |= MODEBUF_DEST_BOUNCE | MODEBUF_DEST_HACK2;
+            if (!IsServer(state.cptr))
+              state.mbuf->mb_dest |= MODEBUF_DEST_DEOP;
+          }
+        }
+
+       break; /* break out of while loop */
+      } else if (state.flags & MODE_PARSE_STRICT ||
+                (MyUser(state.sptr) && state.max_args <= 0)) {
+       state.parc++; /* we didn't actually gobble the argument */
+       state.args_used--;
+       break; /* break out of while loop */
+      }
+    }
+  } /* while (*modestr) */
+
+  /*
+   * the rest of the function finishes building resultant MODEs; if the
+   * origin isn't a member or an oper, skip it.
+   */
+  if (!state.mbuf || state.flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER))
+    return state.args_used; /* tell our parent how many args we gobbled */
+
+  t_mode = state.chptr->mode.mode;
+
+  if (state.del & t_mode) { /* delete any modes to be deleted... */
+    modebuf_mode(state.mbuf, MODE_DEL | (state.del & t_mode));
+
+    t_mode &= ~state.del;
+  }
+  if (state.add & ~t_mode) { /* add any modes to be added... */
+    modebuf_mode(state.mbuf, MODE_ADD | (state.add & ~t_mode));
+
+    t_mode |= state.add;
+  }
+
+  if (state.flags & MODE_PARSE_SET) { /* set the channel modes */
+    if ((state.chptr->mode.mode & MODE_INVITEONLY) &&
+       !(t_mode & MODE_INVITEONLY))
+      mode_invite_clear(state.chptr);
+
+    state.chptr->mode.mode = t_mode;
+  }
+
+  if (state.flags & MODE_PARSE_WIPEOUT) {
+    if (state.chptr->mode.limit && !(state.done & DONE_LIMIT))
+      modebuf_mode_uint(state.mbuf, MODE_DEL | MODE_LIMIT,
+                       state.chptr->mode.limit);
+    if (state.chptr->mode.access && !(state.done & DONE_ACCESS))
+      modebuf_mode_uint(state.mbuf, MODE_DEL | MODE_ACCESS,
+                       state.chptr->mode.access);
+    if (state.chptr->mode.altchan && !(state.done & DONE_ALTCHAN))
+      modebuf_mode_string(state.mbuf, MODE_DEL | MODE_ALTCHAN,
+                       state.chptr->mode.altchan, 0);
+    if (*state.chptr->mode.key && !(state.done & DONE_KEY_DEL))
+      modebuf_mode_string(state.mbuf, MODE_DEL | MODE_KEY,
+                         state.chptr->mode.key, 0);
+    if (*state.chptr->mode.upass && !(state.done & DONE_UPASS_DEL))
+      modebuf_mode_string(state.mbuf, MODE_DEL | MODE_UPASS,
+                         state.chptr->mode.upass, 0);
+    if (*state.chptr->mode.apass && !(state.done & DONE_APASS_DEL))
+      modebuf_mode_string(state.mbuf, MODE_DEL | MODE_APASS,
+                         state.chptr->mode.apass, 0);
+  }
+
+  if (state.done & DONE_BANCLEAN) /* process bans */
+    mode_process_bans(&state);
+
+  /* process client changes */
+  if (state.cli_change[0].flag)
+    mode_process_clients(&state);
+
+  return state.args_used; /* tell our parent how many args we gobbled */
+}
+
+/*
+ * Initialize a join buffer
+ */
+void
+joinbuf_init(struct JoinBuf *jbuf, struct Client *source,
+            struct Client *connect, unsigned int type, char *comment,
+            time_t create)
+{
+  int i;
+
+  assert(0 != jbuf);
+  assert(0 != source);
+  assert(0 != connect);
+
+  jbuf->jb_source = source; /* just initialize struct JoinBuf */
+  jbuf->jb_connect = connect;
+  jbuf->jb_type = type;
+  jbuf->jb_comment = comment;
+  jbuf->jb_create = create;
+  jbuf->jb_count = 0;
+  jbuf->jb_strlen = (((type == JOINBUF_TYPE_JOIN ||
+                      type == JOINBUF_TYPE_PART ||
+                      type == JOINBUF_TYPE_PARTALL) ?
+                     STARTJOINLEN : STARTCREATELEN) +
+                    (comment ? strlen(comment) + 2 : 0));
+
+  for (i = 0; i < MAXJOINARGS; i++)
+    jbuf->jb_channels[i] = 0;
+}
+
+/*
+ * Add a channel to the join buffer
+ */
+void
+joinbuf_join(struct JoinBuf *jbuf, struct Channel *chan, unsigned int flags)
+{
+  unsigned int len;
+  int is_local;
+
+  assert(0 != jbuf);
+
+  if (!chan) {
+    sendcmdto_serv_butone(jbuf->jb_source, CMD_JOIN, jbuf->jb_connect, "0");
+    return;
+  }
+
+  is_local = IsLocalChannel(chan->chname);
+
+  if (jbuf->jb_type == JOINBUF_TYPE_PART ||
+      jbuf->jb_type == JOINBUF_TYPE_PARTALL) {
+    struct Membership *member = find_member_link(chan, jbuf->jb_source);
+    if (IsUserParting(member))
+      return;
+    SetUserParting(member);
+
+    /* Send notification to channel */
+    if (!(flags & (CHFL_ZOMBIE | CHFL_DELAYED)))
+      sendcmdto_channel_butserv_butone(jbuf->jb_source, CMD_PART, chan, NULL, 0,
+                               (flags & CHFL_BANNED || !jbuf->jb_comment) ?
+                               ":%H" : "%H :%s", chan, jbuf->jb_comment);
+    else if (MyUser(jbuf->jb_source))
+      sendcmdto_one(jbuf->jb_source, CMD_PART, jbuf->jb_source,
+                   (flags & CHFL_BANNED || !jbuf->jb_comment) ?
+                   ":%H" : "%H :%s", chan, jbuf->jb_comment);
+    /* XXX: Shouldn't we send a PART here anyway? */
+    /* to users on the channel?  Why?  From their POV, the user isn't on
+     * the channel anymore anyway.  We don't send to servers until below,
+     * when we gang all the channel parts together.  Note that this is
+     * exactly the same logic, albeit somewhat more concise, as was in
+     * the original m_part.c */
+
+    if (jbuf->jb_type == JOINBUF_TYPE_PARTALL ||
+       is_local) /* got to remove user here */
+      remove_user_from_channel(jbuf->jb_source, chan);
+  } else {
+    int oplevel = !chan->mode.apass[0] ? MAXOPLEVEL
+        : (flags & CHFL_CHANNEL_MANAGER) ? 0
+        : 1;
+    /* Add user to channel */
+    if (((chan->mode.mode & MODE_DELJOINS) && !(flags & CHFL_VOICED_OR_OPPED)) || ((flags & CHFL_INVISIBLE) && !(flags & CHFL_VOICED_OR_OPPED))) {
+      add_user_to_channel(chan, jbuf->jb_source, flags | CHFL_DELAYED, oplevel);
+    } else
+      add_user_to_channel(chan, jbuf->jb_source, flags, oplevel);
+
+    /* send JOIN notification to all servers (CREATE is sent later). */
+    if (jbuf->jb_type != JOINBUF_TYPE_CREATE && !is_local) {
+        if ((flags & CHFL_INVISIBLE) && !(flags & CHFL_VOICED_OR_OPPED)) {
+      sendcmdto_serv_butone(jbuf->jb_source, CMD_JOIN, jbuf->jb_connect,
+                           "%H %Tu %i", chan, chan->creationtime, 1);
+         } else {
+         sendcmdto_serv_butone(jbuf->jb_source, CMD_JOIN, jbuf->jb_connect,
+                           "%H %Tu %i", chan, chan->creationtime, 0);
+         }
+       }
+
+    if (!((chan->mode.mode & MODE_DELJOINS) && !(flags & CHFL_VOICED_OR_OPPED)) && !((flags & CHFL_INVISIBLE) && !(flags & CHFL_VOICED_OR_OPPED))) {
+      /* Send the notification to the channel */
+      sendcmdto_channel_butserv_butone(jbuf->jb_source, CMD_JOIN, chan, NULL, 0, "%H", chan);
+
+      /* send an op, too, if needed */
+      if (flags & CHFL_CHANOP && (oplevel < MAXOPLEVEL || !MyUser(jbuf->jb_source)))
+       sendcmdto_channel_butserv_butone((chan->mode.apass[0] ? &his : jbuf->jb_source),
+                                         CMD_MODE, chan, NULL, 0, "%H +o %C",
+                                        chan, jbuf->jb_source);
+    } else if (MyUser(jbuf->jb_source)) {
+      sendcmdto_one(jbuf->jb_source, CMD_JOIN, jbuf->jb_source, ":%H", chan);
+       }
+  }
+
+  if (jbuf->jb_type == JOINBUF_TYPE_PARTALL ||
+      jbuf->jb_type == JOINBUF_TYPE_JOIN || is_local)
+    return; /* don't send to remote */
+
+  /* figure out if channel name will cause buffer to be overflowed */
+  len = chan ? strlen(chan->chname) + 1 : 2;
+  if (jbuf->jb_strlen + len > BUFSIZE)
+    joinbuf_flush(jbuf);
+
+  /* add channel to list of channels to send and update counts */
+  jbuf->jb_channels[jbuf->jb_count++] = chan;
+  jbuf->jb_strlen += len;
+
+  /* if we've used up all slots, flush */
+  if (jbuf->jb_count >= MAXJOINARGS)
+    joinbuf_flush(jbuf);
+}
+
+/*
+ * Flush the channel list to remote servers
+ */
+int
+joinbuf_flush(struct JoinBuf *jbuf)
+{
+  char chanlist[BUFSIZE];
+  int chanlist_i = 0;
+  int i;
+
+  if (!jbuf->jb_count || jbuf->jb_type == JOINBUF_TYPE_PARTALL ||
+      jbuf->jb_type == JOINBUF_TYPE_JOIN)
+    return 0; /* no joins to process */
+
+  for (i = 0; i < jbuf->jb_count; i++) { /* build channel list */
+    build_string(chanlist, &chanlist_i,
+                jbuf->jb_channels[i] ? jbuf->jb_channels[i]->chname : "0", 0,
+                i == 0 ? '\0' : ',');
+    if (JOINBUF_TYPE_PART == jbuf->jb_type)
+      /* Remove user from channel */
+      remove_user_from_channel(jbuf->jb_source, jbuf->jb_channels[i]);
+
+    jbuf->jb_channels[i] = 0; /* mark slot empty */
+  }
+
+  jbuf->jb_count = 0; /* reset base counters */
+  jbuf->jb_strlen = ((jbuf->jb_type == JOINBUF_TYPE_PART ?
+                     STARTJOINLEN : STARTCREATELEN) +
+                    (jbuf->jb_comment ? strlen(jbuf->jb_comment) + 2 : 0));
+
+  /* and send the appropriate command */
+  switch (jbuf->jb_type) {
+  case JOINBUF_TYPE_CREATE:
+    sendcmdto_serv_butone(jbuf->jb_source, CMD_CREATE, jbuf->jb_connect,
+                         "%s %Tu", chanlist, jbuf->jb_create);
+    break;
+
+  case JOINBUF_TYPE_PART:
+    sendcmdto_serv_butone(jbuf->jb_source, CMD_PART, jbuf->jb_connect,
+                         jbuf->jb_comment ? "%s :%s" : "%s", chanlist,
+                         jbuf->jb_comment);
+    break;
+  }
+
+  return 0;
+}
+
+/* Returns TRUE (1) if client is invited, FALSE (0) if not */
+int IsInvited(struct Client* cptr, const void* chptr)
+{
+  struct SLink *lp;
+
+  for (lp = (cli_user(cptr))->invited; lp; lp = lp->next)
+    if (lp->value.chptr == chptr)
+      return 1;
+  return 0;
+}
+
+/* RevealDelayedJoin: sends a join for a hidden user */
+
+void RevealDelayedJoin(struct Membership *member)
+{
+  ClearDelayedJoin(member);
+  sendcmdto_channel_butserv_butone(member->user, CMD_JOIN, member->channel, member->user, 0, ":%H",
+                                   member->channel);
+  CheckDelayedJoins(member->channel);
+}
+
+/* CheckDelayedJoins: checks and clear +d if necessary */
+
+void CheckDelayedJoins(struct Channel *chan)
+{
+  if ((chan->mode.mode & MODE_WASDELJOINS) && !find_delayed_joins(chan)) {
+    chan->mode.mode &= ~MODE_WASDELJOINS;
+    sendcmdto_channel_butserv_butone(&me, CMD_MODE, chan, NULL, 0,
+                                     "%H -d", chan);
+    sendcmdto_channel_servers_butone(&me, CMD_MODE, chan, NULL, 0,
+                                     "%H -d", chan);
+  }
+}
+
+/* checks whether a channel is nonpersistent with no users and deletes it
+ * returns 1 if deleted, otherwise 0
+ */
+signed int destruct_nonpers_channel(struct Channel *chptr) {
+  if(!(chptr->mode.mode & MODE_PERSIST) && chptr->users == 0) {
+    if(chptr->destruct_event)
+      remove_destruct_event(chptr);
+    destruct_channel(chptr);
+    return 1;
+  }
+  return 0;
+}
+
+/** Send a join for the user if (s)he is a hidden member of the channel.
+ */
+void RevealDelayedJoinIfNeeded(struct Client *sptr, struct Channel *chptr)
+{
+  struct Membership *member = find_member_link(chptr, sptr);
+  if (member && IsDelayedJoin(member) && !IsInvisibleJoin(member))
+    RevealDelayedJoin(member);
+}
+
+/** Extended multi target message block check.
+ * The channelmode MODE_NOAMSGS prevents multi-target messages from being sent
+ * to the channel. Since many clients sent these so called AMSGS manually with
+ * one PRIVMSG per channel, we have this extended check which prevents messages
+ * from being sent to multiple channels.
+ *
+ * The check is quite simple: We save the last sent message of every client.
+ * When the client sends a new PRIVMSG to another channel, we compare the
+ * message to the previously sent message and if they equal we may drop the new
+ * message instead of broadcasting it.
+ * There are several additional checks. That is, the new message must be sent in
+ * a specific amount of time in which this check works. If the ducplicate
+ * message is delayed for too long then it will pass this check. Furthermore,
+ * there is a specific number a message must be already sent to different
+ * channels until it is blocked.
+ * Both numbers can be configured by the FEATURES subsystem.
+ *
+ * This function returns 0 if the message may pass and 1 if the message should
+ * be blocked.
+ * For this function to work properly it must be called on every PRIVMSG which
+ * is sent by any user.
+ *
+ * Since users are creative and sometimes smart (damnit!) this function can be
+ * outsourced into a dynamic library so we can adjust this function to protect
+ * against any user scripts on-the-fly.
+ *
+ * --gix 2009/11/19
+ */
+int ext_amsg_block(struct Client *cptr, struct Channel *chptr, const char *msg)
+{
+  int amsg_time;
+
+  /* First on every message we check whether the mechanism is enabled.
+   * If it is enabled, we check:
+   *  - whether the channel has MODE_NOAMSGS
+   *  - whether it was sent in between the configured time span
+   *  - whether it matches the previous message
+   * in exactly this order. If at least one test fails, we do not block the
+   * message.
+   * If at least one test failed we copy the message into the users buffer so
+   * it will be checked the next time he sends a message. We also update the
+   * timestamp of the user.
+   */
+  amsg_time = feature_int(FEAT_NOAMSG_TIME);
+  if(amsg_time > 0) {
+    /* Allocate a new buffer if there is none, yet. */
+    if(!cli_user(cptr)->lastmsg) {
+      cli_user(cptr)->lastmsg = MyMalloc(BUFSIZE + 1);
+      memset(cli_user(cptr)->lastmsg, 0, BUFSIZE + 1);
+    }
+    if((chptr->mode.mode & MODE_NOAMSGS) &&
+       ((cli_user(cptr)->lastmsg_time + amsg_time) >= CurrentTime) &&
+       (strcmp(cli_user(cptr)->lastmsg, msg) == 0)) {
+      cli_user(cptr)->lastmsg_time = CurrentTime;
+      cli_user(cptr)->lastmsg_num++;
+      if(cli_user(cptr)->lastmsg_num >= feature_int(FEAT_NOAMSG_NUM)) return 1;
+      else return 0;
+    }
+    /* Message did not match so update the data. */
+    cli_user(cptr)->lastmsg_time = CurrentTime;
+    cli_user(cptr)->lastmsg_num = 0;
+    strcpy(cli_user(cptr)->lastmsg, msg);
+  }
+  return 0;
+}
+
diff --git a/ircd/chattr.tab.c b/ircd/chattr.tab.c
new file mode 100644 (file)
index 0000000..db7a240
--- /dev/null
@@ -0,0 +1,175 @@
+/*
+ * Automatically Generated Tables - DO NOT EDIT
+ */
+#include <limits.h>
+const char ToLowerTab_8859_1[] = {
+#if (CHAR_MIN<0)
+/* x80-x87 */ '\x80', '\x81', '\x82', '\x83', '\x84', '\x85', '\x86', '\x87',
+/* x88-x8f */ '\x88', '\x89', '\x8a', '\x8b', '\x8c', '\x8d', '\x8e', '\x8f',
+/* x90-x97 */ '\x90', '\x91', '\x92', '\x93', '\x94', '\x95', '\x96', '\x97',
+/* x98-x9f */ '\x98', '\x99', '\x9a', '\x9b', '\x9c', '\x9d', '\x9e', '\x9f',
+/* xa0-xa7 */ '\xa0', '\xa1', '\xa2', '\xa3', '\xa4', '\xa5', '\xa6', '\xa7',
+/* xa8-xaf */ '\xa8', '\xa9', '\xaa', '\xab', '\xac', '\xad', '\xae', '\xaf',
+/* xb0-xb7 */ '\xb0', '\xb1', '\xb2', '\xb3', '\xb4', '\xb5', '\xb6', '\xb7',
+/* xb8-xbf */ '\xb8', '\xb9', '\xba', '\xbb', '\xbc', '\xbd', '\xbe', '\xbf',
+/* xc0-xc7 */ '\xe0', '\xe1', '\xe2', '\xe3', '\xe4', '\xe5', '\xe6', '\xe7',
+/* xc8-xcf */ '\xe8', '\xe9', '\xea', '\xeb', '\xec', '\xed', '\xee', '\xef',
+/* xd0-xd7 */ '\xf0', '\xf1', '\xf2', '\xf3', '\xf4', '\xf5', '\xf6', '\xd7',
+/* xd8-xdf */ '\xf8', '\xf9', '\xfa', '\xfb', '\xfc', '\xfd', '\xfe', '\xdf',
+/* xe0-xe7 */ '\xe0', '\xe1', '\xe2', '\xe3', '\xe4', '\xe5', '\xe6', '\xe7',
+/* xe8-xef */ '\xe8', '\xe9', '\xea', '\xeb', '\xec', '\xed', '\xee', '\xef',
+/* xf0-xf7 */ '\xf0', '\xf1', '\xf2', '\xf3', '\xf4', '\xf5', '\xf6', '\xf7',
+/* xf8-xff */ '\xf8', '\xf9', '\xfa', '\xfb', '\xfc', '\xfd', '\xfe', '\xff'
+                ,
+#endif /* (CHAR_MIN<0) */
+/* x00-x07 */ '\x00', '\x01', '\x02', '\x03', '\x04', '\x05', '\x06', '\x07',
+/* x08-x0f */ '\x08', '\x09', '\x0a', '\x0b', '\x0c', '\x0d', '\x0e', '\x0f',
+/* x10-x17 */ '\x10', '\x11', '\x12', '\x13', '\x14', '\x15', '\x16', '\x17',
+/* x18-x1f */ '\x18', '\x19', '\x1a', '\x1b', '\x1c', '\x1d', '\x1e', '\x1f',
+/* ' '-x27 */    ' ',    '!',    '"',    '#',    '$',    '%',    '&', '\x27',
+/* '('-'/' */    '(',    ')',    '*',    '+',    ',',    '-',    '.',    '/',
+/* '0'-'7' */    '0',    '1',    '2',    '3',    '4',    '5',    '6',    '7',
+/* '8'-'?' */    '8',    '9',    ':',    ';',    '<',    '=',    '>',    '?',
+/* '@'-'G' */    '@',    'a',    'b',    'c',    'd',    'e',    'f',    'g',
+/* 'H'-'O' */    'h',    'i',    'j',    'k',    'l',    'm',    'n',    'o',
+/* 'P'-'W' */    'p',    'q',    'r',    's',    't',    'u',    'v',    'w',
+/* 'X'-'_' */    'x',    'y',    'z',    '{',    '|',    '}',    '~',    '_',
+/* '`'-'g' */    '`',    'a',    'b',    'c',    'd',    'e',    'f',    'g',
+/* 'h'-'o' */    'h',    'i',    'j',    'k',    'l',    'm',    'n',    'o',
+/* 'p'-'w' */    'p',    'q',    'r',    's',    't',    'u',    'v',    'w',
+/* 'x'-x7f */    'x',    'y',    'z',    '{',    '|',    '}',    '~', '\x7f'
+#if (!(CHAR_MIN<0))
+                ,
+/* x80-x87 */ '\x80', '\x81', '\x82', '\x83', '\x84', '\x85', '\x86', '\x87',
+/* x88-x8f */ '\x88', '\x89', '\x8a', '\x8b', '\x8c', '\x8d', '\x8e', '\x8f',
+/* x90-x97 */ '\x90', '\x91', '\x92', '\x93', '\x94', '\x95', '\x96', '\x97',
+/* x98-x9f */ '\x98', '\x99', '\x9a', '\x9b', '\x9c', '\x9d', '\x9e', '\x9f',
+/* xa0-xa7 */ '\xa0', '\xa1', '\xa2', '\xa3', '\xa4', '\xa5', '\xa6', '\xa7',
+/* xa8-xaf */ '\xa8', '\xa9', '\xaa', '\xab', '\xac', '\xad', '\xae', '\xaf',
+/* xb0-xb7 */ '\xb0', '\xb1', '\xb2', '\xb3', '\xb4', '\xb5', '\xb6', '\xb7',
+/* xb8-xbf */ '\xb8', '\xb9', '\xba', '\xbb', '\xbc', '\xbd', '\xbe', '\xbf',
+/* xc0-xc7 */ '\xe0', '\xe1', '\xe2', '\xe3', '\xe4', '\xe5', '\xe6', '\xe7',
+/* xc8-xcf */ '\xe8', '\xe9', '\xea', '\xeb', '\xec', '\xed', '\xee', '\xef',
+/* xd0-xd7 */ '\xf0', '\xf1', '\xf2', '\xf3', '\xf4', '\xf5', '\xf6', '\xd7',
+/* xd8-xdf */ '\xf8', '\xf9', '\xfa', '\xfb', '\xfc', '\xfd', '\xfe', '\xdf',
+/* xe0-xe7 */ '\xe0', '\xe1', '\xe2', '\xe3', '\xe4', '\xe5', '\xe6', '\xe7',
+/* xe8-xef */ '\xe8', '\xe9', '\xea', '\xeb', '\xec', '\xed', '\xee', '\xef',
+/* xf0-xf7 */ '\xf0', '\xf1', '\xf2', '\xf3', '\xf4', '\xf5', '\xf6', '\xf7',
+/* xf8-xff */ '\xf8', '\xf9', '\xfa', '\xfb', '\xfc', '\xfd', '\xfe', '\xff'
+#endif /* (!(CHAR_MIN<0)) */
+  };
+
+const char ToUpperTab_8859_1[] = {
+#if (CHAR_MIN<0)
+/* x80-x87 */ '\x80', '\x81', '\x82', '\x83', '\x84', '\x85', '\x86', '\x87',
+/* x88-x8f */ '\x88', '\x89', '\x8a', '\x8b', '\x8c', '\x8d', '\x8e', '\x8f',
+/* x90-x97 */ '\x90', '\x91', '\x92', '\x93', '\x94', '\x95', '\x96', '\x97',
+/* x98-x9f */ '\x98', '\x99', '\x9a', '\x9b', '\x9c', '\x9d', '\x9e', '\x9f',
+/* xa0-xa7 */ '\xa0', '\xa1', '\xa2', '\xa3', '\xa4', '\xa5', '\xa6', '\xa7',
+/* xa8-xaf */ '\xa8', '\xa9', '\xaa', '\xab', '\xac', '\xad', '\xae', '\xaf',
+/* xb0-xb7 */ '\xb0', '\xb1', '\xb2', '\xb3', '\xb4', '\xb5', '\xb6', '\xb7',
+/* xb8-xbf */ '\xb8', '\xb9', '\xba', '\xbb', '\xbc', '\xbd', '\xbe', '\xbf',
+/* xc0-xc7 */ '\xc0', '\xc1', '\xc2', '\xc3', '\xc4', '\xc5', '\xc6', '\xc7',
+/* xc8-xcf */ '\xc8', '\xc9', '\xca', '\xcb', '\xcc', '\xcd', '\xce', '\xcf',
+/* xd0-xd7 */ '\xd0', '\xd1', '\xd2', '\xd3', '\xd4', '\xd5', '\xd6', '\xd7',
+/* xd8-xdf */ '\xd8', '\xd9', '\xda', '\xdb', '\xdc', '\xdd', '\xde', '\xdf',
+/* xe0-xe7 */ '\xc0', '\xc1', '\xc2', '\xc3', '\xc4', '\xc5', '\xc6', '\xc7',
+/* xe8-xef */ '\xc8', '\xc9', '\xca', '\xcb', '\xcc', '\xcd', '\xce', '\xcf',
+/* xf0-xf7 */ '\xd0', '\xd1', '\xd2', '\xd3', '\xd4', '\xd5', '\xd6', '\xf7',
+/* xf8-xff */ '\xd8', '\xd9', '\xda', '\xdb', '\xdc', '\xdd', '\xde', '\xff'
+                ,
+#endif /* (CHAR_MIN<0) */
+/* x00-x07 */ '\x00', '\x01', '\x02', '\x03', '\x04', '\x05', '\x06', '\x07',
+/* x08-x0f */ '\x08', '\x09', '\x0a', '\x0b', '\x0c', '\x0d', '\x0e', '\x0f',
+/* x10-x17 */ '\x10', '\x11', '\x12', '\x13', '\x14', '\x15', '\x16', '\x17',
+/* x18-x1f */ '\x18', '\x19', '\x1a', '\x1b', '\x1c', '\x1d', '\x1e', '\x1f',
+/* ' '-x27 */    ' ',    '!',    '"',    '#',    '$',    '%',    '&', '\x27',
+/* '('-'/' */    '(',    ')',    '*',    '+',    ',',    '-',    '.',    '/',
+/* '0'-'7' */    '0',    '1',    '2',    '3',    '4',    '5',    '6',    '7',
+/* '8'-'?' */    '8',    '9',    ':',    ';',    '<',    '=',    '>',    '?',
+/* '@'-'G' */    '@',    'A',    'B',    'C',    'D',    'E',    'F',    'G',
+/* 'H'-'O' */    'H',    'I',    'J',    'K',    'L',    'M',    'N',    'O',
+/* 'P'-'W' */    'P',    'Q',    'R',    'S',    'T',    'U',    'V',    'W',
+/* 'X'-'_' */    'X',    'Y',    'Z',    '[', '\x5c',    ']',    '^',    '_',
+/* '`'-'g' */    '`',    'A',    'B',    'C',    'D',    'E',    'F',    'G',
+/* 'h'-'o' */    'H',    'I',    'J',    'K',    'L',    'M',    'N',    'O',
+/* 'p'-'w' */    'P',    'Q',    'R',    'S',    'T',    'U',    'V',    'W',
+/* 'x'-x7f */    'X',    'Y',    'Z',    '[', '\x5c',    ']',    '^', '\x7f'
+#if (!(CHAR_MIN<0))
+                ,
+/* x80-x87 */ '\x80', '\x81', '\x82', '\x83', '\x84', '\x85', '\x86', '\x87',
+/* x88-x8f */ '\x88', '\x89', '\x8a', '\x8b', '\x8c', '\x8d', '\x8e', '\x8f',
+/* x90-x97 */ '\x90', '\x91', '\x92', '\x93', '\x94', '\x95', '\x96', '\x97',
+/* x98-x9f */ '\x98', '\x99', '\x9a', '\x9b', '\x9c', '\x9d', '\x9e', '\x9f',
+/* xa0-xa7 */ '\xa0', '\xa1', '\xa2', '\xa3', '\xa4', '\xa5', '\xa6', '\xa7',
+/* xa8-xaf */ '\xa8', '\xa9', '\xaa', '\xab', '\xac', '\xad', '\xae', '\xaf',
+/* xb0-xb7 */ '\xb0', '\xb1', '\xb2', '\xb3', '\xb4', '\xb5', '\xb6', '\xb7',
+/* xb8-xbf */ '\xb8', '\xb9', '\xba', '\xbb', '\xbc', '\xbd', '\xbe', '\xbf',
+/* xc0-xc7 */ '\xc0', '\xc1', '\xc2', '\xc3', '\xc4', '\xc5', '\xc6', '\xc7',
+/* xc8-xcf */ '\xc8', '\xc9', '\xca', '\xcb', '\xcc', '\xcd', '\xce', '\xcf',
+/* xd0-xd7 */ '\xd0', '\xd1', '\xd2', '\xd3', '\xd4', '\xd5', '\xd6', '\xd7',
+/* xd8-xdf */ '\xd8', '\xd9', '\xda', '\xdb', '\xdc', '\xdd', '\xde', '\xdf',
+/* xe0-xe7 */ '\xc0', '\xc1', '\xc2', '\xc3', '\xc4', '\xc5', '\xc6', '\xc7',
+/* xe8-xef */ '\xc8', '\xc9', '\xca', '\xcb', '\xcc', '\xcd', '\xce', '\xcf',
+/* xf0-xf7 */ '\xd0', '\xd1', '\xd2', '\xd3', '\xd4', '\xd5', '\xd6', '\xf7',
+/* xf8-xff */ '\xd8', '\xd9', '\xda', '\xdb', '\xdc', '\xdd', '\xde', '\xff'
+#endif /* (!(CHAR_MIN<0)) */
+  };
+
+const unsigned int IRCD_CharAttrTab[] = {
+#if (CHAR_MIN<0)
+/* x80-x87 */ 0x0400, 0x0400, 0x0400, 0x0400, 0x0400, 0x0400, 0x0400, 0x0400,
+/* x88-x8f */ 0x0400, 0x0400, 0x0400, 0x0400, 0x0400, 0x0400, 0x0400, 0x0400,
+/* x90-x97 */ 0x0400, 0x0400, 0x0400, 0x0400, 0x0400, 0x0400, 0x0400, 0x0400,
+/* x98-x9f */ 0x0400, 0x0400, 0x0400, 0x0400, 0x0400, 0x0400, 0x0400, 0x0400,
+/* xa0-xa7 */ 0x0000, 0x0400, 0x0400, 0x0400, 0x0400, 0x0400, 0x0400, 0x0400,
+/* xa8-xaf */ 0x0400, 0x0400, 0x0400, 0x0400, 0x0400, 0x0400, 0x0400, 0x0400,
+/* xb0-xb7 */ 0x0400, 0x0400, 0x0400, 0x0400, 0x0400, 0x0400, 0x0400, 0x0400,
+/* xb8-xbf */ 0x0400, 0x0400, 0x0400, 0x0400, 0x0400, 0x0400, 0x0400, 0x0400,
+/* xc0-xc7 */ 0x2c00, 0x2c00, 0x2c00, 0x2c00, 0x2c00, 0x2c00, 0x2c00, 0x2c00,
+/* xc8-xcf */ 0x2c00, 0x2c00, 0x2c00, 0x2c00, 0x2c00, 0x2c00, 0x2c00, 0x2c00,
+/* xd0-xd7 */ 0x2c00, 0x2c00, 0x2c00, 0x2c00, 0x2c00, 0x2c00, 0x2c00, 0x0400,
+/* xd8-xdf */ 0x2c00, 0x2c00, 0x2c00, 0x2c00, 0x2c00, 0x2c00, 0x2c00, 0x0400,
+/* xe0-xe7 */ 0x2400, 0x2400, 0x2400, 0x2400, 0x2400, 0x2400, 0x2400, 0x2400,
+/* xe8-xef */ 0x2400, 0x2400, 0x2400, 0x2400, 0x2400, 0x2400, 0x2400, 0x2400,
+/* xf0-xf7 */ 0x2400, 0x2400, 0x2400, 0x2400, 0x2400, 0x2400, 0x2400, 0x0400,
+/* xf8-xff */ 0x2400, 0x2400, 0x2400, 0x2400, 0x2400, 0x2400, 0x2400, 0x0400
+                ,
+#endif /* (CHAR_MIN<0) */
+/* x00-x07 */ 0x0004, 0x0004, 0x0004, 0x0004, 0x0004, 0x0004, 0x0004, 0x0004,
+/* x08-x0f */ 0x0004, 0x0104, 0x10104, 0x0104, 0x0104, 0x10104, 0x0004, 0x0004,
+/* x10-x17 */ 0x0004, 0x0004, 0x0004, 0x0004, 0x0004, 0x0004, 0x0004, 0x0004,
+/* x18-x1f */ 0x0004, 0x0004, 0x0004, 0x0004, 0x0004, 0x0004, 0x0004, 0x0004,
+/* ' '-x27 */ 0x20140, 0x04d0, 0x04d0, 0x404d0, 0x04d0, 0x04d0, 0x404d0, 0x24d0,
+/* '('-'/' */ 0x04d0, 0x04d0, 0x04d0, 0x04d0, 0x200d0, 0x274d0, 0x8e4d0, 0x04d0,
+/* '0'-'7' */ 0xaf459, 0xaf459, 0xaf459, 0xaf459, 0xaf459, 0xaf459, 0xaf459, 0xaf459,
+/* '8'-'?' */ 0xaf459, 0xaf459, 0x804d0, 0x04d0, 0x04d0, 0x04d0, 0x04d0, 0x04d0,
+/* '@'-'G' */ 0x04d0, 0x87653, 0x87653, 0x87653, 0x87653, 0x87653, 0x87653, 0x7653,
+/* 'H'-'O' */ 0x7653, 0x7653, 0x7653, 0x7653, 0x7653, 0x7653, 0x7653, 0x7653,
+/* 'P'-'W' */ 0x7653, 0x7653, 0x7653, 0x7653, 0x7653, 0x7653, 0x7653, 0x7653,
+/* 'X'-'_' */ 0x7653, 0x7653, 0x7653, 0x7653, 0x7653, 0x7653, 0x7653, 0x74d0,
+/* '`'-'g' */ 0x34d0, 0x87473, 0x87473, 0x87473, 0x87473, 0x87473, 0x87473, 0x7473,
+/* 'h'-'o' */ 0x7473, 0x7473, 0x7473, 0x7473, 0x7473, 0x7473, 0x7473, 0x7473,
+/* 'p'-'w' */ 0x7473, 0x7473, 0x7473, 0x7473, 0x7473, 0x7473, 0x7473, 0x7473,
+/* 'x'-x7f */ 0x7473, 0x7473, 0x7473, 0x7473, 0x7473, 0x7473, 0x7473, 0x0400
+#if (!(CHAR_MIN<0))
+                ,
+/* x80-x87 */ 0x0400, 0x0400, 0x0400, 0x0400, 0x0400, 0x0400, 0x0400, 0x0400,
+/* x88-x8f */ 0x0400, 0x0400, 0x0400, 0x0400, 0x0400, 0x0400, 0x0400, 0x0400,
+/* x90-x97 */ 0x0400, 0x0400, 0x0400, 0x0400, 0x0400, 0x0400, 0x0400, 0x0400,
+/* x98-x9f */ 0x0400, 0x0400, 0x0400, 0x0400, 0x0400, 0x0400, 0x0400, 0x0400,
+/* xa0-xa7 */ 0x0000, 0x0400, 0x0400, 0x0400, 0x0400, 0x0400, 0x0400, 0x0400,
+/* xa8-xaf */ 0x0400, 0x0400, 0x0400, 0x0400, 0x0400, 0x0400, 0x0400, 0x0400,
+/* xb0-xb7 */ 0x0400, 0x0400, 0x0400, 0x0400, 0x0400, 0x0400, 0x0400, 0x0400,
+/* xb8-xbf */ 0x0400, 0x0400, 0x0400, 0x0400, 0x0400, 0x0400, 0x0400, 0x0400,
+/* xc0-xc7 */ 0x2c00, 0x2c00, 0x2c00, 0x2c00, 0x2c00, 0x2c00, 0x2c00, 0x2c00,
+/* xc8-xcf */ 0x2c00, 0x2c00, 0x2c00, 0x2c00, 0x2c00, 0x2c00, 0x2c00, 0x2c00,
+/* xd0-xd7 */ 0x2c00, 0x2c00, 0x2c00, 0x2c00, 0x2c00, 0x2c00, 0x2c00, 0x0400,
+/* xd8-xdf */ 0x2c00, 0x2c00, 0x2c00, 0x2c00, 0x2c00, 0x2c00, 0x2c00, 0x0400,
+/* xe0-xe7 */ 0x2400, 0x2400, 0x2400, 0x2400, 0x2400, 0x2400, 0x2400, 0x2400,
+/* xe8-xef */ 0x2400, 0x2400, 0x2400, 0x2400, 0x2400, 0x2400, 0x2400, 0x2400,
+/* xf0-xf7 */ 0x2400, 0x2400, 0x2400, 0x2400, 0x2400, 0x2400, 0x2400, 0x0400,
+/* xf8-xff */ 0x2400, 0x2400, 0x2400, 0x2400, 0x2400, 0x2400, 0x2400, 0x0400
+#endif /* (!(CHAR_MIN<0)) */
+  };
+
diff --git a/ircd/class.c b/ircd/class.c
new file mode 100644 (file)
index 0000000..460ffd3
--- /dev/null
@@ -0,0 +1,309 @@
+/*
+ * IRC - Internet Relay Chat, ircd/class.c
+ * Copyright (C) 1990 Darren Reed
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+/** @file
+ * @brief Implementation of connection class handling functions.
+ * @version $Id: class.c 1514 2005-10-06 00:37:31Z entrope $
+ */
+#include "config.h"
+
+#include "class.h"
+#include "client.h"
+#include "ircd.h"
+#include "ircd_alloc.h"
+#include "ircd_features.h"
+#include "ircd_log.h"
+#include "ircd_reply.h"
+#include "ircd_string.h"
+#include "list.h"
+#include "numeric.h"
+#include "s_conf.h"
+#include "s_debug.h"
+#include "send.h"
+
+/* #include <assert.h> -- Now using assert in ircd_log.h */
+
+/** List of all connection classes. */
+static struct ConnectionClass* connClassList;
+/** Number of allocated connection classes. */
+static unsigned int connClassAllocCount;
+
+/** Get start of connection class linked list. */
+const struct ConnectionClass* get_class_list(void)
+{
+  return connClassList;
+}
+
+/** Allocate a new connection class.
+ * If #connClassList is not null, insert the new class just after it.
+ * @return Newly allocated connection class structure.
+ */
+struct ConnectionClass* make_class(void)
+{
+  struct ConnectionClass *tmp;
+
+  tmp = (struct ConnectionClass*) MyCalloc(1, sizeof(struct ConnectionClass));
+  assert(0 != tmp);
+  tmp->ref_count = 1;
+  if (connClassList)
+  {
+    tmp->next = connClassList->next;
+    connClassList->next = tmp;
+  }
+  ++connClassAllocCount;
+  return tmp;
+}
+
+/** Dereference a connection class.
+ * @param[in] p Connection class to dereference.
+ */
+void free_class(struct ConnectionClass* p)
+{
+  if (p)
+  {
+    assert(0 == p->valid);
+    MyFree(p->cc_name);
+    MyFree(p->default_umode);
+    MyFree(p);
+    --connClassAllocCount;
+  }
+}
+
+/** Initialize the connection class list.
+ * A connection class named "default" is created, with ping frequency,
+ * connection frequency, maximum links and max SendQ values from the
+ * corresponding configuration features.
+ */
+void init_class(void)
+{
+  if (!connClassList) {
+    connClassList = (struct ConnectionClass*) make_class();
+    connClassList->next   = 0;
+  }
+
+  /* We had better not try and free this... */
+  ConClass(connClassList) = "default";
+  PingFreq(connClassList) = feature_int(FEAT_PINGFREQUENCY);
+  ConFreq(connClassList)  = feature_int(FEAT_CONNECTFREQUENCY);
+  MaxLinks(connClassList) = feature_int(FEAT_MAXIMUM_LINKS);
+  MaxSendq(connClassList) = feature_int(FEAT_DEFAULTMAXSENDQLENGTH);
+  connClassList->max_channels = 0;
+  connClassList->valid    = 1;
+  Links(connClassList)    = 1;
+}
+
+/** Mark current connection classes as invalid.
+ */
+void class_mark_delete(void)
+{
+  struct ConnectionClass* p;
+  assert(0 != connClassList);
+
+  for (p = connClassList->next; p; p = p->next)
+    p->valid = 0;
+}
+
+/** Unlink (and dereference) invalid connection classes.
+ * This is used in combination with class_mark_delete() during rehash
+ * to get rid of connection classes that are no longer in the
+ * configuration.
+ */
+void class_delete_marked(void)
+{
+  struct ConnectionClass* cl;
+  struct ConnectionClass* prev;
+
+  Debug((DEBUG_DEBUG, "Class check:"));
+
+  for (prev = cl = connClassList; cl; cl = prev->next) {
+    Debug((DEBUG_DEBUG, "Class %s : CF: %d PF: %d ML: %d LI: %d SQ: %d",
+           ConClass(cl), ConFreq(cl), PingFreq(cl), MaxLinks(cl),
+           Links(cl), MaxSendq(cl)));
+    /*
+     * unlink marked classes, delete unreferenced ones
+     */
+    if (cl->valid || Links(cl) > 1)
+      prev = cl;
+    else
+    {
+      prev->next = cl->next;
+      free_class(cl);
+    }
+  }
+}
+
+/** Get connection class name for a configuration item.
+ * @param[in] aconf Configuration item to check.
+ * @return Name of connection class associated with \a aconf.
+ */
+char*
+get_conf_class(const struct ConfItem* aconf)
+{
+  if ((aconf) && (aconf->conn_class))
+    return (ConfClass(aconf));
+
+  Debug((DEBUG_DEBUG, "No Class For %s", (aconf) ? aconf->name : "*No Conf*"));
+
+  return NULL;
+}
+
+/** Get ping time for a configuration item.
+ * @param[in] aconf Configuration item to check.
+ * @return Ping time for connection class associated with \a aconf.
+ */
+int get_conf_ping(const struct ConfItem* aconf)
+{
+  assert(0 != aconf);
+  if (aconf->conn_class)
+    return (ConfPingFreq(aconf));
+
+  Debug((DEBUG_DEBUG, "No Ping For %s", aconf->name));
+
+  return -1;
+}
+
+/** Get connection class name for a particular client.
+ * @param[in] acptr Client to check.
+ * @return Name of connection class to which \a acptr belongs.
+ */
+char*
+get_client_class(struct Client *acptr)
+{
+  struct SLink *tmp;
+  struct ConnectionClass *cl;
+
+  /* Return the most recent(first on LL) client class... */
+  if (acptr && !IsMe(acptr) && (cli_confs(acptr)))
+    for (tmp = cli_confs(acptr); tmp; tmp = tmp->next)
+    {
+      if (tmp->value.aconf && (cl = tmp->value.aconf->conn_class))
+        return ConClass(cl);
+    }
+  return "(null-class)";
+}
+
+/** Make sure we have a connection class named \a name.
+ * If one does not exist, create it.  Then set its ping frequency,
+ * connection frequency, maximum link count, and max SendQ according
+ * to the parameters.
+ * @param[in] name Connection class name.
+ * @param[in] ping Ping frequency for clients in this class.
+ * @param[in] confreq Connection frequency for clients.
+ * @param[in] maxli Maximum link count for class.
+ * @param[in] sendq Max SendQ for clients.
+ * @param[in] max_channels Maximum number of channels.
+ */
+void add_class(char *name, unsigned int ping, unsigned int confreq,
+               unsigned int maxli, unsigned int sendq, unsigned int max_channels)
+{
+  struct ConnectionClass* p;
+
+  Debug((DEBUG_DEBUG, "Add Class %s: cf: %u pf: %u ml: %u sq: %d mc: %u",
+         name, confreq, ping, maxli, sendq, max_channels));
+  assert(name != NULL);
+  p = do_find_class(name, 1);
+  if (!p)
+    p = make_class();
+  else
+    MyFree(ConClass(p));
+  ConClass(p) = name;
+  ConFreq(p) = confreq;
+  PingFreq(p) = ping;
+  MaxLinks(p) = maxli;
+  p->max_channels = max_channels;
+  MaxSendq(p) = (sendq > 0) ?
+     sendq : feature_int(FEAT_DEFAULTMAXSENDQLENGTH);
+  p->valid = 1;
+}
+
+/** Find a connection class by name.
+ * @param[in] name Name of connection class to search for.
+ * @param[in] extras If non-zero, include unreferenced classes.
+ * @return Pointer to connection class structure (or NULL if none match).
+ */
+struct ConnectionClass* do_find_class(const char *name, int extras)
+{
+  struct ConnectionClass *cltmp;
+
+  for (cltmp = connClassList; cltmp; cltmp = cltmp->next) {
+    if (!cltmp->valid && !extras)
+      continue;
+    if (!ircd_strcmp(ConClass(cltmp), name))
+      return cltmp;
+  }
+  return NULL;
+}
+
+/** Report connection classes to a client.
+ * @param[in] sptr Client requesting statistics.
+ * @param[in] sd Stats descriptor for request (ignored).
+ * @param[in] param Extra parameter from user (ignored).
+ */
+void
+report_classes(struct Client *sptr, const struct StatDesc *sd,
+               char *param)
+{
+  struct ConnectionClass *cltmp;
+
+  for (cltmp = connClassList; cltmp; cltmp = cltmp->next)
+    send_reply(sptr, RPL_STATSYLINE, (cltmp->valid ? 'Y' : 'y'),
+               ConClass(cltmp), PingFreq(cltmp), ConFreq(cltmp),
+               MaxLinks(cltmp), MaxSendq(cltmp), MaxChannels(cltmp), Links(cltmp) - 1);
+}
+
+/** Return maximum SendQ length for a client.
+ * @param[in] cptr Local client to check.
+ * @return Number of bytes allowed in SendQ for \a cptr.
+ */
+unsigned int
+get_sendq(struct Client *cptr)
+{
+  assert(0 != cptr);
+  assert(0 != cli_local(cptr));
+
+  if (cli_max_sendq(cptr))
+    return cli_max_sendq(cptr);
+
+  else if (cli_confs(cptr)) {
+    struct SLink*     tmp;
+    struct ConnectionClass* cl;
+
+    for (tmp = cli_confs(cptr); tmp; tmp = tmp->next) {
+      if (!tmp->value.aconf || !(cl = tmp->value.aconf->conn_class))
+        continue;
+      if (ConClass(cl) != NULL) {
+        cli_max_sendq(cptr) = MaxSendq(cl);
+        return cli_max_sendq(cptr);
+      }
+    }
+  }
+  return feature_int(FEAT_DEFAULTMAXSENDQLENGTH);
+}
+
+/** Report connection class memory statistics to a client.
+ * Send number of classes and number of bytes allocated for them.
+ * @param[in] cptr Client requesting statistics.
+ */
+void class_send_meminfo(struct Client* cptr)
+{
+  send_reply(cptr, SND_EXPLICIT | RPL_STATSDEBUG, ":Classes: inuse: %d(%d)",
+             connClassAllocCount,
+             connClassAllocCount * sizeof(struct ConnectionClass));
+}
+
+
diff --git a/ircd/client.c b/ircd/client.c
new file mode 100644 (file)
index 0000000..276e82c
--- /dev/null
@@ -0,0 +1,316 @@
+/*
+ * IRC - Internet Relay Chat, ircd/client.c
+ * Copyright (C) 1990 Darren Reed
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+/** @file
+ * @brief Implementation of functions for handling local clients.
+ * @version $Id: client.c 1523 2005-10-12 23:52:12Z entrope $
+ */
+#include "config.h"
+
+#include "client.h"
+#include "class.h"
+#include "ircd.h"
+#include "ircd_features.h"
+#include "ircd_log.h"
+#include "ircd_reply.h"
+#include "list.h"
+#include "msgq.h"
+#include "numeric.h"
+#include "s_conf.h"
+#include "s_debug.h"
+#include "send.h"
+#include "struct.h"
+
+/* #include <assert.h> -- Now using assert in ircd_log.h */
+#include <string.h>
+
+/** Find the shortest non-zero ping time attached to a client.
+ * If all attached ping times are zero, return the value for
+ * FEAT_PINGFREQUENCY.
+ * @param[in] acptr Client to find ping time for.
+ * @return Ping time in seconds.
+ */
+int client_get_ping(const struct Client* acptr)
+{
+  int     ping = 0;
+  struct ConfItem* aconf;
+  struct SLink*    link;
+
+  assert(cli_verify(acptr));
+
+  for (link = cli_confs(acptr); link; link = link->next) {
+    aconf = link->value.aconf;
+    if (aconf->status & (CONF_CLIENT | CONF_SERVER)) {
+      int tmp = get_conf_ping(aconf);
+      if (0 < tmp && (ping > tmp || !ping))
+        ping = tmp;
+    }
+  }
+  if (0 == ping)
+    ping = feature_int(FEAT_PINGFREQUENCY);
+
+  Debug((DEBUG_DEBUG, "Client %s Ping %d", cli_name(acptr), ping));
+
+  return ping;
+}
+
+/** Find the default usermode for a client.
+ * @param[in] sptr Client to find default usermode for.
+ * @return Pointer to usermode string (or NULL, if there is no default).
+ */
+const char* client_get_default_umode(const struct Client* sptr)
+{
+  struct ConfItem* aconf;
+  struct SLink* link;
+
+  assert(cli_verify(sptr));
+
+  for (link = cli_confs(sptr); link; link = link->next) {
+    aconf = link->value.aconf;
+    if ((aconf->status & CONF_CLIENT) && ConfUmode(aconf))
+      return ConfUmode(aconf);
+  }
+  return NULL;
+}
+
+/** Remove a connection from the list of connections with queued data.
+ * @param[in] con Connection with no queued data.
+ */
+void client_drop_sendq(struct Connection* con)
+{
+  if (con_prev_p(con)) { /* on the queued data list... */
+    if (con_next(con))
+      con_prev_p(con_next(con)) = con_prev_p(con);
+    *(con_prev_p(con)) = con_next(con);
+
+    con_next(con) = 0;
+    con_prev_p(con) = 0;
+  }
+}
+
+/** Add a connection to the list of connections with queued data.
+ * @param[in] con Connection with queued data.
+ * @param[in,out] con_p Previous pointer to next connection.
+ */
+void client_add_sendq(struct Connection* con, struct Connection** con_p)
+{
+  if (!con_prev_p(con)) { /* not on the queued data list yet... */
+    con_prev_p(con) = con_p;
+    con_next(con) = *con_p;
+
+    if (*con_p)
+      con_prev_p(*con_p) = &(con_next(con));
+    *con_p = con;
+  }
+}
+
+/** Default privilege set for global operators. */
+static struct Privs privs_global;
+/** Default privilege set for local operators. */
+static struct Privs privs_local;
+/** Non-zero if #privs_global and #privs_local have been initialized. */
+static int privs_defaults_set;
+
+/* client_set_privs(struct Client* client)
+ *
+ * Sets the privileges for opers.
+ */
+/** Set the privileges for a client.
+ * @param[in] client Client who has become an operator.
+ * @param[in] oper Configuration item describing oper's privileges.
+ */
+void
+client_set_privs(struct Client *client, struct ConfItem *oper)
+{
+  struct Privs *source, *defaults;
+  enum Priv priv;
+
+  if (!MyConnect(client))
+    return;
+
+  /* Clear out client's privileges. */
+  memset(cli_privs(client), 0, sizeof(struct Privs));
+
+  if (!IsAnOper(client) || !oper)
+      return;
+
+  if (!privs_defaults_set)
+  {
+    memset(&privs_global, -1, sizeof(privs_global));
+    FlagClr(&privs_global, PRIV_WALK_LCHAN);
+    FlagClr(&privs_global, PRIV_UNLIMIT_QUERY);
+    FlagClr(&privs_global, PRIV_SET);
+    FlagClr(&privs_global, PRIV_BADCHAN);
+    FlagClr(&privs_global, PRIV_LOCAL_BADCHAN);
+    FlagClr(&privs_global, PRIV_APASS_OPMODE);
+    FlagClr(&privs_global, PRIV_UMODE_CHSERV);
+    FlagClr(&privs_global, PRIV_UMODE_XTRAOP);
+    FlagClr(&privs_global, PRIV_UMODE_NETSERV);
+
+    memset(&privs_local, 0, sizeof(privs_local));
+    //FlagSet(&privs_local, PRIV_CHAN_LIMIT);
+    //FlagSet(&privs_local, PRIV_MODE_LCHAN);
+    //FlagSet(&privs_local, PRIV_SHOW_INVIS);
+    //FlagSet(&privs_local, PRIV_SHOW_ALL_INVIS);
+    //FlagSet(&privs_local, PRIV_LOCAL_KILL);
+    //FlagSet(&privs_local, PRIV_REHASH);
+    //FlagSet(&privs_local, PRIV_LOCAL_GLINE);
+    //FlagSet(&privs_local, PRIV_LOCAL_JUPE);
+    //FlagSet(&privs_local, PRIV_LOCAL_OPMODE);
+    //FlagSet(&privs_local, PRIV_WHOX);
+    //FlagSet(&privs_local, PRIV_DISPLAY);
+    //FlagSet(&privs_local, PRIV_FORCE_LOCAL_OPMODE);
+    //FlagSet(&privs_local, PRIV_UMODE_NOCHAN);
+    //FlagSet(&privs_local, PRIV_UMODE_NOIDLE);
+    //FlagSet(&privs_local, PRIV_SEE_IDLETIME);
+    //FlagSet(&privs_local, PRIV_HALFFLOOD);
+    //FlagSet(&privs_local, PRIV_UMODE_OVERRIDECC);
+
+    privs_defaults_set = 1;
+  }
+
+  /* Decide whether to use global or local oper defaults. */
+  if (FlagHas(&oper->privs_dirty, PRIV_PROPAGATE))
+    defaults = FlagHas(&oper->privs, PRIV_PROPAGATE) ? &privs_global : &privs_local;
+  else if (FlagHas(&oper->conn_class->privs_dirty, PRIV_PROPAGATE))
+    defaults = FlagHas(&oper->conn_class->privs, PRIV_PROPAGATE) ? &privs_global : &privs_local;
+  else {
+    assert(0 && "Oper has no propagation and neither does connection class");
+    return;
+  }
+
+  /* For each feature, figure out whether it comes from the operator
+   * conf, the connection class conf, or the defaults, then apply it.
+   */
+  for (priv = 0; priv < PRIV_LAST_PRIV; ++priv)
+  {
+    /* Figure out most applicable definition for the privilege. */
+    if (FlagHas(&oper->privs_dirty, priv))
+      source = &oper->privs;
+    else if (FlagHas(&oper->conn_class->privs_dirty, priv))
+      source = &oper->conn_class->privs;
+    else
+      source = defaults;
+
+    /* Set it if necessary (privileges were already cleared). */
+    if (FlagHas(source, priv))
+      SetPriv(client, priv);
+  }
+
+  /* This should be handled in the config, but lets be sure... */
+  if (HasPriv(client, PRIV_PROPAGATE))
+  {
+    /* force propagating opers to display */
+    SetPriv(client, PRIV_DISPLAY);
+  }
+  else
+  {
+    /* if they don't propagate oper status, prevent desyncs */
+    ClrPriv(client, PRIV_KILL);
+    ClrPriv(client, PRIV_GLINE);
+    ClrPriv(client, PRIV_JUPE);
+    ClrPriv(client, PRIV_OPMODE);
+    ClrPriv(client, PRIV_BADCHAN);
+  }
+}
+
+/** Array mapping privilege values to names and vice versa. */
+static struct {
+  char        *name; /**< Name of privilege. */
+  unsigned int priv; /**< Enumeration value of privilege */
+  unsigned int oper; /**< Oper only privileges. */
+} privtab[] = {
+/** Helper macro to define an array entry for a privilege. */
+#define P(priv)      { #priv, PRIV_ ## priv, 1 }
+#define UP(priv)  { #priv, PRIV_ ## priv, 0 }
+  UP(CHAN_LIMIT),     P(MODE_LCHAN),     P(WALK_LCHAN),    P(DEOP_LCHAN),
+  P(SHOW_INVIS),     P(SHOW_ALL_INVIS), P(UNLIMIT_QUERY), P(KILL),
+  P(LOCAL_KILL),     P(REHASH),         P(RESTART),       P(DIE),
+  P(GLINE),          P(LOCAL_GLINE),    P(JUPE),          P(LOCAL_JUPE),
+  P(OPMODE),         P(LOCAL_OPMODE),   P(SET),           P(WHOX),
+  P(BADCHAN),        P(LOCAL_BADCHAN),  P(SEE_CHAN),      P(PROPAGATE),
+  P(DISPLAY),        P(SEE_OPERS),      P(WIDE_GLINE),    P(LIST_CHAN),
+  P(FORCE_OPMODE),   P(FORCE_LOCAL_OPMODE), P(APASS_OPMODE),
+  UP(UMODE_NOCHAN),  UP(UMODE_NOIDLE),  UP(UMODE_CHSERV), P(UMODE_XTRAOP),
+  UP(UMODE_NETSERV), UP(SEE_IDLETIME),  UP(HALFFLOOD),    UP(FLOOD),
+  UP(UMODE_OVERRIDECC), UP(UNLIMITED_TARGET), UP(HIDE_IDLETIME),
+  UP(NOAMSG_OVERRIDE),
+#undef UP
+#undef P
+  { 0, 0, 0 }
+};
+
+/** Set the user privileges for a client.
+ * @param[in] client Client who should get user privileges.
+ * @param[in] aconf Configuration item describing user's privileges.
+ */
+void
+client_set_uprivs(struct Client *client, struct ConfItem *aconf) {
+  struct ConnectionClass *conn_class;
+  enum Priv priv;
+  int i;
+
+  if (!MyConnect(client))
+    return;
+
+  /* Clear out client's privileges. */
+  //memset(cli_privs(client), 0, sizeof(struct Privs));
+
+  if (!aconf || !(conn_class = aconf->conn_class))
+    return;
+
+  for (priv = 0; priv < PRIV_LAST_PRIV; ++priv)
+  {
+    if (FlagHas(&conn_class->privs_dirty, priv) && FlagHas(&conn_class->privs, priv)) {
+      for (i = 0; privtab[i].name; i++) {
+        if(privtab[i].priv == priv && !privtab[i].oper) {
+          SetPriv(client, priv);
+          break;
+        }
+        else if(privtab[i].priv == priv && privtab[i].oper) {
+          break;
+        }
+      }
+    }
+  }
+}
+
+/** Report privileges of \a client to \a to.
+ * @param[in] to Client requesting privilege list.
+ * @param[in] client Client whos privileges should be listed.
+ * @return Zero.
+ */
+int
+client_report_privs(struct Client *to, struct Client *client)
+{
+  struct MsgBuf *mb;
+  int found1 = 0;
+  int i;
+
+  mb = msgq_make(to, rpl_str(RPL_PRIVS), cli_name(&me), cli_name(to),
+       cli_name(client));
+
+  for (i = 0; privtab[i].name; i++)
+    if (HasPriv(client, privtab[i].priv))
+      msgq_append(0, mb, "%s%s%s", found1++ ? " " : "", (privtab[i].oper ? "" : "*"), privtab[i].name);
+
+  send_buffer(to, mb, 0); /* send response */
+  msgq_clean(mb);
+
+  return 0;
+}
\ No newline at end of file
diff --git a/ircd/convert-conf.c b/ircd/convert-conf.c
new file mode 100644 (file)
index 0000000..2e103ea
--- /dev/null
@@ -0,0 +1,675 @@
+/* convert-conf.c - Convert ircu2.10.11 ircd.conf to ircu2.10.12 format.
+ * Copyright 2005 Michael Poole
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA.
+ */
+
+#include <ctype.h> /* tolower() */
+#include <stdio.h> /* *printf(), fgets() */
+#include <stdlib.h> /* free(), strtol() */
+#include <string.h> /* strlen(), memcpy(), strchr(), strspn() */
+
+#define MAX_FIELDS 5
+
+const char *admin_names[] = { "location", "contact", "contact", 0 },
+    *connect_names[] = { "host", "password", "name", "#port", "class", 0 },
+    *crule_names[] = { "server", "",  "rule", 0 },
+    *general_names[] = { "name", "vhost", "description", "", "#numeric", 0 },
+    *motd_names[] = { "host", "file", 0 },
+    *class_names[] = { "name", "#pingfreq", "#connectfreq", "#maxlinks", "#sendq", 0 },
+    *removed_features[] = { "VIRTUAL_HOST", "TIMESEC", "OPERS_SEE_IN_SECRET_CHANNELS", "LOCOP_SEE_IN_SECRET_CHANNELS", "HIS_STATS_h", "HIS_DESYNCS", "AUTOHIDE", 0 };
+char orig_line[512], line[512], dbuf[512];
+char *fields[MAX_FIELDS + 1];
+unsigned int nfields;
+unsigned int lineno;
+
+/*** GENERIC SUPPORT CODE ***/
+
+static int split_line(char *input, char **output)
+{
+    size_t quoted = 0, jj;
+    char *dest = dbuf, ch;
+
+    nfields = 1;
+    output[0] = dest;
+    while (*input != '\0' && *input != '#') switch (ch = *input++) {
+    case ':':
+        if (quoted)
+            *dest++ = ch;
+        else {
+            *dest++ = '\0';
+            if (nfields >= MAX_FIELDS)
+                return nfields;
+            output[nfields++] = dest;
+        }
+        break;
+    case '\\':
+        switch (ch = *input++) {
+        case 'b': *dest++ = '\b'; break;
+        case 'f': *dest++ = '\f'; break;
+        case 'n': *dest++ = '\n'; break;
+        case 'r': *dest++ = '\r'; break;
+        case 't': *dest++ = '\t'; break;
+        case 'v': *dest++ = '\v'; break;
+        default: *dest++ = ch; break;
+        }
+        break;
+    case '"': quoted = !quoted; break;
+    default: *dest++ = ch;  break;
+    }
+
+    *dest = '\0';
+    for (jj = nfields; jj < MAX_FIELDS; ++jj)
+        output[jj] = dest;
+    return nfields;
+}
+
+static void simple_line(const char *block, const char **names, const char *extra)
+{
+    size_t ii;
+
+    /* Print the current line and start the new block. */
+    fprintf(stdout, "# %s\n%s {\n", orig_line, block);
+
+    /* Iterate over fields in input line, formatting each. */
+    for (ii = 0; ii < nfields && names[ii]; ++ii) {
+        if (!fields[ii][0] || !names[ii][0])
+            continue;
+        else if (names[ii][0] == '#')
+            fprintf(stdout, "\t%s = %s;\n", names[ii] + 1, fields[ii]);
+        else
+            fprintf(stdout, "\t%s = \"%s\";\n", names[ii], fields[ii]);
+    }
+
+    /* Close the new block (including any fixed-form text). */
+    if (extra)
+        fprintf(stdout, "\t%s\n", extra);
+    fputs("};\n", stdout);
+}
+
+#define dupstring(TARGET, SOURCE) do { free(TARGET); if (SOURCE) { size_t len = strlen(SOURCE) + 1; (TARGET) = malloc(len); memcpy((TARGET), (SOURCE), len); } else (TARGET) = 0; } while(0)
+
+/*** MANAGING LISTS OF STRINGS ***/
+
+struct string_list {
+    struct string_list *next;
+    char *origin;
+    char *extra;
+    char value[1];
+};
+
+/** Find or insert the element from \a list that contains \a value.
+ * If an element of \a list already contains \a value, return it.
+ * Otherwise, append a new element to \a list containing \a value and
+ * return it.
+ * @param[in,out] list A list of strings.
+ * @param[in] value A string to search for.
+ * @return A string list element from \a list containing \a value.
+ */
+static struct string_list *string_get(struct string_list **list, const char *value)
+{
+    struct string_list *curr;
+    size_t len = strlen(value), ii;
+
+    while ((curr = *list)) {
+        for (ii = 0; tolower(curr->value[ii]) == tolower(value[ii]) && ii < len; ++ii) ;
+        if (curr->value[ii] == '\0' && value[ii] == '\0')
+            return curr;
+        list = &curr->next;
+    }
+
+    *list = calloc(1, sizeof(**list) + len);
+    memcpy((*list)->value, value, len);
+    return *list;
+}
+
+/*** SERVER CONNECTION RELATED CODE ***/
+
+struct connect {
+    char *host;
+    char *password;
+    char *port;
+    char *class;
+    char *hub;
+    char *maximum;
+    struct connect *next;
+    struct string_list *origins;
+    char name[1];
+} *connects;
+
+static struct connect *get_connect(const char *name)
+{
+    struct connect *conn;
+    size_t ii, nlen;
+
+    /* Look for a pre-existing connection with the same name. */
+    nlen = strlen(name);
+    for (conn = connects; conn; conn = conn->next)
+    {
+        for (ii = 0; tolower(name[ii]) == tolower(conn->name[ii]) && ii < nlen; ++ii) ;
+        if (conn->name[ii] == '\0' && name[ii] == '\0')
+            break;
+    }
+
+    /* If none was found, create a new one. */
+    if (!conn)
+    {
+        conn = calloc(1, sizeof(*conn) + nlen);
+        for (ii = 0; ii < nlen; ++ii)
+            conn->name[ii] = name[ii];
+        conn->next = connects;
+        connects = conn;
+    }
+
+    /* Return the connection. */
+    return conn;
+}
+
+static void do_connect(void)
+{
+    struct connect *conn = get_connect(fields[2]);
+    dupstring(conn->host, fields[0]);
+    dupstring(conn->password, fields[1]);
+    dupstring(conn->port, fields[3]);
+    dupstring(conn->class, fields[4]);
+    string_get(&conn->origins, orig_line);
+}
+
+static void do_hub(void)
+{
+    struct connect *conn = get_connect(fields[2]);
+    dupstring(conn->hub, fields[0]);
+    dupstring(conn->maximum, fields[3]);
+    string_get(&conn->origins, orig_line);
+}
+
+static void do_leaf(void)
+{
+    struct connect *conn = get_connect(fields[2]);
+    free(conn->hub);
+    conn->hub = 0;
+    string_get(&conn->origins, orig_line);
+}
+
+static void finish_connects(void)
+{
+    struct connect *conn;
+    struct string_list *sl;
+
+    for (conn = connects; conn; conn = conn->next)
+    {
+        for (sl = conn->origins; sl; sl = sl->next)
+            fprintf(stdout, "# %s\n", sl->value);
+       if (conn->host == NULL
+            || conn->password == NULL
+            || conn->class == NULL)
+        {
+           fprintf(stderr, "H:line missing C:line for %s\n", conn->name);
+           continue;
+       }
+
+        fprintf(stdout,
+                "Connect {\n\tname =\"%s\";\n\thost = \"%s\";\n"
+                "\tpassword = \"%s\";\n\tclass = \"%s\";\n",
+                conn->name, conn->host, conn->password, conn->class);
+        if (conn->port && conn->port[0] != '\0')
+            fprintf(stdout, "\tport = %s;\n", conn->port);
+        else
+            fprintf(stdout,
+                    "# Every Connect block should have a port number.\n"
+                    "# To prevent autoconnects, set autoconnect = no.\n"
+                    "#\tport = 4400;\n"
+                    "\tautoconnect = no;\n");
+        if (conn->maximum && conn->maximum[0] != '\0')
+            fprintf(stdout, "\tmaxhops = %s;\n", conn->maximum);
+        if (conn->hub && conn->hub[0] != '\0')
+            fprintf(stdout, "\thub = \"%s\";\n", conn->hub);
+        fprintf(stdout, "};\n\n");
+
+    }
+}
+
+/*** FEATURE MANAGEMENT CODE ***/
+
+struct feature {
+    struct string_list *values;
+    struct string_list *origins;
+    struct feature *next;
+    char name[1];
+} *features;
+
+struct remapped_feature {
+    const char *name;
+    const char *privilege;
+    int flags; /* 2 = global, 1 = local */
+    struct feature *feature;
+} remapped_features[] = {
+    /* Specially handled privileges: If you change the index of
+     * anything with NULL privilege, change the code in
+     * finish_operators() to match!
+     */
+    { "CRYPT_OPER_PASSWORD", NULL, 0, 0 }, /* default: true */
+    { "OPER_KILL", NULL, 2, 0 }, /* default: true */
+    { "LOCAL_KILL_ONLY", NULL, 2, 0 }, /* default: false */
+    /* remapped features that affect all opers  */
+    { "OPER_NO_CHAN_LIMIT", "chan_limit", 3, 0 },
+    { "OPER_MODE_LCHAN", "mode_lchan", 3, 0 },
+    { "OPER_WALK_THROUGH_LMODES", "walk_lchan", 3, 0 },
+    { "NO_OPER_DEOP_LCHAN", "deop_lchan", 3, 0 },
+    { "SHOW_INVISIBLE_USERS", "show_invis", 3, 0 },
+    { "SHOW_ALL_INVISIBLE_USERS", "show_all_invis", 3, 0 },
+    { "UNLIMIT_OPER_QUERY", "unlimit_query", 3, 0 },
+    /* remapped features affecting only global opers */
+    { "OPER_REHASH", "rehash", 2, 0 },
+    { "OPER_RESTART", "restart", 2, 0 },
+    { "OPER_DIE", "die", 2, 0 },
+    { "OPER_GLINE", "gline", 2, 0 },
+    { "OPER_LGLINE", "local_gline", 2, 0 },
+    { "OPER_JUPE", "jupe", 2, 0 },
+    { "OPER_LJUPE", "local_jupe", 2, 0 },
+    { "OPER_OPMODE", "opmode", 2, 0 },
+    { "OPER_LOPMODE", "local_opmode", 2, 0 },
+    { "OPER_FORCE_OPMODE", "force_opmode", 2, 0 },
+    { "OPER_FORCE_LOPMODE", "force_local_opmode", 2, 0 },
+    { "OPER_BADCHAN", "badchan", 2, 0 },
+    { "OPER_LBADCHAN", "local_badchan", 2, 0 },
+    { "OPER_SET", "set", 2, 0 },
+    { "OPER_WIDE_GLINE", "wide_gline", 2, 0 },
+    /* remapped features affecting only local opers */
+    { "LOCOP_KILL", "kill", 1, 0 },
+    { "LOCOP_REHASH", "rehash", 1, 0 },
+    { "LOCOP_RESTART", "restart", 1, 0 },
+    { "LOCOP_DIE", "die", 1, 0 },
+    { "LOCOP_LGLINE", "local_gline", 1, 0 },
+    { "LOCOP_LJUPE", "local_jupe", 1, 0 },
+    { "LOCOP_LOPMODE", "local_opmode", 1, 0 },
+    { "LOCOP_FORCE_LOPMODE", "force_local_opmode", 1, 0 },
+    { "LOCOP_LBADCHAN", "local_badchan", 1, 0 },
+    { "LOCOP_WIDE_GLINE", "wide_gline", 1, 0 },
+    { 0, 0, 0, 0 }
+};
+
+static void do_feature(void)
+{
+    struct feature *feat;
+    size_t ii;
+
+    ii = strlen(fields[0]);
+    feat = calloc(1, sizeof(*feat) + ii);
+    while (ii-- > 0)
+        feat->name[ii] = fields[0][ii];
+    feat->next = features;
+    features = feat;
+    string_get(&feat->origins, orig_line);
+    for (ii = 1; fields[ii] && fields[ii][0]; ++ii)
+        string_get(&feat->values, fields[ii]);
+}
+
+static void finish_features(void)
+{
+    struct remapped_feature *rmf;
+    struct string_list *sl;
+    struct feature *feat;
+    size_t ii;
+
+    fputs("Features {\n", stdout);
+    fputs("\t\"OPLEVELS\" = \"FALSE\";\n", stdout);
+    fputs("\t\"ZANNELS\" = \"FALSE\";\n", stdout);
+
+    for (feat = features; feat; feat = feat->next) {
+        /* Display the original feature line we are talking about. */
+        for (sl = feat->origins; sl; sl = sl->next)
+            fprintf(stdout, "# %s\n", sl->value);
+
+        /* See if the feature was remapped to an oper privilege. */
+        for (rmf = remapped_features; rmf->name; rmf++)
+            if (0 == strcmp(feat->name, rmf->name))
+                break;
+        if (rmf->name) {
+            rmf->feature = feat;
+            fprintf(stdout, "# Above feature mapped to an oper privilege.\n");
+            continue;
+        }
+
+        /* Was it removed? */
+        for (ii = 0; removed_features[ii]; ++ii)
+            if (0 == strcmp(feat->name, removed_features[ii]))
+                break;
+        if (removed_features[ii]) {
+            fprintf(stdout, "# Above feature no longer exists.\n");
+            continue;
+        }
+
+        /* If it had no value before, drop it now since the lexer does
+         * not accept empty strings and the grammar does not accept
+         * empty stringlists.*/
+        if (!feat->values) {
+            fprintf(stdout, "# Above feature had no value.\n");
+            continue;
+        }
+
+        /* Wasn't remapped, wasn't removed: print it out. */
+        fprintf(stdout, "\t\"%s\" =", feat->name);
+        for (sl = feat->values; sl; sl = sl->next)
+            fprintf(stdout, " \"%s\"", sl->value);
+        fprintf(stdout, ";\n");
+    }
+    fputs("};\n\n", stdout);
+
+}
+
+/*** OPERATOR BLOCKS ***/
+
+struct operator {
+    char *name;
+    char *host;
+    char *password;
+    char *class;
+    char *origin;
+    int is_local;
+    struct operator *next;
+} *operators;
+
+static void do_operator(int is_local)
+{
+    struct operator *oper;
+
+    oper = calloc(1, sizeof(*oper));
+    dupstring(oper->host, fields[0]);
+    dupstring(oper->password, fields[1]);
+    dupstring(oper->name, fields[2]);
+    dupstring(oper->class, fields[4]);
+    dupstring(oper->origin, orig_line);
+    oper->is_local = is_local;
+    oper->next = operators;
+    operators = oper;
+}
+
+static void finish_operators(void)
+{
+    struct remapped_feature *remap;
+    struct operator *oper;
+    struct feature *feat;
+    char *pw_salt = "";
+    int global_kill = 0, mask = 0;
+    size_t ii;
+
+    if ((feat = remapped_features[0].feature) && feat->values
+        && 0 == strcmp(feat->values->value, "FALSE"))
+        pw_salt = "$PLAIN$";
+
+    if ((feat = remapped_features[1].feature) && feat->values
+        && 0 == strcmp(feat->values->value, "FALSE"))
+        global_kill = 1;
+    else if ((feat = remapped_features[2].feature) && feat->values
+        && 0 == strcmp(feat->values->value, "FALSE"))
+        global_kill = 2;
+
+    for (oper = operators; oper; oper = oper->next) {
+        fprintf(stdout, "# %s\nOperator {\n\tname = \"%s\";\n"
+                "\thost = \"%s\";\n\tpassword = \"%s%s\";\n"
+                "\tclass = \"%s\";\n",
+                oper->origin, oper->name, oper->host, pw_salt,
+                oper->password, oper->class);
+        if (oper->is_local) {
+            fputs("\tlocal = yes;\n", stdout);
+            mask = 1;
+        } else {
+            fputs("\tlocal = no;\n", stdout);
+            if (global_kill == 1)
+                fputs("\tkill = no;\n\tlocal_kill = no;\n", stdout);
+            else if (global_kill == 2)
+                fputs("\tkill = no;\n\tlocal_kill = yes;\n", stdout);
+            mask = 2;
+        }
+        for (ii = 0; (remap = &remapped_features[ii++])->name; ) {
+            if (!remap->feature || !remap->privilege
+                || !remap->feature->values || !(remap->flags & mask))
+                continue;
+            fprintf(stdout, "\t%s = %s;\n", remap->privilege,
+                    strcmp(remap->feature->values->value, "TRUE") ? "no" : "yes");
+        }
+        fputs("};\n\n", stdout);
+    }
+}
+
+/*** OTHER CONFIG TRANSFORMS ***/
+
+static void do_kill(void)
+{
+    const char *host = fields[0], *reason = fields[1], *user = fields[2];
+
+    if (!memcmp(host, "$R", 3)) {
+        fprintf(stderr, "Empty realname K: line at line %u.\n", lineno);
+        return;
+    }
+
+    /* Print the current line and start the new block. */
+    fprintf(stdout, "# %s\nKill {\n", orig_line);
+
+    /* Translate the user-matching portions. */
+    if (host[0] == '$' && host[1] == 'R') {
+        /* Realname kill, possibly with a username */
+        fprintf(stdout, "\trealname = \"%s\";\n", host + 2);
+        if (user[0] != '\0' && (user[0] != '*' || user[1] != '\0'))
+            fprintf(stdout, "\thost = \"%s@*\";\n", user);
+    } else {
+        /* Normal host or IP-based kill */
+        if (user[0] != '\0' && (user[0] != '*' || user[1] != '\0'))
+            fprintf(stdout, "\thost = \"%s@%s\";\n", user, host);
+        else
+            fprintf(stdout, "\thost = \"%s\";\n", host);
+    }
+
+    /* Translate the reason section. */
+    if (reason[0] == '!')
+        fprintf(stdout, "\tfile = \"%s\";\n", reason + 1);
+    else
+        fprintf(stdout, "\treason = \"%s\";\n", reason);
+
+    /* Close the block. */
+    fprintf(stdout, "};\n");
+}
+
+static void do_port(void)
+{
+    const char *ipmask = fields[0], *iface = fields[1], *flags = fields[2], *port = fields[3];
+
+    /* Print the current line and start the new block. */
+    fprintf(stdout, "# %s\nPort {\n", orig_line);
+
+    /* Print the easy fields. */
+    fprintf(stdout, "\tport = %s;\n", port);
+    if (iface && iface[0] != '\0')
+        fprintf(stdout, "\tvhost = \"%s\";\n", iface);
+    if (ipmask && ipmask[0] != '\0')
+        fprintf(stdout, "\tmask = \"%s\";\n", ipmask);
+
+    /* Translate flag field. */
+    while (*flags) switch (*flags++) {
+    case 'C': case 'c': /* client port is default state */; break;
+    case 'S': case 's': fprintf(stdout, "\tserver = yes;\n"); break;
+    case 'H': case 'h': fprintf(stdout, "\thidden = yes;\n"); break;
+    }
+
+    /* Close the block. */
+    fprintf(stdout, "};\n");
+}
+
+struct string_list *quarantines;
+
+static void do_quarantine(void)
+{
+    struct string_list *q;
+    q = string_get(&quarantines, fields[0]);
+    dupstring(q->origin, orig_line);
+    dupstring(q->extra, fields[1]);
+}
+
+static void finish_quarantines(void)
+{
+    struct string_list *sl;
+
+    if (quarantines)
+    {
+        fputs("Quarantine {\n", stdout);
+        for (sl = quarantines; sl; sl = sl->next)
+            fprintf(stdout, "# %s\n\t\"%s\" = \"%s\";\n", sl->origin, sl->value, sl->extra);
+        fputs("};\n\n", stdout);
+    }
+}
+
+static void do_uworld(void)
+{
+    fprintf(stdout, "# %s\n", orig_line);
+    if (fields[0] && fields[0][0])
+        fprintf(stdout, "Uworld { name = \"%s\"; };\n", fields[0]);
+    if (fields[1] && fields[1][0])
+        fprintf(stdout, "Jupe { nick = \"%s\"; };\n", fields[1]);
+}
+
+static void emit_client(const char *mask, const char *passwd, const char *class, long maxlinks, int is_ip)
+{
+    char *delim;
+    size_t len;
+
+    delim = strchr(mask, '@');
+    if (delim) {
+        *delim++ = '\0';
+        if (is_ip) {
+            len = strspn(delim, "0123456789.*");
+            if (delim[len]) {
+                fprintf(stderr, "Invalid IP mask on line %u.\n", lineno);
+                return;
+            }
+            fprintf(stdout, "Client {\n\tusername = \"%s\";\n\tip = \"%s\";\n", mask, delim);
+        } else {
+            fprintf(stdout, "Client {\n\tusername =\"%s\";\n\thost = \"%s\";\n", mask, delim);
+        }
+    } else if (is_ip) {
+        len = strspn(mask, "0123456789.*");
+        if (mask[len])
+            return;
+        fprintf(stdout, "Client {\n\tip = \"%s\";\n", mask);
+    } else {
+        if (!strchr(mask, '.') && !strchr(mask, '*'))
+            return;
+        fprintf(stdout, "Client {\n\thost = \"%s\";\n", mask);
+    }
+
+    if (passwd)
+        fprintf(stdout, "\tpassword = \"%s\";\n", passwd);
+
+    if (maxlinks >= 0)
+        fprintf(stdout, "\tmaxlinks = %ld;\n", maxlinks);
+
+    fprintf(stdout, "\tclass = \"%s\";\n};\n", class);
+}
+
+static void do_client(void)
+{
+    char *passwd = NULL, *delim;
+    long maxlinks;
+
+    /* Print the current line. */
+    fprintf(stdout, "# %s\n", orig_line);
+
+    /* See if the password is really a maxlinks count. */
+    maxlinks = strtol(fields[1], &delim, 10);
+    if (fields[1][0] == '\0')
+        maxlinks = -1;
+    else if (maxlinks < 0 || maxlinks > 99 || *delim != '\0')
+        passwd = fields[1];
+
+    /* Translate the IP and host mask fields into blocks. */
+    emit_client(fields[0], passwd, fields[4], maxlinks, 1);
+    emit_client(fields[2], passwd, fields[4], maxlinks, 0);
+}
+
+int main(int argc, char *argv[])
+{
+    FILE *ifile;
+
+    if (argc < 2)
+        ifile = stdin;
+    else if (!(ifile = fopen(argv[1], "rt"))) {
+        fprintf(stderr, "Unable to open file %s for input.\n", argv[1]);
+        return 1;
+    }
+
+    for (lineno = 1; fgets(line, sizeof(line), ifile); ++lineno) {
+        /* Read line and pass comments through. */
+        size_t len = strlen(line);
+        if (line[0] == '#') {
+            fputs(line, stdout);
+            continue;
+        }
+        /* Strip trailing whitespace. */
+        while (len > 0 && isspace(line[len-1]))
+            line[--len] = '\0';
+        /* Pass blank lines through. */
+        if (len == 0) {
+            fputc('\n', stdout);
+            continue;
+        }
+        /* Skip but report invalid lines. */
+        if (line[1] != ':') {
+            fprintf(stdout, "# %s\n", line);
+            fprintf(stderr, "Invalid input line %d.\n", lineno);
+            continue;
+        }
+        /* Copy the original line into a reusable variable. */
+        strcpy(orig_line, line);
+        /* Split line into fields. */
+        nfields = split_line(line + 2, fields);
+
+        /* Process the input line. */
+        switch (line[0]) {
+        case 'A': case 'a': simple_line("Admin", admin_names, NULL); break;
+        case 'C': case 'c': do_connect(); break;
+        case 'D':           simple_line("CRule", crule_names, "all = yes;"); break;
+                  case 'd': simple_line("CRule", crule_names, NULL); break;
+        case 'F': case 'f': do_feature(); break;
+        case 'H': case 'h': do_hub(); break;
+        case 'I': case 'i': do_client(); break;
+        case 'K': case 'k': do_kill(); break;
+        case 'L': case 'l': do_leaf(); break;
+        case 'M': case 'm': simple_line("General", general_names, NULL); break;
+        case 'O':           do_operator(0); break;
+                  case 'o': do_operator(1); break;
+        case 'P': case 'p': do_port(); break;
+        case 'Q': case 'q': do_quarantine(); break;
+        case 'T': case 't': simple_line("Motd", motd_names, NULL); break;
+        case 'U': case 'u': do_uworld(); break;
+        case 'Y': case 'y': simple_line("Class", class_names, NULL); break;
+        default:
+            fprintf(stderr, "Unknown line %u with leading character '%c'.\n", lineno, line[0]);
+            break;
+        }
+    }
+
+    fclose(ifile);
+
+    fputs("\n# The following lines were intentionally moved and rearranged."
+          "\n# Our apologies for any inconvenience this may cause."
+          "\n\n", stdout);
+    finish_connects();
+    finish_quarantines();
+    finish_features();
+    finish_operators();
+
+    return 0;
+}
diff --git a/ircd/crule.c b/ircd/crule.c
new file mode 100644 (file)
index 0000000..2f7e409
--- /dev/null
@@ -0,0 +1,867 @@
+/**
+ * @file
+ * @brief Connection rule parser and checker
+ * @version $Id: crule.c 1334 2005-03-20 16:06:30Z entrope $
+ *
+ * by Tony Vencill (Tonto on IRC) <vencill@bga.com>
+ *
+ * The majority of this file is a recursive descent parser used to convert
+ * connection rules into expression trees when the conf file is read.
+ * All parsing structures and types are hidden in the interest of good
+ * programming style and to make possible future data structure changes
+ * without affecting the interface between this patch and the rest of the
+ * server.  The only functions accessible externally are crule_parse,
+ * crule_free, and crule_eval.  Prototypes for these functions can be
+ * found in h.h.
+ *
+ * Please direct any connection rule or SmartRoute questions to Tonto on
+ * IRC or by email to vencill@bga.com.
+ *
+ * For parser testing, defining CR_DEBUG generates a stand-alone parser
+ * that takes rules from stdin and prints out memory allocation
+ * information and the parsed rule.  This stand alone parser is ignorant
+ * of the irc server and thus cannot do rule evaluation.  Do not define
+ * this flag when compiling the server!  If you wish to generate the
+ * test parser, compile from the ircd directory with a line similar to
+ * cc -o parser -DCR_DEBUG crule.c
+ *
+ * The define CR_CHKCONF is provided to generate routines needed in
+ * chkconf.  These consist of the parser, a different crule_parse that
+ * prints errors to stderr, and crule_free (just for good style and to
+ * more closely simulate the actual ircd environment).  crule_eval and
+ * the rule functions are made empty functions as in the stand-alone
+ * test parser.
+ *
+ * The production rules for the grammar are as follows ("rule" is the
+ * starting production):
+ *
+ *   rule:
+ *     orexpr END          END is end of input or :
+ *   orexpr:
+ *     andexpr
+ *     andexpr || orexpr
+ *   andexpr:
+ *     primary
+ *     primary && andexpr
+ *  primary:
+ *    function
+ *    ! primary
+ *    ( orexpr )
+ *  function:
+ *    word ( )             word is alphanumeric string, first character
+ *    word ( arglist )       must be a letter
+ *  arglist:
+ *    word
+ *    word , arglist
+ */
+#include "config.h"
+
+#include "crule.h"
+#ifndef CR_DEBUG
+
+/* ircd functions and types we need */
+#include "client.h"
+#include "ircd.h"
+#include "ircd_alloc.h"
+#include "ircd_chattr.h"
+#include "ircd_string.h"
+#include "match.h"
+#include "s_bsd.h"
+#include "s_debug.h"
+#include "struct.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#else /* includes and defines to make the stand-alone test parser */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#define BadPtr(x) (!(x) || (*(x) == '\0'))
+#define DupString(x,y) \
+        do { \
+          x = (char*) MyMalloc(strlen(y)+1); \
+        strcpy(x,y); \
+        } while(0)
+
+/* We don't care about collation discrepancies here, it seems.... */
+#define ircd_strcmp strcasecmp
+
+#endif
+
+#include <string.h>
+
+
+#if defined(CR_DEBUG) || defined(CR_CHKCONF)
+#undef MyMalloc
+#undef malloc
+#define MyMalloc malloc
+#undef MyFree
+#undef free
+#define MyFree free
+#endif
+
+/* some constants and shared data types */
+#define CR_MAXARGLEN 80         /**< Maximum arg length (must be > HOSTLEN) */
+#define CR_MAXARGS 3            /**< Maximum number of args for a rule */
+
+/*
+ * Some symbols for easy reading
+ */
+
+/** Input scanner tokens. */
+enum crule_token {
+  CR_UNKNOWN,    /**< Unknown token type. */
+  CR_END,        /**< End of input ('\\0' or ':'). */
+  CR_AND,        /**< Logical and operator (&&). */
+  CR_OR,         /**< Logical or operator (||). */
+  CR_NOT,        /**< Logical not operator (!). */
+  CR_OPENPAREN,  /**< Open parenthesis. */
+  CR_CLOSEPAREN, /**< Close parenthesis. */
+  CR_COMMA,      /**< Comma. */
+  CR_WORD        /**< Something that looks like a hostmask (alphanumerics, "*?.-"). */
+};
+
+/** Parser error codes. */
+enum crule_errcode {
+  CR_NOERR,      /**< No error. */
+  CR_UNEXPCTTOK, /**< Invalid token given context. */
+  CR_UNKNWTOK,   /**< Input did not form a valid token. */
+  CR_EXPCTAND,   /**< Did not see expected && operator. */
+  CR_EXPCTOR,    /**< Did not see expected || operator. */
+  CR_EXPCTPRIM,  /**< Expected a primitive (parentheses, ! or word). */
+  CR_EXPCTOPEN,  /**< Expected an open parenthesis after function name. */
+  CR_EXPCTCLOSE, /**< Expected a close parenthesis to match open parenthesis. */
+  CR_UNKNWFUNC,  /**< Attempt to use an unknown function. */
+  CR_ARGMISMAT   /**< Wrong number of arguments to function. */
+};
+
+/*
+ * Expression tree structure, function pointer, and tree pointer local!
+ */
+/** Evaluation function for a connection rule. */
+typedef int (*crule_funcptr) (int, void **);
+
+/** Node in a connection rule tree. */
+struct CRuleNode {
+  crule_funcptr funcptr; /**< Evaluation function for this node. */
+  int numargs;           /**< Number of arguments. */
+  void *arg[CR_MAXARGS]; /**< Array of arguments.  For operators, each arg
+                            is a tree element; for functions, each arg is
+                            a string. */
+};
+
+/** Typedef to save typing effort. */
+typedef struct CRuleNode* CRuleNodePtr;
+
+/* local rule function prototypes */
+static int crule_connected(int, void *[]);
+static int crule_directcon(int, void *[]);
+static int crule_via(int, void *[]);
+static int crule_directop(int, void *[]);
+static int crule__andor(int, void *[]);
+static int crule__not(int, void *[]);
+
+/* local parsing function prototypes */
+static int crule_gettoken(int* token, const char** str);
+static void crule_getword(char*, int*, size_t, const char**);
+static int crule_parseandexpr(CRuleNodePtr*, int *, const char**);
+static int crule_parseorexpr(CRuleNodePtr*, int *, const char**);
+static int crule_parseprimary(CRuleNodePtr*, int *, const char**);
+static int crule_parsefunction(CRuleNodePtr*, int *, const char**);
+static int crule_parsearglist(CRuleNodePtr, int *, const char**);
+
+#if defined(CR_DEBUG) || defined(CR_CHKCONF)
+/*
+ * Prototypes for the test parser; if not debugging,
+ * these are defined in h.h
+ */
+struct CRuleNode* crule_parse(const char*);
+void crule_free(struct CRuleNode**);
+#ifdef CR_DEBUG
+void print_tree(CRuleNodePtr);
+#endif
+#endif
+
+/** Error messages, indexed by the corresponding crule_errcode. */
+char *crule_errstr[] = {
+  "Unknown error",              /* NOERR? - for completeness */
+  "Unexpected token",           /* UNEXPCTTOK */
+  "Unknown token",              /* UNKNWTOK */
+  "And expr expected",          /* EXPCTAND */
+  "Or expr expected",           /* EXPCTOR */
+  "Primary expected",           /* EXPCTPRIM */
+  "( expected",                 /* EXPCTOPEN */
+  ") expected",                 /* EXPCTCLOSE */
+  "Unknown function",           /* UNKNWFUNC */
+  "Argument mismatch"           /* ARGMISMAT */
+};
+
+/** Connection rule function table entry. */
+struct crule_funclistent {
+  char name[15];         /**< Function name. */
+  int reqnumargs;        /**< Required number of arguments. */
+  crule_funcptr funcptr; /**< Handler function. */
+};
+
+/** Defined connection rules. */
+struct crule_funclistent crule_funclist[] = {
+  /* maximum function name length is 14 chars */
+  {"connected", 1, crule_connected},
+  {"directcon", 1, crule_directcon},
+  {"via", 2, crule_via},
+  {"directop", 0, crule_directop},
+  {"", 0, NULL}                 /* this must be here to mark end of list */
+};
+
+/** Check whether any connected server matches crulearg[0].
+ * @param[in] numargs Number of valid args in \a crulearg.
+ * @param[in] crulearg Argument array.
+ * @return Non-zero if the condition is true, zero if not.
+ */
+static int crule_connected(int numargs, void *crulearg[])
+{
+#if !defined(CR_DEBUG) && !defined(CR_CHKCONF)
+  struct Client *acptr;
+
+  /* taken from m_links */
+  for (acptr = GlobalClientList; acptr; acptr = cli_next(acptr))
+  {
+    if (!IsServer(acptr) && !IsMe(acptr))
+      continue;
+    if (match((char *)crulearg[0], cli_name(acptr)))
+      continue;
+    return (1);
+  }
+#endif
+  return (0);
+}
+
+/** Check whether any directly connected server matches crulearg[0].
+ * @param[in] numargs Number of valid args in \a crulearg.
+ * @param[in] crulearg Argument array.
+ * @return Non-zero if the condition is true, zero if not.
+ */
+static int crule_directcon(int numargs, void *crulearg[])
+{
+#if !defined(CR_DEBUG) && !defined(CR_CHKCONF)
+  int i;
+  struct Client *acptr;
+
+  /* adapted from m_trace and exit_one_client */
+  for (i = 0; i <= HighestFd; i++)
+  {
+    if (!(acptr = LocalClientArray[i]) || !IsServer(acptr))
+      continue;
+    if (match((char *)crulearg[0], cli_name(acptr)))
+      continue;
+    return (1);
+  }
+#endif
+  return (0);
+}
+
+/** Check whether a connected server matching crulearg[1] is
+ * connnected to me behind one matching crulearg[0].
+ * @param[in] numargs Number of valid args in \a crulearg.
+ * @param[in] crulearg Argument array.
+ * @return Non-zero if the condition is true, zero if not.
+ */
+static int crule_via(int numargs, void *crulearg[])
+{
+#if !defined(CR_DEBUG) && !defined(CR_CHKCONF)
+  struct Client *acptr;
+
+  /* adapted from m_links */
+  for (acptr = GlobalClientList; acptr; acptr = cli_next(acptr))
+  {
+    if (!IsServer(acptr) && !IsMe(acptr))
+      continue;
+    if (match((char *)crulearg[1], cli_name(acptr)))
+      continue;
+    if (match((char *)crulearg[0], cli_name(cli_from(acptr))))
+      continue;
+    return (1);
+  }
+#endif
+  return (0);
+}
+
+/** Check whether we have a local IRC operator.
+ * @param[in] numargs Number of valid args in \a crulearg.
+ * @param[in] crulearg Argument array.
+ * @return Non-zero if the condition is true, zero if not.
+ */
+static int crule_directop(int numargs, void *crulearg[])
+{
+#if !defined(CR_DEBUG) && !defined(CR_CHKCONF)
+  int i;
+  struct Client *acptr;
+
+  /* adapted from m_trace */
+  for (i = 0; i <= HighestFd; i++)
+  {
+    if (!(acptr = LocalClientArray[i]) || !IsAnOper(acptr))
+      continue;
+    return (1);
+  }
+#endif
+  return (0);
+}
+
+/** Evaluate a connection rule.
+ * @param[in] rule Rule to evalute.
+ * @return Non-zero if the rule allows the connection, zero otherwise.
+ */
+int crule_eval(struct CRuleNode* rule)
+{
+  return (rule->funcptr(rule->numargs, rule->arg));
+}
+
+/** Perform an and-or-or test on crulearg[0] and crulearg[1].
+ * If crulearg[2] is non-NULL, it means do OR; if it is NULL, do AND.
+ * @param[in] numargs Number of valid args in \a crulearg.
+ * @param[in] crulearg Argument array.
+ * @return Non-zero if the condition is true, zero if not.
+ */
+static int crule__andor(int numargs, void *crulearg[])
+{
+  int result1;
+
+  result1 = crule_eval(crulearg[0]);
+  if (crulearg[2])              /* or */
+    return (result1 || crule_eval(crulearg[1]));
+  else
+    return (result1 && crule_eval(crulearg[1]));
+}
+
+/** Logically invert the result of crulearg[0].
+ * @param[in] numargs Number of valid args in \a crulearg.
+ * @param[in] crulearg Argument array.
+ * @return Non-zero if the condition is true, zero if not.
+ */
+static int crule__not(int numargs, void *crulearg[])
+{
+  return (!crule_eval(crulearg[0]));
+}
+
+/** Scan an input token from \a ruleptr.
+ * @param[out] next_tokp Receives type of next token.
+ * @param[in,out] ruleptr Next readable character from input.
+ * @return Either CR_UNKNWTOK if the input was unrecognizable, else CR_NOERR.
+ */
+static int crule_gettoken(int* next_tokp, const char** ruleptr)
+{
+  char pending = '\0';
+
+  *next_tokp = CR_UNKNOWN;
+  while (*next_tokp == CR_UNKNOWN)
+    switch (*(*ruleptr)++)
+    {
+      case ' ':
+      case '\t':
+        break;
+      case '&':
+        if (pending == '\0')
+          pending = '&';
+        else if (pending == '&')
+          *next_tokp = CR_AND;
+        else
+          return (CR_UNKNWTOK);
+        break;
+      case '|':
+        if (pending == '\0')
+          pending = '|';
+        else if (pending == '|')
+          *next_tokp = CR_OR;
+        else
+          return (CR_UNKNWTOK);
+        break;
+      case '!':
+        *next_tokp = CR_NOT;
+        break;
+      case '(':
+        *next_tokp = CR_OPENPAREN;
+        break;
+      case ')':
+        *next_tokp = CR_CLOSEPAREN;
+        break;
+      case ',':
+        *next_tokp = CR_COMMA;
+        break;
+      case '\0':
+        (*ruleptr)--;
+        *next_tokp = CR_END;
+        break;
+      case ':':
+        *next_tokp = CR_END;
+        break;
+      default:
+        if ((IsAlpha(*(--(*ruleptr)))) || (**ruleptr == '*') ||
+            (**ruleptr == '?') || (**ruleptr == '.') || (**ruleptr == '-'))
+          *next_tokp = CR_WORD;
+        else
+          return (CR_UNKNWTOK);
+        break;
+    }
+  return CR_NOERR;
+}
+
+/** Scan a word from \a ruleptr.
+ * @param[out] word Output buffer.
+ * @param[out] wordlenp Length of word written to \a word (not including terminating NUL).
+ * @param[in] maxlen Maximum number of bytes writable to \a word.
+ * @param[in,out] ruleptr Next readable character from input.
+ */
+static void crule_getword(char* word, int* wordlenp, size_t maxlen, const char** ruleptr)
+{
+  char *word_ptr;
+
+  word_ptr = word;
+  while ((size_t)(word_ptr - word) < maxlen
+      && (IsAlnum(**ruleptr)
+      || **ruleptr == '*' || **ruleptr == '?'
+      || **ruleptr == '.' || **ruleptr == '-'))
+    *word_ptr++ = *(*ruleptr)++;
+  *word_ptr = '\0';
+  *wordlenp = word_ptr - word;
+}
+
+/** Parse an entire rule.
+ * @param[in] rule Text form of rule.
+ * @return CRuleNode for rule, or NULL if there was a parse error.
+ */
+struct CRuleNode* crule_parse(const char *rule)
+{
+  const char* ruleptr = rule;
+  int next_tok;
+  struct CRuleNode* ruleroot = 0;
+  int errcode = CR_NOERR;
+
+  if ((errcode = crule_gettoken(&next_tok, &ruleptr)) == CR_NOERR) {
+    if ((errcode = crule_parseorexpr(&ruleroot, &next_tok, &ruleptr)) == CR_NOERR) {
+      if (ruleroot != NULL) {
+        if (next_tok == CR_END)
+          return (ruleroot);
+        else
+          errcode = CR_UNEXPCTTOK;
+      }
+      else
+        errcode = CR_EXPCTOR;
+    }
+  }
+  if (ruleroot != NULL)
+    crule_free(&ruleroot);
+#if !defined(CR_DEBUG) && !defined(CR_CHKCONF)
+  Debug((DEBUG_ERROR, "%s in rule: %s", crule_errstr[errcode], rule));
+#else
+  fprintf(stderr, "%s in rule: %s\n", crule_errstr[errcode], rule);
+#endif
+  return 0;
+}
+
+/** Parse an or expression.
+ * @param[out] orrootp Receives parsed node.
+ * @param[in,out] next_tokp Next input token type.
+ * @param[in,out] ruleptr Next input character.
+ * @return A crule_errcode value.
+ */
+static int crule_parseorexpr(CRuleNodePtr * orrootp, int *next_tokp, const char** ruleptr)
+{
+  int errcode = CR_NOERR;
+  CRuleNodePtr andexpr;
+  CRuleNodePtr orptr;
+
+  *orrootp = NULL;
+  while (errcode == CR_NOERR)
+  {
+    errcode = crule_parseandexpr(&andexpr, next_tokp, ruleptr);
+    if ((errcode == CR_NOERR) && (*next_tokp == CR_OR))
+    {
+      orptr = (CRuleNodePtr) MyMalloc(sizeof(struct CRuleNode));
+#ifdef CR_DEBUG
+      fprintf(stderr, "allocating or element at %ld\n", orptr);
+#endif
+      orptr->funcptr = crule__andor;
+      orptr->numargs = 3;
+      orptr->arg[2] = (void *)1;
+      if (*orrootp != NULL)
+      {
+        (*orrootp)->arg[1] = andexpr;
+        orptr->arg[0] = *orrootp;
+      }
+      else
+        orptr->arg[0] = andexpr;
+      *orrootp = orptr;
+    }
+    else
+    {
+      if (*orrootp != NULL)
+      {
+        if (andexpr != NULL)
+        {
+          (*orrootp)->arg[1] = andexpr;
+          return (errcode);
+        }
+        else
+        {
+          (*orrootp)->arg[1] = NULL;    /* so free doesn't seg fault */
+          return (CR_EXPCTAND);
+        }
+      }
+      else
+      {
+        *orrootp = andexpr;
+        return (errcode);
+      }
+    }
+    if ((errcode = crule_gettoken(next_tokp, ruleptr)) != CR_NOERR)
+      return (errcode);
+  }
+  return (errcode);
+}
+
+/** Parse an and expression.
+ * @param[out] androotp Receives parsed node.
+ * @param[in,out] next_tokp Next input token type.
+ * @param[in,out] ruleptr Next input character.
+ * @return A crule_errcode value.
+ */
+static int crule_parseandexpr(CRuleNodePtr * androotp, int *next_tokp, const char** ruleptr)
+{
+  int errcode = CR_NOERR;
+  CRuleNodePtr primary;
+  CRuleNodePtr andptr;
+
+  *androotp = NULL;
+  while (errcode == CR_NOERR)
+  {
+    errcode = crule_parseprimary(&primary, next_tokp, ruleptr);
+    if ((errcode == CR_NOERR) && (*next_tokp == CR_AND))
+    {
+      andptr = (CRuleNodePtr) MyMalloc(sizeof(struct CRuleNode));
+#ifdef CR_DEBUG
+      fprintf(stderr, "allocating and element at %ld\n", andptr);
+#endif
+      andptr->funcptr = crule__andor;
+      andptr->numargs = 3;
+      andptr->arg[2] = (void *)0;
+      if (*androotp != NULL)
+      {
+        (*androotp)->arg[1] = primary;
+        andptr->arg[0] = *androotp;
+      }
+      else
+        andptr->arg[0] = primary;
+      *androotp = andptr;
+    }
+    else
+    {
+      if (*androotp != NULL)
+      {
+        if (primary != NULL)
+        {
+          (*androotp)->arg[1] = primary;
+          return (errcode);
+        }
+        else
+        {
+          (*androotp)->arg[1] = NULL;   /* so free doesn't seg fault */
+          return (CR_EXPCTPRIM);
+        }
+      }
+      else
+      {
+        *androotp = primary;
+        return (errcode);
+      }
+    }
+    if ((errcode = crule_gettoken(next_tokp, ruleptr)) != CR_NOERR)
+      return (errcode);
+  }
+  return (errcode);
+}
+
+/** Parse a primary expression.
+ * @param[out] primrootp Receives parsed node.
+ * @param[in,out] next_tokp Next input token type.
+ * @param[in,out] ruleptr Next input character.
+ * @return A crule_errcode value.
+ */
+static int crule_parseprimary(CRuleNodePtr* primrootp, int *next_tokp, const char** ruleptr)
+{
+  CRuleNodePtr *insertionp;
+  int errcode = CR_NOERR;
+
+  *primrootp = NULL;
+  insertionp = primrootp;
+  while (errcode == CR_NOERR)
+  {
+    switch (*next_tokp)
+    {
+      case CR_OPENPAREN:
+        if ((errcode = crule_gettoken(next_tokp, ruleptr)) != CR_NOERR)
+          break;
+        if ((errcode = crule_parseorexpr(insertionp, next_tokp, ruleptr)) != CR_NOERR)
+          break;
+        if (*insertionp == NULL)
+        {
+          errcode = CR_EXPCTAND;
+          break;
+        }
+        if (*next_tokp != CR_CLOSEPAREN)
+        {
+          errcode = CR_EXPCTCLOSE;
+          break;
+        }
+        errcode = crule_gettoken(next_tokp, ruleptr);
+        break;
+      case CR_NOT:
+        *insertionp = (CRuleNodePtr) MyMalloc(sizeof(struct CRuleNode));
+#ifdef CR_DEBUG
+        fprintf(stderr, "allocating primary element at %ld\n", *insertionp);
+#endif
+        (*insertionp)->funcptr = crule__not;
+        (*insertionp)->numargs = 1;
+        (*insertionp)->arg[0] = NULL;
+        insertionp = (CRuleNodePtr *) & ((*insertionp)->arg[0]);
+        if ((errcode = crule_gettoken(next_tokp, ruleptr)) != CR_NOERR)
+          break;
+        continue;
+      case CR_WORD:
+        errcode = crule_parsefunction(insertionp, next_tokp, ruleptr);
+        break;
+      default:
+        if (*primrootp == NULL)
+          errcode = CR_NOERR;
+        else
+          errcode = CR_EXPCTPRIM;
+        break;
+    }
+    return (errcode);
+  }
+  return (errcode);
+}
+
+/** Parse a function call.
+ * @param[out] funcrootp Receives parsed node.
+ * @param[in,out] next_tokp Next input token type.
+ * @param[in,out] ruleptr Next input character.
+ * @return A crule_errcode value.
+ */
+static int crule_parsefunction(CRuleNodePtr* funcrootp, int* next_tokp, const char** ruleptr)
+{
+  int errcode = CR_NOERR;
+  char funcname[CR_MAXARGLEN];
+  int namelen;
+  int funcnum;
+
+  *funcrootp = NULL;
+  crule_getword(funcname, &namelen, CR_MAXARGLEN - 1, ruleptr);
+  if ((errcode = crule_gettoken(next_tokp, ruleptr)) != CR_NOERR)
+    return (errcode);
+  if (*next_tokp == CR_OPENPAREN)
+  {
+    for (funcnum = 0;; funcnum++)
+    {
+      if (0 == ircd_strcmp(crule_funclist[funcnum].name, funcname))
+        break;
+      if (crule_funclist[funcnum].name[0] == '\0')
+        return (CR_UNKNWFUNC);
+    }
+    if ((errcode = crule_gettoken(next_tokp, ruleptr)) != CR_NOERR)
+      return (errcode);
+    *funcrootp = (CRuleNodePtr) MyMalloc(sizeof(struct CRuleNode));
+#ifdef CR_DEBUG
+    fprintf(stderr, "allocating function element at %ld\n", *funcrootp);
+#endif
+    (*funcrootp)->funcptr = NULL;       /* for freeing aborted trees */
+    if ((errcode =
+        crule_parsearglist(*funcrootp, next_tokp, ruleptr)) != CR_NOERR)
+      return (errcode);
+    if (*next_tokp != CR_CLOSEPAREN)
+      return (CR_EXPCTCLOSE);
+    if ((crule_funclist[funcnum].reqnumargs != (*funcrootp)->numargs) &&
+        (crule_funclist[funcnum].reqnumargs != -1))
+      return (CR_ARGMISMAT);
+    if ((errcode = crule_gettoken(next_tokp, ruleptr)) != CR_NOERR)
+      return (errcode);
+    (*funcrootp)->funcptr = crule_funclist[funcnum].funcptr;
+    return (CR_NOERR);
+  }
+  else
+    return (CR_EXPCTOPEN);
+}
+
+/** Parse the argument list to a CRuleNode.
+ * @param[in,out] argrootp Node whos argument list is being populated.
+ * @param[in,out] next_tokp Next input token type.
+ * @param[in,out] ruleptr Next input character.
+ * @return A crule_errcode value.
+ */
+static int crule_parsearglist(CRuleNodePtr argrootp, int *next_tokp, const char** ruleptr)
+{
+  int errcode = CR_NOERR;
+  char *argelemp = NULL;
+  char currarg[CR_MAXARGLEN];
+  int arglen = 0;
+  char word[CR_MAXARGLEN];
+  int wordlen = 0;
+
+  argrootp->numargs = 0;
+  currarg[0] = '\0';
+  while (errcode == CR_NOERR)
+  {
+    switch (*next_tokp)
+    {
+      case CR_WORD:
+        crule_getword(word, &wordlen, CR_MAXARGLEN - 1, ruleptr);
+        if (currarg[0] != '\0')
+        {
+          if ((arglen + wordlen) < (CR_MAXARGLEN - 1))
+          {
+            strcat(currarg, " ");
+            strcat(currarg, word);
+            arglen += wordlen + 1;
+          }
+        }
+        else
+        {
+          strcpy(currarg, word);
+          arglen = wordlen;
+        }
+        errcode = crule_gettoken(next_tokp, ruleptr);
+        break;
+      default:
+#if !defined(CR_DEBUG) && !defined(CR_CHKCONF)
+        collapse(currarg);
+#endif
+        if (!BadPtr(currarg))
+        {
+          DupString(argelemp, currarg);
+          argrootp->arg[argrootp->numargs++] = (void *)argelemp;
+        }
+        if (*next_tokp != CR_COMMA)
+          return (CR_NOERR);
+        currarg[0] = '\0';
+        errcode = crule_gettoken(next_tokp, ruleptr);
+        break;
+    }
+  }
+  return (errcode);
+}
+
+/*
+ * This function is recursive..  I wish I knew a nonrecursive way but
+ * I don't.  Anyway, recursion is fun..  :)
+ * DO NOT CALL THIS FUNCTION WITH A POINTER TO A NULL POINTER
+ * (i.e.: If *elem is NULL, you're doing it wrong - seg fault)
+ */
+/** Free a connection rule and all its children.
+ * @param[in,out] elem Pointer to pointer to element to free.  MUST NOT BE NULL.
+ */
+void crule_free(struct CRuleNode** elem)
+{
+  int arg, numargs;
+
+  if ((*(elem))->funcptr == crule__not)
+  {
+    /* type conversions and ()'s are fun! ;)  here have an aspirin.. */
+    if ((*(elem))->arg[0] != NULL)
+      crule_free((struct CRuleNode**) &((*(elem))->arg[0]));
+  }
+  else if ((*(elem))->funcptr == crule__andor)
+  {
+    crule_free((struct CRuleNode**) &((*(elem))->arg[0]));
+    if ((*(elem))->arg[1] != NULL)
+      crule_free((struct CRuleNode**) &((*(elem))->arg[1]));
+  }
+  else
+  {
+    numargs = (*(elem))->numargs;
+    for (arg = 0; arg < numargs; arg++)
+      MyFree((*(elem))->arg[arg]);
+  }
+#ifdef CR_DEBUG
+  fprintf(stderr, "freeing element at %ld\n", *elem);
+#endif
+  MyFree(*elem);
+  *elem = 0;
+}
+
+#ifdef CR_DEBUG
+/** Display a connection rule as text.
+ * @param[in] printelem Connection rule to display.
+ */
+static void print_tree(CRuleNodePtr printelem)
+{
+  int funcnum, arg;
+
+  if (printelem->funcptr == crule__not)
+  {
+    printf("!( ");
+    print_tree((CRuleNodePtr) printelem->arg[0]);
+    printf(") ");
+  }
+  else if (printelem->funcptr == crule__andor)
+  {
+    printf("( ");
+    print_tree((CRuleNodePtr) printelem->arg[0]);
+    if (printelem->arg[2])
+      printf("|| ");
+    else
+      printf("&& ");
+    print_tree((CRuleNodePtr) printelem->arg[1]);
+    printf(") ");
+  }
+  else
+  {
+    for (funcnum = 0;; funcnum++)
+    {
+      if (printelem->funcptr == crule_funclist[funcnum].funcptr)
+        break;
+      if (crule_funclist[funcnum].funcptr == NULL)
+        MyCoreDump;
+    }
+    printf("%s(", crule_funclist[funcnum].name);
+    for (arg = 0; arg < printelem->numargs; arg++)
+    {
+      if (arg != 0)
+        printf(",");
+      printf("%s", (char *)printelem->arg[arg]);
+    }
+    printf(") ");
+  }
+}
+
+#endif
+
+#ifdef CR_DEBUG
+/** Read connection rules from stdin and display parsed forms as text.
+ * @return Zero.
+ */
+int main(void)
+{
+  char indata[256];
+  CRuleNode* rule;
+
+  printf("rule: ");
+  while (fgets(indata, 256, stdin) != NULL)
+  {
+    indata[strlen(indata) - 1] = '\0';  /* lose the newline */
+    if ((rule = crule_parse(indata)) != NULL)
+    {
+      printf("equivalent rule: ");
+      print_tree((CRuleNodePtr) rule);
+      printf("\n");
+      crule_free(&rule);
+    }
+    printf("\nrule: ");
+  }
+  printf("\n");
+
+  return 0;
+}
+
+#endif
diff --git a/ircd/dbuf.c b/ircd/dbuf.c
new file mode 100644 (file)
index 0000000..8366235
--- /dev/null
@@ -0,0 +1,389 @@
+/*
+ * IRC - Internet Relay Chat, common/dbuf.c
+ * Copyright (C) 1990 Markku Savela
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+/** @file
+ * @brief Implementation of functions dealing with data buffers.
+ * @version $Id: dbuf.c 1271 2004-12-11 05:14:07Z klmitch $
+ */
+#include "config.h"
+
+#include "dbuf.h"
+#include "ircd_alloc.h"
+#include "ircd_chattr.h"
+#include "ircd_features.h"
+#include "ircd_log.h"
+#include "send.h"
+#include "sys.h"       /* MIN */
+
+/* #include <assert.h> -- Now using assert in ircd_log.h */
+#include <string.h>
+
+/*
+ * dbuf is a collection of functions which can be used to
+ * maintain a dynamic buffering of a byte stream.
+ * Functions allocate and release memory dynamically as
+ * required [Actually, there is nothing that prevents
+ * this package maintaining the buffer on disk, either]
+ */
+
+/** Number of dbufs allocated.
+ * This should only be modified by dbuf.c.
+ */
+int DBufAllocCount = 0;
+/** Number of dbufs in use.
+ * This should only be modified by dbuf.c.
+ */
+int DBufUsedCount = 0;
+
+/** List of allocated but unused DBuf structures. */
+static struct DBufBuffer *dbufFreeList = 0;
+
+/** Size of data for a single DBufBuffer. */
+#define DBUF_SIZE 2048
+
+/** Single data buffer in a DBuf. */
+struct DBufBuffer {
+  struct DBufBuffer *next;      /**< Next data buffer, NULL if last */
+  char *start;                  /**< data starts here */
+  char *end;                    /**< data ends here */
+  char data[DBUF_SIZE];         /**< Actual data stored here */
+};
+
+/** Return memory used by allocated data buffers.
+ * @param[out] allocated Receives number of bytes allocated to DBufs.
+ * @param[out] used Receives number of bytes for currently used DBufs.
+ */
+void dbuf_count_memory(size_t *allocated, size_t *used)
+{
+  assert(0 != allocated);
+  assert(0 != used);
+  *allocated = DBufAllocCount * sizeof(struct DBufBuffer);
+  *used = DBufUsedCount * sizeof(struct DBufBuffer);
+}
+
+/** Allocate a new DBufBuffer.
+ * If #dbufFreeList != NULL, use the head of that list; otherwise,
+ * allocate a new buffer.
+ * @return Newly allocated buffer list.
+ */
+static struct DBufBuffer *dbuf_alloc(void)
+{
+  struct DBufBuffer* db = dbufFreeList;
+
+  if (db) {
+    dbufFreeList = db->next;
+    ++DBufUsedCount;
+  }
+  else if (DBufAllocCount * DBUF_SIZE < feature_int(FEAT_BUFFERPOOL)) {
+    db = (struct DBufBuffer*) MyMalloc(sizeof(struct DBufBuffer));
+    assert(0 != db);
+    ++DBufAllocCount;
+    ++DBufUsedCount;
+  }
+  return db;
+}
+
+/** Release a DBufBuffer back to the free list.
+ * @param[in] db Data buffer to release.
+ */
+static void dbuf_free(struct DBufBuffer *db)
+{
+  assert(0 != db);
+  --DBufUsedCount;
+  db->next = dbufFreeList;
+  dbufFreeList = db;
+}
+
+/** Handle a memory allocation error on a DBuf.
+ * This frees all the buffers owned by the DBuf, since we have to
+ * close the associated connection.
+ * @param[in] dyn DBuf to clean out.
+ * @return Zero.
+ */
+static int dbuf_malloc_error(struct DBuf *dyn)
+{
+  struct DBufBuffer *db;
+  struct DBufBuffer *next;
+
+  for (db = dyn->head; db; db = next)
+  {
+    next = db->next;
+    dbuf_free(db);
+  }
+  dyn->tail = dyn->head = 0;
+  dyn->length = 0;
+  return 0;
+}
+
+/** Append bytes to a data buffer.
+ * @param[in] dyn Buffer to append to.
+ * @param[in] buf Data to append.
+ * @param[in] length Number of bytes to append.
+ * @return Non-zero on success, or zero on failure.
+ */
+int dbuf_put(struct DBuf *dyn, const char *buf, unsigned int length)
+{
+  struct DBufBuffer** h;
+  struct DBufBuffer*  db;
+  unsigned int chunk;
+
+  assert(0 != dyn);
+  assert(0 != buf);
+  /*
+   * Locate the last non-empty buffer. If the last buffer is full,
+   * the loop will terminate with 'db==NULL'.
+   * This loop assumes that the 'dyn->length' field is correctly
+   * maintained, as it should--no other check really needed.
+   */
+  if (!dyn->length)
+    h = &(dyn->head);
+  else
+    h = &(dyn->tail);
+  /*
+   * Append users data to buffer, allocating buffers as needed
+   */
+  dyn->length += length;
+
+  for (; length > 0; h = &(db->next)) {
+    if (0 == (db = *h)) {
+      if (0 == (db = dbuf_alloc())) {
+       if (feature_bool(FEAT_HAS_FERGUSON_FLUSHER)) {
+         /*
+          * from "Married With Children" episode were Al bought a REAL toilet
+          * on the black market because he was tired of the wimpy water
+          * conserving toilets they make these days --Bleep
+          */
+         /*
+          * Apparently this doesn't work, the server _has_ to
+          * dump a few clients to handle the load. A fully loaded
+          * server cannot handle a net break without dumping some
+          * clients. If we flush the connections here under a full
+          * load we may end up starving the kernel for mbufs and
+          * crash the machine
+          */
+         /*
+          * attempt to recover from buffer starvation before
+          * bailing this may help servers running out of memory
+          */
+         flush_connections(0);
+         db = dbuf_alloc();
+       }
+
+        if (0 == db)
+          return dbuf_malloc_error(dyn);
+      }
+      dyn->tail = db;
+      *h = db;
+      db->next = 0;
+      db->start = db->end = db->data;
+    }
+    chunk = (db->data + DBUF_SIZE) - db->end;
+    if (chunk) {
+      if (chunk > length)
+        chunk = length;
+
+      memcpy(db->end, buf, chunk);
+
+      length -= chunk;
+      buf += chunk;
+      db->end += chunk;
+    }
+  }
+  return 1;
+}
+
+/** Get the first contiguous block of data from a DBuf.
+ * Generally a call to dbuf_map(dyn, &count) will be followed with a
+ * call to dbuf_delete(dyn, count).
+ * @param[in] dyn DBuf to retrieve data from.
+ * @param[out] length Receives number of bytes in block.
+ * @return Pointer to start of block (or NULL if the first block is empty).
+ */
+const char *dbuf_map(const struct DBuf* dyn, unsigned int* length)
+{
+  assert(0 != dyn);
+  assert(0 != length);
+
+  if (0 == dyn->length)
+  {
+    *length = 0;
+    return 0;
+  }
+  assert(0 != dyn->head);
+
+  *length = dyn->head->end - dyn->head->start;
+  return dyn->head->start;
+}
+
+/** Discard data from a DBuf.
+ * @param[in,out] dyn DBuf to drop data from.
+ * @param[in] length Number of bytes to discard.
+ */
+void dbuf_delete(struct DBuf *dyn, unsigned int length)
+{
+  struct DBufBuffer *db;
+  unsigned int chunk;
+
+  if (length > dyn->length)
+    length = dyn->length;
+
+  while (length > 0)
+  {
+    if (0 == (db = dyn->head))
+      break;
+    chunk = db->end - db->start;
+    if (chunk > length)
+      chunk = length;
+
+    length -= chunk;
+    dyn->length -= chunk;
+    db->start += chunk;
+
+    if (db->start == db->end)
+    {
+      dyn->head = db->next;
+      dbuf_free(db);
+    }
+  }
+  if (0 == dyn->head)
+  {
+    dyn->length = 0;
+    dyn->tail = 0;
+  }
+}
+
+/** Copy data from a buffer and remove what was copied.
+ * @param[in,out] dyn Buffer to copy from.
+ * @param[out] buf Buffer to write to.
+ * @param[in] length Maximum number of bytes to copy.
+ * @return Number of bytes actually copied.
+ */
+unsigned int dbuf_get(struct DBuf *dyn, char *buf, unsigned int length)
+{
+  unsigned int moved = 0;
+  unsigned int chunk;
+  const char *b;
+
+  assert(0 != dyn);
+  assert(0 != buf);
+
+  while (length > 0 && (b = dbuf_map(dyn, &chunk)) != 0)
+  {
+    if (chunk > length)
+      chunk = length;
+
+    memcpy(buf, b, chunk);
+    dbuf_delete(dyn, chunk);
+
+    buf += chunk;
+    length -= chunk;
+    moved += chunk;
+  }
+  return moved;
+}
+
+/** Flush empty lines from a buffer.
+ * @param[in,out] dyn Data buffer to flush.
+ * @return Number of bytes in first available block (or zero if none).
+ */
+static unsigned int dbuf_flush(struct DBuf *dyn)
+{
+  struct DBufBuffer *db = dyn->head;
+
+  if (0 == db)
+    return 0;
+
+  assert(db->start < db->end);
+  /*
+   * flush extra line terms
+   */
+  while (IsEol(*db->start))
+  {
+    if (++db->start == db->end)
+    {
+      dyn->head = db->next;
+      dbuf_free(db);
+      if (0 == (db = dyn->head))
+      {
+        dyn->tail = 0;
+        dyn->length = 0;
+        break;
+      }
+    }
+    --dyn->length;
+  }
+  return dyn->length;
+}
+
+/** Copy a single line from a data buffer.
+ * If the output buffer cannot hold the whole line, or if there is no
+ * EOL in the buffer, return 0.
+ * @param[in,out] dyn Data buffer to copy from.
+ * @param[out] buf Buffer to copy to.
+ * @param[in] length Maximum number of bytes to copy.
+ * @return Number of bytes copied to \a buf.
+ */
+unsigned int dbuf_getmsg(struct DBuf *dyn, char *buf, unsigned int length)
+{
+  struct DBufBuffer *db;
+  char *start;
+  char *end;
+  unsigned int count;
+  unsigned int copied = 0;
+
+  assert(0 != dyn);
+  assert(0 != buf);
+
+  if (0 == dbuf_flush(dyn))
+    return 0;
+
+  assert(0 != dyn->head);
+
+  db = dyn->head;
+  start = db->start;
+
+  assert(start < db->end);
+
+  if (length > dyn->length)
+    length = dyn->length;
+  /*
+   * might as well copy it while we're here
+   */
+  while (length > 0)
+  {
+    end = IRCD_MIN(db->end, (start + length));
+    while (start < end && !IsEol(*start))
+      *buf++ = *start++;
+
+    count = start - db->start;
+    if (start < end)
+    {
+      *buf = '\0';
+      copied += count;
+      dbuf_delete(dyn, copied);
+      dbuf_flush(dyn);
+      return copied;
+    }
+    if (0 == (db = db->next))
+      break;
+    copied += count;
+    length -= count;
+    start = db->start;
+  }
+  return 0;
+}
diff --git a/ircd/destruct_event.c b/ircd/destruct_event.c
new file mode 100644 (file)
index 0000000..da6d61b
--- /dev/null
@@ -0,0 +1,158 @@
+/*
+ * IRC - Internet Relay Chat, ircd/destruct_event.c
+ * Copyright (C) 2002 Carlo Wood <carlo@alinoe.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+/** @file
+ * @brief Implementation of timed channel destruction events.
+ * @version $Id: destruct_event.c 1271 2004-12-11 05:14:07Z klmitch $
+ */
+#include "config.h"
+
+#include "channel.h"   /* destruct_channel */
+#include "s_debug.h"
+#include "ircd_alloc.h"
+#include "ircd.h"
+#include "ircd_events.h"
+#include "ircd_log.h"
+#include "send.h"
+#include "msg.h"
+
+/* #include <assert.h> -- Now using assert in ircd_log.h */
+#include <stdlib.h>
+
+/** Structure describing a destruction event. */
+struct DestructEvent {
+  struct DestructEvent* next_event; /**< Next event in the queue. */
+  struct DestructEvent* prev_event; /**< Previous event in the queue. */
+  time_t expires;                   /**< When the destruction should happen. */
+  struct Channel* chptr;            /**< Channel to destroy. */
+};
+
+/** Head of short-delay destruction events.  */
+static struct DestructEvent* minute_list_top;
+/** Tail of short-delay destruction events. */
+static struct DestructEvent* minute_list_bottom;
+/** Head of long-delay destruction events. */
+static struct DestructEvent* days_list_top;
+/** Tail of long-delay destruction events. */
+static struct DestructEvent* days_list_bottom;
+
+/** Schedule a short-delay destruction event for \a chptr.
+ * @param[in] chptr Channel to destroy.
+ */
+void schedule_destruct_event_1m(struct Channel* chptr)
+{
+  struct DestructEvent* new_event;
+
+  /* Ignore request when we already have a destruct request */
+  if (chptr->destruct_event)
+    return;
+
+  /* Create a new destruct event and add it at the top of the list. */
+  new_event = (struct DestructEvent*)MyMalloc(sizeof(struct DestructEvent));
+  new_event->expires = TStime() + 60;  /* 1 minute from now */
+  new_event->next_event = NULL;
+  new_event->prev_event = minute_list_top;
+  new_event->chptr = chptr;
+
+  if (minute_list_top)
+    minute_list_top->next_event = new_event;
+  minute_list_top = new_event;
+  if (!minute_list_bottom)
+    minute_list_bottom = new_event;
+
+  chptr->destruct_event = new_event;
+}
+
+/** Schedule a long-delay destruction event for \a chptr.
+ * @param[in] chptr Channel to destroy.
+ */
+void schedule_destruct_event_48h(struct Channel* chptr)
+{
+  struct DestructEvent* new_event;
+
+  /* Ignore request when we already have a destruct request */
+  if (chptr->destruct_event)
+    return;
+
+  /* Create a new destruct event and add it at the top of the list. */
+  new_event = (struct DestructEvent*)MyMalloc(sizeof(struct DestructEvent));
+  new_event->expires = TStime() + 172800;      /* 48 hours from now */
+  new_event->next_event = NULL;
+  new_event->prev_event = days_list_top;
+  new_event->chptr = chptr;
+
+  if (days_list_top)
+    days_list_top->next_event = new_event;
+  days_list_top = new_event;
+  if (!days_list_bottom)
+    days_list_bottom = new_event;
+
+  chptr->destruct_event = new_event;
+}
+
+/** Unlink a destruction event for a channel.
+ * @param[in] chptr Channel that is being destroyed early.
+ */
+void remove_destruct_event(struct Channel* chptr)
+{
+  struct DestructEvent* event = chptr->destruct_event;
+
+  assert(event != NULL);
+
+  /* unlink event */
+  if (event->prev_event)
+    event->prev_event->next_event = event->next_event;
+  if (event->next_event)
+    event->next_event->prev_event = event->prev_event;
+
+  /* correct top and bottom pointers */
+  if (days_list_top == event)
+    days_list_top = event->prev_event;
+  if (minute_list_top == event)
+    minute_list_top = event->prev_event;
+  if (days_list_bottom == event)
+    days_list_bottom = event->next_event;
+  if (minute_list_bottom == event)
+    minute_list_bottom = event->next_event;
+
+  /* Free memory */
+  MyFree(event);
+
+  chptr->destruct_event = NULL;
+}
+
+/** Execute expired channel destruction events.
+ * @param[in] ev Expired timer event (ignored).
+ */
+void exec_expired_destruct_events(struct Event* ev)
+{
+  int i = 0;
+  struct DestructEvent** list_bottom;
+  for(list_bottom = &minute_list_bottom; i < 2; ++i, list_bottom = &days_list_bottom)
+  {
+    while (*list_bottom && TStime() >= (*list_bottom)->expires)
+    {
+      struct Channel* chptr = (*list_bottom)->chptr;
+      /* Send DESTRUCT message */
+      sendcmdto_serv_butone(&me, CMD_DESTRUCT, 0, "%s %Tu", chptr->chname, chptr->creationtime);
+      remove_destruct_event(chptr);
+      destruct_channel(chptr);
+    }
+  }
+}
+
diff --git a/ircd/engine_devpoll.c b/ircd/engine_devpoll.c
new file mode 100644 (file)
index 0000000..2360ec6
--- /dev/null
@@ -0,0 +1,450 @@
+/*
+ * IRC - Internet Relay Chat, ircd/engine_devpoll.c
+ * Copyright (C) 2001 Kevin L. Mitchell <klmitch@mit.edu>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+/** @file
+ * @brief Solaris /dev/poll event engine.
+ * @version $Id: engine_devpoll.c 1593 2005-12-30 13:28:42Z entrope $
+ */
+#include "config.h"
+
+#include "ircd_events.h"
+
+#include "ircd.h"
+#include "ircd_alloc.h"
+#include "ircd_features.h"
+#include "ircd_log.h"
+#include "s_debug.h"
+
+/* #include <assert.h> -- Now using assert in ircd_log.h */
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/devpoll.h>
+#include <sys/poll.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#define DEVPOLL_ERROR_THRESHOLD        20      /**< after 20 devpoll errors, restart */
+#define ERROR_EXPIRE_TIME      3600    /**< expire errors after an hour */
+
+/* Figure out what bits to set for read */
+#if defined(POLLMSG) && defined(POLLIN) && defined(POLLRDNORM)
+#  define POLLREADFLAGS (POLLMSG|POLLIN|POLLRDNORM)
+#elif defined(POLLIN) && defined(POLLRDNORM)
+#  define POLLREADFLAGS (POLLIN|POLLRDNORM)
+#elif defined(POLLIN)
+#  define POLLREADFLAGS POLLIN
+#elif defined(POLLRDNORM)
+#  define POLLREADFLAGS POLLRDNORM
+#endif
+
+/* Figure out what bits to set for write */
+#if defined(POLLOUT) && defined(POLLWRNORM)
+#  define POLLWRITEFLAGS (POLLOUT|POLLWRNORM)
+#elif defined(POLLOUT)
+#  define POLLWRITEFLAGS POLLOUT
+#elif defined(POLLWRNORM)
+#  define POLLWRITEFLAGS POLLWRNORM
+#endif
+
+/** Array of active Socket structures, indexed by file descriptor. */
+static struct Socket** sockList;
+/** Maximum file descriptor supported, plus one. */
+static int devpoll_max;
+/** File descriptor for /dev/poll device. */
+static int devpoll_fd;
+
+/** Number of recent errors from /dev/poll. */
+static int errors = 0;
+/** Periodic timer to forget errors. */
+static struct Timer clear_error;
+
+/** Decrement the error count (once per hour).
+ * @param[in] ev Expired timer event (ignored).
+ */
+static void
+error_clear(struct Event* ev)
+{
+  if (!--errors) /* remove timer when error count reaches 0 */
+    timer_del(ev_timer(ev));
+}
+
+/** Initialize the /dev/poll engine.
+ * @param[in] max_sockets Maximum number of file descriptors to support.
+ * @return Non-zero on success, or zero on failure.
+ */
+static int
+engine_init(int max_sockets)
+{
+  int i;
+
+  if ((devpoll_fd = open("/dev/poll", O_RDWR)) < 0) {
+    log_write(LS_SYSTEM, L_WARNING, 0,
+             "/dev/poll engine cannot open device: %m");
+    return 0; /* engine cannot be initialized; defer */
+  }
+
+  /* allocate necessary memory */
+  sockList = (struct Socket**) MyMalloc(sizeof(struct Socket*) * max_sockets);
+
+  /* initialize the data */
+  for (i = 0; i < max_sockets; i++)
+    sockList[i] = 0;
+
+  devpoll_max = max_sockets; /* number of sockets allocated */
+
+  return 1;
+}
+
+/** Figure out what events go with a given state.
+ * @param[in] state %Socket state to consider.
+ * @param[in] events User-specified preferred event set.
+ * @return Actual set of preferred events.
+ */
+static unsigned int
+state_to_events(enum SocketState state, unsigned int events)
+{
+  switch (state) {
+  case SS_CONNECTING: /* connecting socket */
+    return SOCK_EVENT_WRITABLE;
+    break;
+
+  case SS_LISTENING: /* listening socket */
+  case SS_NOTSOCK: /* our signal socket */
+    return SOCK_EVENT_READABLE;
+    break;
+
+  case SS_CONNECTED: case SS_DATAGRAM: case SS_CONNECTDG:
+    return events; /* ordinary socket */
+    break;
+  }
+
+  /*NOTREACHED*/
+  return 0;
+}
+
+/** Set the desired events for a socket.
+ * @param[in,out] sock Socket to operate on.
+ * @param[in] events User-specified preferred event set.
+ */
+static void
+set_events(struct Socket* sock, unsigned int events)
+{
+  struct pollfd pfd;
+
+  pfd.fd = s_fd(sock);
+
+  if (s_ed_int(sock)) { /* is one in /dev/poll already? */
+    pfd.events = POLLREMOVE; /* First, remove old pollfd */
+
+    Debug((DEBUG_ENGINE, "devpoll: Removing old entry for socket %d [%p]",
+          s_fd(sock), sock));
+
+    if (write(devpoll_fd, &pfd, sizeof(pfd)) != sizeof(pfd)) {
+      event_generate(ET_ERROR, sock, errno); /* report error */
+      return;
+    }
+
+    s_ed_int(sock) = 0; /* mark that it's gone */
+  }
+
+  if (!(events & SOCK_EVENT_MASK)) /* no events, so stop here */
+    return;
+
+  pfd.events = 0; /* Now, set up new pollfd... */
+  if (events & SOCK_EVENT_READABLE)
+    pfd.events |= POLLREADFLAGS; /* look for readable conditions */
+  if (events & SOCK_EVENT_WRITABLE)
+    pfd.events |= POLLWRITEFLAGS; /* look for writable conditions */
+
+  Debug((DEBUG_ENGINE, "devpoll: Registering interest on %d [%p] (state %s, "
+        "mask [%s])", s_fd(sock), sock, state_to_name(s_state(sock)),
+        sock_flags(s_events(sock))));
+
+  if (write(devpoll_fd, &pfd, sizeof(pfd)) != sizeof(pfd)) {
+    event_generate(ET_ERROR, sock, errno); /* report error */
+    return;
+  }
+
+  s_ed_int(sock) = 1; /* mark that we've added a pollfd */
+}
+
+/** Add a socket to the event engine.
+ * @param[in] sock Socket to add to engine.
+ * @return Non-zero on success, or zero on error.
+ */
+static int
+engine_add(struct Socket* sock)
+{
+  assert(0 != sock);
+  assert(0 == sockList[s_fd(sock)]);
+
+  /* bounds-check... */
+  if (s_fd(sock) >= devpoll_max) {
+    log_write(LS_SYSTEM, L_ERROR, 0,
+             "Attempt to add socket %d (> %d) to event engine", s_fd(sock),
+             devpoll_max);
+    return 0;
+  }
+
+  sockList[s_fd(sock)] = sock; /* add to list */
+
+  Debug((DEBUG_ENGINE, "devpoll: Adding socket %d [%p], state %s, to engine",
+        s_fd(sock), sock, state_to_name(s_state(sock))));
+
+  /* set the correct events */
+  set_events(sock, state_to_events(s_state(sock), s_events(sock)));
+
+  return 1; /* success */
+}
+
+/** Handle state transition for a socket.
+ * @param[in] sock Socket changing state.
+ * @param[in] new_state New state for socket.
+ */
+static void
+engine_state(struct Socket* sock, enum SocketState new_state)
+{
+  assert(0 != sock);
+  assert(sock == sockList[s_fd(sock)]);
+
+  Debug((DEBUG_ENGINE, "devpoll: Changing state for socket %p to %s", sock,
+        state_to_name(new_state)));
+
+  /* set the correct events */
+  set_events(sock, state_to_events(new_state, s_events(sock)));
+}
+
+/** Handle change to preferred socket events.
+ * @param[in] sock Socket getting new interest list.
+ * @param[in] new_events New set of interesting events for socket.
+ */
+static void
+engine_events(struct Socket* sock, unsigned int new_events)
+{
+  assert(0 != sock);
+  assert(sock == sockList[s_fd(sock)]);
+
+  Debug((DEBUG_ENGINE, "devpoll: Changing event mask for socket %p to [%s]",
+        sock, sock_flags(new_events)));
+
+  /* set the correct events */
+  set_events(sock, state_to_events(s_state(sock), new_events));
+}
+
+/** Remove a socket from the event engine.
+ * @param[in] sock Socket being destroyed.
+ */
+static void
+engine_delete(struct Socket* sock)
+{
+  assert(0 != sock);
+  assert(sock == sockList[s_fd(sock)]);
+
+  Debug((DEBUG_ENGINE, "devpoll: Deleting socket %d [%p], state %s",
+        s_fd(sock), sock, state_to_name(s_state(sock))));
+
+  set_events(sock, 0); /* get rid of the socket */
+
+  sockList[s_fd(sock)] = 0; /* zero the socket list entry */
+}
+
+/** Run engine event loop.
+ * @param[in] gen Lists of generators of various types.
+ */
+static void
+engine_loop(struct Generators* gen)
+{
+  struct dvpoll dopoll;
+  struct pollfd *polls;
+  int polls_count;
+  struct Socket* sock;
+  int nfds;
+  int i;
+  int errcode;
+  size_t codesize;
+
+  if ((polls_count = feature_int(FEAT_POLLS_PER_LOOP)) < 20)
+    polls_count = 20;
+  polls = (struct pollfd *)MyMalloc(sizeof(struct pollfd) * polls_count);
+
+  while (running) {
+    if ((i = feature_int(FEAT_POLLS_PER_LOOP)) >= 20 && i != polls_count) {
+      polls = (struct pollfd *)MyRealloc(polls, sizeof(struct pollfd) * i);
+      polls_count = i;
+    }
+
+    dopoll.dp_fds = polls; /* set up the struct dvpoll */
+    dopoll.dp_nfds = polls_count;
+
+    /* calculate the proper timeout */
+    dopoll.dp_timeout = timer_next(gen) ?
+      (timer_next(gen) - CurrentTime) * 1000 : -1;
+
+    Debug((DEBUG_INFO, "devpoll: delay: %Tu (%Tu) %d", timer_next(gen),
+          CurrentTime, dopoll.dp_timeout));
+
+    /* check for active files */
+    nfds = ioctl(devpoll_fd, DP_POLL, &dopoll);
+
+    CurrentTime = time(0); /* set current time... */
+
+    if (nfds < 0) {
+      if (errno != EINTR) { /* ignore interrupts */
+       /* Log the poll error */
+       log_write(LS_SOCKET, L_ERROR, 0, "ioctl(DP_POLL) error: %m");
+       if (!errors++)
+         timer_add(timer_init(&clear_error), error_clear, 0, TT_PERIODIC,
+                   ERROR_EXPIRE_TIME);
+       else if (errors > DEVPOLL_ERROR_THRESHOLD) /* too many errors... */
+         server_restart("too many /dev/poll errors");
+      }
+      /* old code did a sleep(1) here; with usage these days,
+       * that may be too expensive
+       */
+      continue;
+    }
+
+    for (i = 0; i < nfds; i++) {
+      assert(-1 < polls[i].fd);
+
+      sock = sockList[polls[i].fd];
+      if (!sock) /* slots may become empty while processing events */
+       continue;
+
+      assert(s_fd(sock) == polls[i].fd);
+
+      gen_ref_inc(sock); /* can't have it going away on us */
+
+      Debug((DEBUG_ENGINE, "devpoll: Checking socket %p (fd %d) state %s, "
+            "events %s", sock, s_fd(sock), state_to_name(s_state(sock)),
+            sock_flags(s_events(sock))));
+
+      if (s_state(sock) != SS_NOTSOCK) {
+       errcode = 0; /* check for errors on socket */
+       codesize = sizeof(errcode);
+       if (getsockopt(s_fd(sock), SOL_SOCKET, SO_ERROR, &errcode,
+                      &codesize) < 0)
+         errcode = errno; /* work around Solaris implementation */
+
+       if (errcode) { /* an error occurred; generate an event */
+         Debug((DEBUG_ENGINE, "devpoll: Error %d on fd %d, socket %p",
+                errcode, s_fd(sock), sock));
+         event_generate(ET_ERROR, sock, errcode);
+         gen_ref_dec(sock); /* careful not to leak reference counts */
+         continue;
+       }
+      }
+
+      assert(!(polls[i].revents & POLLERR));
+
+#ifdef POLLHUP
+      if (polls[i].revents & POLLHUP) { /* hang-up on socket */
+       Debug((DEBUG_ENGINE, "devpoll: EOF from client (POLLHUP)"));
+       event_generate(ET_EOF, sock, 0);
+       nfds--;
+       continue;
+      }
+#endif /* POLLHUP */
+
+      switch (s_state(sock)) {
+      case SS_CONNECTING:
+       if (polls[i].revents & POLLWRITEFLAGS) { /* connection completed */
+         Debug((DEBUG_ENGINE, "devpoll: Connection completed"));
+         event_generate(ET_CONNECT, sock, 0);
+       }
+       break;
+
+      case SS_LISTENING:
+       if (polls[i].revents & POLLREADFLAGS) { /* connect. to be accept. */
+         Debug((DEBUG_ENGINE, "devpoll: Ready for accept"));
+         event_generate(ET_ACCEPT, sock, 0);
+       }
+       break;
+
+      case SS_NOTSOCK:
+       if (polls[i].revents & POLLREADFLAGS) { /* data on socket */
+         /* can't peek; it's not a socket */
+         Debug((DEBUG_ENGINE, "devpoll: non-socket readable"));
+         event_generate(ET_READ, sock, 0);
+       }
+       break;
+
+      case SS_CONNECTED:
+       if (polls[i].revents & POLLREADFLAGS) { /* data on socket */
+         char c;
+
+         switch (recv(s_fd(sock), &c, 1, MSG_PEEK)) { /* check EOF */
+         case -1: /* error occurred?!? */
+           if (errno == EAGAIN) {
+             Debug((DEBUG_ENGINE, "devpoll: Resource temporarily "
+                    "unavailable?"));
+             continue;
+           }
+           Debug((DEBUG_ENGINE, "devpoll: Uncaught error!"));
+           event_generate(ET_ERROR, sock, errno);
+           break;
+
+         case 0: /* EOF from client */
+           Debug((DEBUG_ENGINE, "devpoll: EOF from client"));
+           event_generate(ET_EOF, sock, 0);
+           break;
+
+         default: /* some data can be read */
+           Debug((DEBUG_ENGINE, "devpoll: Data to be read"));
+           event_generate(ET_READ, sock, 0);
+           break;
+         }
+       }
+       if (polls[i].revents & POLLWRITEFLAGS) { /* socket writable */
+         Debug((DEBUG_ENGINE, "devpoll: Data can be written"));
+         event_generate(ET_WRITE, sock, 0);
+       }
+       break;
+
+      case SS_DATAGRAM: case SS_CONNECTDG:
+       if (polls[i].revents & POLLREADFLAGS) { /* socket readable */
+         Debug((DEBUG_ENGINE, "devpoll: Datagram to be read"));
+         event_generate(ET_READ, sock, 0);
+       }
+       if (polls[i].revents & POLLWRITEFLAGS) { /* socket writable */
+         Debug((DEBUG_ENGINE, "devpoll: Datagram can be written"));
+         event_generate(ET_WRITE, sock, 0);
+       }
+       break;
+      }
+
+      gen_ref_dec(sock); /* we're done with it */
+    }
+
+    timer_run(); /* execute any pending timers */
+  }
+}
+
+/** Descriptor for /dev/poll event engine. */
+struct Engine engine_devpoll = {
+  "/dev/poll",         /* Engine name */
+  engine_init,         /* Engine initialization function */
+  0,                   /* Engine signal registration function */
+  engine_add,          /* Engine socket registration function */
+  engine_state,                /* Engine socket state change function */
+  engine_events,       /* Engine socket events mask function */
+  engine_delete,       /* Engine socket deletion function */
+  engine_loop          /* Core engine event loop */
+};
diff --git a/ircd/engine_epoll.c b/ircd/engine_epoll.c
new file mode 100644 (file)
index 0000000..6793a5e
--- /dev/null
@@ -0,0 +1,350 @@
+/*
+ * IRC - Internet Relay Chat, ircd/engine_epoll.c
+ * Copyright (C) 2003 Michael Poole <mdpoole@troilus.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+/** @file
+ * @brief Linux epoll_*() event engine.
+ * @version $Id: engine_epoll.c 1463 2005-08-25 01:26:46Z entrope $
+ */
+#include "config.h"
+
+#include "ircd.h"
+#include "ircd_events.h"
+#include "ircd_alloc.h"
+#include "ircd_features.h"
+#include "ircd_log.h"
+#include "s_debug.h"
+
+/* #include <assert.h> -- Now using assert in ircd_log.h */
+#include <errno.h>
+#include <sys/types.h>
+#ifdef HAVE_STDINT_H
+#include <stdint.h> /* bah */
+#endif
+#include <string.h>
+#include <sys/epoll.h>
+#include <sys/socket.h>
+#include <time.h>
+#include <linux/unistd.h>
+
+/* The GNU C library may have a valid header but stub implementations
+ * of the epoll system calls.  If so, provide our own. */
+#if defined(__stub_epoll_create) || defined(__stub___epoll_create) || defined(EPOLL_NEED_BODY)
+
+/* Oh, did we mention that some glibc releases do not even define the
+ * syscall numbers? */
+#if !defined(__NR_epoll_create)
+#if defined(__ia64__)
+#define __NR_epoll_create 1243
+#define __NR_epoll_ctl 1244
+#define __NR_epoll_wait 1245
+#elif defined(__x86_64__)
+#define __NR_epoll_create 214
+#define __NR_epoll_ctl 233
+#define __NR_epoll_wait 232
+#elif defined(__sparc64__) || defined(__sparc__)
+#define __NR_epoll_create 193
+#define __NR_epoll_ctl 194
+#define __NR_epoll_wait 195
+#elif defined(__s390__) || defined(__m68k__)
+#define __NR_epoll_create 249
+#define __NR_epoll_ctl 250
+#define __NR_epoll_wait 251
+#elif defined(__ppc64__) || defined(__ppc__)
+#define __NR_epoll_create 236
+#define __NR_epoll_ctl 237
+#define __NR_epoll_wait 238
+#elif defined(__parisc__) || defined(__arm26__) || defined(__arm__)
+#define __NR_epoll_create 224
+#define __NR_epoll_ctl 225
+#define __NR_epoll_wait 226
+#elif defined(__alpha__)
+#define __NR_epoll_create 407
+#define __NR_epoll_ctl 408
+#define __NR_epoll_wait 409
+#elif defined(__sh64__)
+#define __NR_epoll_create 282
+#define __NR_epoll_ctl 283
+#define __NR_epoll_wait 284
+#elif defined(__i386__) || defined(__sh__) || defined(__m32r__) || defined(__h8300__) || defined(__frv__)
+#define __NR_epoll_create 254
+#define __NR_epoll_ctl 255
+#define __NR_epoll_wait 256
+#else /* cpu types */
+#error No system call numbers defined for epoll family.
+#endif /* cpu types */
+#endif /* !defined(__NR_epoll_create) */
+
+_syscall1(int, epoll_create, int, size)
+_syscall4(int, epoll_ctl, int, epfd, int, op, int, fd, struct epoll_event *, event)
+_syscall4(int, epoll_wait, int, epfd, struct epoll_event *, pevents, int, maxevents, int, timeout)
+
+#endif /* epoll_create defined as stub */
+
+#define EPOLL_ERROR_THRESHOLD 20   /**< after 20 epoll errors, restart */
+#define ERROR_EXPIRE_TIME     3600 /**< expire errors after an hour */
+
+/** File descriptor for epoll pseudo-file. */
+static int epoll_fd;
+/** Number of recent epoll errors. */
+static int errors;
+/** Periodic timer to forget errors. */
+static struct Timer clear_error;
+
+/** Decrement the error count (once per hour).
+ * @param[in] ev Expired timer event (ignored).
+ */
+static void
+error_clear(struct Event *ev)
+{
+  if (!--errors)
+    timer_del(ev_timer(ev));
+}
+
+/** Initialize the epoll engine.
+ * @param[in] max_sockets Maximum number of file descriptors to support.
+ * @return Non-zero on success, or zero on failure.
+ */
+static int
+engine_init(int max_sockets)
+{
+  if ((epoll_fd = epoll_create(max_sockets)) < 0) {
+    log_write(LS_SYSTEM, L_WARNING, 0,
+              "epoll() engine cannot initialize: %m");
+    return 0;
+  }
+  return 1;
+}
+
+/** Set events for a particular socket.
+ * @param[in] sock Socket to calculate events for.
+ * @param[in] state Current socket state.
+ * @param[in] events User-specified event interest list.
+ * @param[out] evt epoll event structure for socket.
+ */
+static void
+set_events(struct Socket *sock, enum SocketState state, unsigned int events, struct epoll_event *evt)
+{
+  assert(0 != sock);
+  assert(0 <= s_fd(sock));
+  memset(evt, 0, sizeof(*evt));
+
+  evt->data.ptr = sock;
+
+  switch (state) {
+  case SS_CONNECTING:
+    evt->events = EPOLLOUT;
+    break;
+
+  case SS_LISTENING:
+  case SS_NOTSOCK:
+    evt->events = EPOLLIN;
+    break;
+
+  case SS_CONNECTED:
+  case SS_DATAGRAM:
+  case SS_CONNECTDG:
+    switch (events & SOCK_EVENT_MASK) {
+    case 0:
+      evt->events = 0;
+      break;
+    case SOCK_EVENT_READABLE:
+      evt->events = EPOLLIN;
+      break;
+    case SOCK_EVENT_WRITABLE:
+      evt->events = EPOLLOUT;
+      break;
+    case SOCK_EVENT_READABLE|SOCK_EVENT_WRITABLE:
+      evt->events = EPOLLIN|EPOLLOUT;
+      break;
+    }
+    break;
+  }
+}
+
+/** Add a socket to the event engine.
+ * @param[in] sock Socket to add to engine.
+ * @return Non-zero on success, or zero on error.
+ */
+static int
+engine_add(struct Socket *sock)
+{
+  struct epoll_event evt;
+
+  assert(0 != sock);
+  Debug((DEBUG_ENGINE, "epoll: Adding socket %d [%p], state %s, to engine",
+         s_fd(sock), sock, state_to_name(s_state(sock))));
+  set_events(sock, s_state(sock), s_events(sock), &evt);
+  if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, s_fd(sock), &evt) < 0) {
+    /* epoll mysteriously occasionally returns errno-17 here if the
+     * client uses OpenSSL. Seems to be an epoll bug because other
+     * polling mechanism don't show this behaviour.
+     * We just ignore errno 17 here.
+     * --gix
+     */
+    if(errno == 17) return 1;
+    event_generate(ET_ERROR, sock, errno);
+    return 0;
+  }
+  return 1;
+}
+
+/** Handle state transition for a socket.
+ * @param[in] sock Socket changing state.
+ * @param[in] new_state New state for socket.
+ */
+static void
+engine_set_state(struct Socket *sock, enum SocketState new_state)
+{
+  struct epoll_event evt;
+
+  assert(0 != sock);
+  Debug((DEBUG_ENGINE, "epoll: Changing state for socket %p to %s",
+         sock, state_to_name(new_state)));
+  set_events(sock, new_state, s_events(sock), &evt);
+  if (epoll_ctl(epoll_fd, EPOLL_CTL_MOD, s_fd(sock), &evt) < 0)
+    event_generate(ET_ERROR, sock, errno);
+}
+
+/** Handle change to preferred socket events.
+ * @param[in] sock Socket getting new interest list.
+ * @param[in] new_events New set of interesting events for socket.
+ */
+static void
+engine_set_events(struct Socket *sock, unsigned new_events)
+{
+  struct epoll_event evt;
+
+  assert(0 != sock);
+  Debug((DEBUG_ENGINE, "epoll: Changing event mask for socket %p to [%s]",
+         sock, sock_flags(new_events)));
+  set_events(sock, s_state(sock), new_events, &evt);
+  if (epoll_ctl(epoll_fd, EPOLL_CTL_MOD, s_fd(sock), &evt) < 0)
+    event_generate(ET_ERROR, sock, errno);
+}
+
+/** Remove a socket from the event engine.
+ * @param[in] sock Socket being destroyed.
+ */
+static void
+engine_delete(struct Socket *sock)
+{
+  assert(0 != sock);
+  Debug((DEBUG_ENGINE, "epoll: Deleting socket %d [%p], state %s",
+        s_fd(sock), sock, state_to_name(s_state(sock))));
+  /* No action necessary; epoll removes the socket on close(). */
+}
+
+/** Run engine event loop.
+ * @param[in] gen Lists of generators of various types.
+ */
+static void
+engine_loop(struct Generators *gen)
+{
+  struct epoll_event *events;
+  struct Socket *sock;
+  socklen_t codesize;
+  int events_count, i, wait, nevs, errcode;
+
+  if ((events_count = feature_int(FEAT_POLLS_PER_LOOP)) < 20)
+    events_count = 20;
+  events = MyMalloc(sizeof(events[0]) * events_count);
+  while (running) {
+    if ((i = feature_int(FEAT_POLLS_PER_LOOP)) >= 20 && i != events_count) {
+      events = MyRealloc(events, sizeof(events[0]) * i);
+      events_count = i;
+    }
+
+    wait = timer_next(gen) ? (timer_next(gen) - CurrentTime) * 1000 : -1;
+    Debug((DEBUG_ENGINE, "epoll: delay: %d (%d) %d", timer_next(gen),
+           CurrentTime, wait));
+    nevs = epoll_wait(epoll_fd, events, events_count, wait);
+    CurrentTime = time(0);
+
+    if (nevs < 0) {
+      if (errno != EINTR) {
+        log_write(LS_SOCKET, L_ERROR, 0, "epoll() error: %m");
+        if (!errors++)
+          timer_add(timer_init(&clear_error), error_clear, 0, TT_PERIODIC,
+                    ERROR_EXPIRE_TIME);
+        else if (errors > EPOLL_ERROR_THRESHOLD)
+          server_restart("too many epoll errors");
+      }
+      continue;
+    }
+
+    for (i = 0; i < nevs; i++) {
+      if (!(sock = events[i].data.ptr))
+        continue;
+      gen_ref_inc(sock);
+      Debug((DEBUG_ENGINE,
+             "epoll: Checking socket %p (fd %d) state %s, events %s",
+             sock, s_fd(sock), state_to_name(s_state(sock)),
+             sock_flags(s_events(sock))));
+
+      if (events[i].events & EPOLLERR) {
+        errcode = 0;
+        codesize = sizeof(errcode);
+        if (getsockopt(s_fd(sock), SOL_SOCKET, SO_ERROR, &errcode,
+                       &codesize) < 0)
+          errcode = errno;
+        if (errcode) {
+          event_generate(ET_ERROR, sock, errcode);
+          gen_ref_dec(sock);
+          continue;
+        }
+      } else if (events[i].events & EPOLLHUP) {
+        event_generate(ET_EOF, sock, 0);
+      } else switch (s_state(sock)) {
+      case SS_CONNECTING:
+        if (events[i].events & EPOLLOUT) /* connection completed */
+          event_generate(ET_CONNECT, sock, 0);
+        break;
+
+      case SS_LISTENING:
+        if (events[i].events & EPOLLIN) /* incoming connection */
+          event_generate(ET_ACCEPT, sock, 0);
+        break;
+
+      case SS_NOTSOCK:
+      case SS_CONNECTED:
+      case SS_DATAGRAM:
+      case SS_CONNECTDG:
+        if (events[i].events & EPOLLIN)
+          event_generate(ET_READ, sock, 0);
+        if (events[i].events & EPOLLOUT)
+          event_generate(ET_WRITE, sock, 0);
+        break;
+      }
+      gen_ref_dec(sock);
+    }
+    timer_run();
+  }
+  MyFree(events);
+}
+
+/** Descriptor for epoll event engine. */
+struct Engine engine_epoll = {
+  "epoll()",
+  engine_init,
+  0,
+  engine_add,
+  engine_set_state,
+  engine_set_events,
+  engine_delete,
+  engine_loop
+};
diff --git a/ircd/engine_kqueue.c b/ircd/engine_kqueue.c
new file mode 100644 (file)
index 0000000..0365e6c
--- /dev/null
@@ -0,0 +1,452 @@
+/*
+ * IRC - Internet Relay Chat, ircd/engine_kqueue.c
+ * Copyright (C) 2001 Kevin L. Mitchell <klmitch@mit.edu>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+/** @file
+ * @brief FreeBSD kqueue()/kevent() event engine.
+ * @version $Id: engine_kqueue.c 1335 2005-03-23 00:25:16Z entrope $
+ */
+#include "config.h"
+
+#include "ircd_events.h"
+
+#include "ircd.h"
+#include "ircd_alloc.h"
+#include "ircd_features.h"
+#include "ircd_log.h"
+#include "s_debug.h"
+
+/* #include <assert.h> -- Now using assert in ircd_log.h */
+#include <errno.h>
+#include <signal.h>
+#include <sys/types.h>
+#include <sys/event.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <time.h>
+#include <unistd.h>
+
+#define KQUEUE_ERROR_THRESHOLD 20      /**< after 20 kqueue errors, restart */
+#define ERROR_EXPIRE_TIME      3600    /**< expire errors after an hour */
+
+/** Array of active Socket structures, indexed by file descriptor. */
+static struct Socket** sockList;
+/** Maximum file descriptor supported, plus one. */
+static int kqueue_max;
+/** File descriptor for kqueue pseudo-file. */
+static int kqueue_id;
+
+/** Number of recent errors from kqueue. */
+static int errors = 0;
+/** Periodic timer to forget errors. */
+static struct Timer clear_error;
+
+/** Decrement the error count (once per hour).
+ * @param[in] ev Expired timer event (ignored).
+ */
+static void
+error_clear(struct Event* ev)
+{
+  if (!--errors) /* remove timer when error count reaches 0 */
+    timer_del(ev_timer(ev));
+}
+
+/** Initialize the kqueue engine.
+ * @param[in] max_sockets Maximum number of file descriptors to support.
+ * @return Non-zero on success, or zero on failure.
+ */
+static int
+engine_init(int max_sockets)
+{
+  int i;
+
+  if ((kqueue_id = kqueue()) < 0) { /* initialize... */
+    log_write(LS_SYSTEM, L_WARNING, 0,
+             "kqueue() engine cannot initialize: %m");
+    return 0;
+  }
+
+  /* allocate necessary memory */
+  sockList = (struct Socket**) MyMalloc(sizeof(struct Socket*) * max_sockets);
+
+  /* initialize the data */
+  for (i = 0; i < max_sockets; i++)
+    sockList[i] = 0;
+
+  kqueue_max = max_sockets; /* number of sockets allocated */
+
+  return 1; /* success! */
+}
+
+/** Add a signal to the event engine.
+ * @param[in] sig Signal to add to engine.
+ */
+static void
+engine_signal(struct Signal* sig)
+{
+  struct kevent sigevent;
+  struct sigaction act;
+
+  assert(0 != signal);
+
+  Debug((DEBUG_ENGINE, "kqueue: Adding filter for signal %d [%p]",
+        sig_signal(sig), sig));
+
+  sigevent.ident = sig_signal(sig); /* set up the kqueue event */
+  sigevent.filter = EVFILT_SIGNAL; /* looking for signals... */
+  sigevent.flags = EV_ADD | EV_ENABLE; /* add and enable it */
+  sigevent.fflags = 0;
+  sigevent.data = 0;
+  sigevent.udata = sig; /* store our user data */
+
+  if (kevent(kqueue_id, &sigevent, 1, 0, 0, 0) < 0) { /* add event */
+    log_write(LS_SYSTEM, L_WARNING, 0, "Unable to trap signal %d",
+             sig_signal(sig));
+    return;
+  }
+
+  act.sa_handler = SIG_IGN; /* ignore the signal */
+  act.sa_flags = 0;
+  sigemptyset(&act.sa_mask);
+  sigaction(sig_signal(sig), &act, 0);
+}
+
+/** Figure out what events go with a given state.
+ * @param[in] state %Socket state to consider.
+ * @param[in] events User-specified preferred event set.
+ * @return Actual set of preferred events.
+ */
+static unsigned int
+state_to_events(enum SocketState state, unsigned int events)
+{
+  switch (state) {
+  case SS_CONNECTING: /* connecting socket */
+    return SOCK_EVENT_WRITABLE;
+    break;
+
+  case SS_LISTENING: /* listening socket */
+  case SS_NOTSOCK: /* our signal socket--just in case */
+    return SOCK_EVENT_READABLE;
+    break;
+
+  case SS_CONNECTED: case SS_DATAGRAM: case SS_CONNECTDG:
+    return events; /* ordinary socket */
+    break;
+  }
+
+  /*NOTREACHED*/
+  return 0;
+}
+
+/** Activate kqueue filters as appropriate.
+ * @param[in] sock Socket structure to operate on.
+ * @param[in] clear Set of interest events to clear from socket.
+ * @param[in] set Set of interest events to set on socket.
+ */
+static void
+set_or_clear(struct Socket* sock, unsigned int clear, unsigned int set)
+{
+  int i = 0;
+  struct kevent chglist[2];
+
+  assert(0 != sock);
+  assert(-1 < s_fd(sock));
+
+  if ((clear ^ set) & SOCK_EVENT_READABLE) { /* readable has changed */
+    chglist[i].ident = s_fd(sock); /* set up the change list */
+    chglist[i].filter = EVFILT_READ; /* readable filter */
+    chglist[i].flags = EV_ADD; /* adding it */
+    chglist[i].fflags = 0;
+    chglist[i].data = 0;
+    chglist[i].udata = 0; /* I love udata, but it can't really be used here */
+
+    if (set & SOCK_EVENT_READABLE) /* it's set */
+      chglist[i].flags |= EV_ENABLE;
+    else /* clear it */
+      chglist[i].flags |= EV_DISABLE;
+
+    i++; /* advance to next element */
+  }
+
+  if ((clear ^ set) & SOCK_EVENT_WRITABLE) { /* writable has changed */
+    chglist[i].ident = s_fd(sock); /* set up the change list */
+    chglist[i].filter = EVFILT_WRITE; /* writable filter */
+    chglist[i].flags = EV_ADD; /* adding it */
+    chglist[i].fflags = 0;
+    chglist[i].data = 0;
+    chglist[i].udata = 0;
+
+    if (set & SOCK_EVENT_WRITABLE) /* it's set */
+      chglist[i].flags |= EV_ENABLE;
+    else /* clear it */
+      chglist[i].flags |= EV_DISABLE;
+
+    i++; /* advance count... */
+  }
+
+  if (kevent(kqueue_id, chglist, i, 0, 0, 0) < 0 && errno != EBADF)
+    event_generate(ET_ERROR, sock, errno); /* report error */
+}
+
+/** Add a socket to the event engine.
+ * @param[in] sock Socket to add to engine.
+ * @return Non-zero on success, or zero on error.
+ */
+static int
+engine_add(struct Socket* sock)
+{
+  assert(0 != sock);
+  assert(0 == sockList[s_fd(sock)]);
+
+  /* bounds-check... */
+  if (sock->s_fd >= kqueue_max) {
+    log_write(LS_SYSTEM, L_ERROR, 0,
+             "Attempt to add socket %d (> %d) to event engine", s_fd(sock),
+             kqueue_max);
+    return 0;
+  }
+
+  sockList[s_fd(sock)] = sock; /* add to list */
+
+  Debug((DEBUG_ENGINE, "kqueue: Adding socket %d [%p], state %s, to engine",
+        s_fd(sock), sock, state_to_name(s_state(sock))));
+
+  /* Add socket to queue */
+  set_or_clear(sock, 0, state_to_events(s_state(sock), s_events(sock)));
+
+  return 1; /* success */
+}
+
+/** Handle state transition for a socket.
+ * @param[in] sock Socket changing state.
+ * @param[in] new_state New state for socket.
+ */
+static void
+engine_state(struct Socket* sock, enum SocketState new_state)
+{
+  assert(0 != sock);
+  assert(sock == sockList[s_fd(sock)]);
+
+  Debug((DEBUG_ENGINE, "kqueue: Changing state for socket %p to %s", sock,
+        state_to_name(new_state)));
+
+  /* set the correct events */
+  set_or_clear(sock,
+              state_to_events(s_state(sock), s_events(sock)), /* old state */
+              state_to_events(new_state, s_events(sock))); /* new state */
+
+}
+
+/** Handle change to preferred socket events.
+ * @param[in] sock Socket getting new interest list.
+ * @param[in] new_events New set of interesting events for socket.
+ */
+static void
+engine_events(struct Socket* sock, unsigned int new_events)
+{
+  assert(0 != sock);
+  assert(sock == sockList[s_fd(sock)]);
+
+  Debug((DEBUG_ENGINE, "kqueue: Changing event mask for socket %p to [%s]",
+        sock, sock_flags(new_events)));
+
+  /* set the correct events */
+  set_or_clear(sock,
+              state_to_events(s_state(sock), s_events(sock)), /* old events */
+              state_to_events(s_state(sock), new_events)); /* new events */
+}
+
+/** Remove a socket from the event engine.
+ * @param[in] sock Socket being destroyed.
+ */
+static void
+engine_delete(struct Socket* sock)
+{
+  struct kevent dellist[2];
+
+  assert(0 != sock);
+  assert(sock == sockList[s_fd(sock)]);
+
+  Debug((DEBUG_ENGINE, "kqueue: Deleting socket %d [%p], state %s",
+        s_fd(sock), sock, state_to_name(s_state(sock))));
+
+  dellist[0].ident = s_fd(sock); /* set up the delete list */
+  dellist[0].filter = EVFILT_READ; /* readable filter */
+  dellist[0].flags = EV_DELETE; /* delete it */
+  dellist[0].fflags = 0;
+  dellist[0].data = 0;
+  dellist[0].udata = 0;
+
+  dellist[1].ident = s_fd(sock);
+  dellist[1].filter = EVFILT_WRITE; /* writable filter */
+  dellist[1].flags = EV_DELETE; /* delete it */
+  dellist[1].fflags = 0;
+  dellist[1].data = 0;
+  dellist[1].udata = 0;
+
+  sockList[s_fd(sock)] = 0;
+}
+
+/** Run engine event loop.
+ * @param[in] gen Lists of generators of various types.
+ */
+static void
+engine_loop(struct Generators* gen)
+{
+  struct kevent *events;
+  int events_count;
+  struct Socket* sock;
+  struct timespec wait;
+  int nevs;
+  int i;
+  int errcode;
+  size_t codesize;
+
+  if ((events_count = feature_int(FEAT_POLLS_PER_LOOP)) < 20)
+    events_count = 20;
+  events = (struct kevent *)MyMalloc(sizeof(struct kevent) * events_count);
+
+  while (running) {
+    if ((i = feature_int(FEAT_POLLS_PER_LOOP)) >= 20 && i != events_count) {
+      events = (struct kevent *)MyRealloc(events, sizeof(struct kevent) * i);
+      events_count = i;
+    }
+
+    /* set up the sleep time */
+    wait.tv_sec = timer_next(gen) ? (timer_next(gen) - CurrentTime) : -1;
+    wait.tv_nsec = 0;
+
+    Debug((DEBUG_INFO, "kqueue: delay: %Tu (%Tu) %Tu", timer_next(gen),
+          CurrentTime, wait.tv_sec));
+
+    /* check for active events */
+    nevs = kevent(kqueue_id, 0, 0, events, events_count,
+                 wait.tv_sec < 0 ? 0 : &wait);
+
+    CurrentTime = time(0); /* set current time... */
+
+    if (nevs < 0) {
+      if (errno != EINTR) { /* ignore kevent interrupts */
+       /* Log the kqueue error */
+       log_write(LS_SOCKET, L_ERROR, 0, "kevent() error: %m");
+       if (!errors++)
+         timer_add(timer_init(&clear_error), error_clear, 0, TT_PERIODIC,
+                   ERROR_EXPIRE_TIME);
+       else if (errors > KQUEUE_ERROR_THRESHOLD) /* too many errors... */
+         server_restart("too many kevent errors");
+      }
+      /* old code did a sleep(1) here; with usage these days,
+       * that may be too expensive
+       */
+      continue;
+    }
+
+    for (i = 0; i < nevs; i++) {
+      if (events[i].filter == EVFILT_SIGNAL) {
+       /* it's a signal; deal appropriately */
+       event_generate(ET_SIGNAL, events[i].udata, events[i].ident);
+       continue; /* skip socket processing loop */
+      }
+
+      assert(events[i].filter == EVFILT_READ ||
+            events[i].filter == EVFILT_WRITE);
+
+      sock = sockList[events[i].ident];
+      if (!sock) /* slots may become empty while processing events */
+       continue;
+
+      assert(s_fd(sock) == events[i].ident);
+
+      gen_ref_inc(sock); /* can't have it going away on us */
+
+      Debug((DEBUG_ENGINE, "kqueue: Checking socket %p (fd %d) state %s, "
+            "events %s", sock, s_fd(sock), state_to_name(s_state(sock)),
+            sock_flags(s_events(sock))));
+
+      if (s_state(sock) != SS_NOTSOCK) {
+       errcode = 0; /* check for errors on socket */
+       codesize = sizeof(errcode);
+       if (getsockopt(s_fd(sock), SOL_SOCKET, SO_ERROR, &errcode,
+                      &codesize) < 0)
+         errcode = errno; /* work around Solaris implementation */
+
+       if (errcode) { /* an error occurred; generate an event */
+         Debug((DEBUG_ENGINE, "kqueue: Error %d on fd %d, socket %p", errcode,
+                s_fd(sock), sock));
+         event_generate(ET_ERROR, sock, errcode);
+         gen_ref_dec(sock); /* careful not to leak reference counts */
+         continue;
+       }
+      }
+
+      switch (s_state(sock)) {
+      case SS_CONNECTING:
+       if (events[i].filter == EVFILT_WRITE) { /* connection completed */
+         Debug((DEBUG_ENGINE, "kqueue: Connection completed"));
+         event_generate(ET_CONNECT, sock, 0);
+       }
+       break;
+
+      case SS_LISTENING:
+       if (events[i].filter == EVFILT_READ) { /* connect. to be accept. */
+         Debug((DEBUG_ENGINE, "kqueue: Ready for accept"));
+         event_generate(ET_ACCEPT, sock, 0);
+       }
+       break;
+
+      case SS_NOTSOCK: /* doing nothing socket-specific */
+      case SS_CONNECTED:
+       if (events[i].filter == EVFILT_READ) { /* data on socket */
+         Debug((DEBUG_ENGINE, "kqueue: EOF or data to be read"));
+         event_generate(events[i].flags & EV_EOF ? ET_EOF : ET_READ, sock, 0);
+       }
+       if (events[i].filter == EVFILT_WRITE) { /* socket writable */
+         Debug((DEBUG_ENGINE, "kqueue: Data can be written"));
+         event_generate(ET_WRITE, sock, 0);
+       }
+       break;
+
+      case SS_DATAGRAM: case SS_CONNECTDG:
+       if (events[i].filter == EVFILT_READ) { /* socket readable */
+         Debug((DEBUG_ENGINE, "kqueue: Datagram to be read"));
+         event_generate(ET_READ, sock, 0);
+       }
+       if (events[i].filter == EVFILT_WRITE) { /* socket writable */
+         Debug((DEBUG_ENGINE, "kqueue: Datagram can be written"));
+         event_generate(ET_WRITE, sock, 0);
+       }
+       break;
+      }
+
+      gen_ref_dec(sock); /* we're done with it */
+    }
+
+    timer_run(); /* execute any pending timers */
+  }
+}
+
+/** Descriptor for kqueue() event engine. */
+struct Engine engine_kqueue = {
+  "kqueue()",          /* Engine name */
+  engine_init,         /* Engine initialization function */
+  engine_signal,       /* Engine signal registration function */
+  engine_add,          /* Engine socket registration function */
+  engine_state,                /* Engine socket state change function */
+  engine_events,       /* Engine socket events mask function */
+  engine_delete,       /* Engine socket deletion function */
+  engine_loop          /* Core engine event loop */
+};
diff --git a/ircd/engine_poll.c b/ircd/engine_poll.c
new file mode 100644 (file)
index 0000000..41ab939
--- /dev/null
@@ -0,0 +1,439 @@
+/*
+ * IRC - Internet Relay Chat, ircd/engine_poll.c
+ * Copyright (C) 2001 Kevin L. Mitchell <klmitch@mit.edu>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+/** @file
+ * @brief POSIX poll() event engine.
+ * @version $Id: engine_poll.c 1271 2004-12-11 05:14:07Z klmitch $
+ */
+#include "config.h"
+
+#include "ircd_events.h"
+
+#include "ircd.h"
+#include "ircd_alloc.h"
+#include "ircd_log.h"
+#include "s_debug.h"
+
+/* #include <assert.h> -- Now using assert in ircd_log.h */
+#include <errno.h>
+#include <sys/poll.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <time.h>
+#include <unistd.h>
+
+#define POLL_ERROR_THRESHOLD   20      /**< after 20 poll errors, restart */
+#define ERROR_EXPIRE_TIME      3600    /**< expire errors after an hour */
+
+/* Figure out what bits to set for read */
+#if defined(POLLMSG) && defined(POLLIN) && defined(POLLRDNORM)
+#  define POLLREADFLAGS (POLLMSG|POLLIN|POLLRDNORM)
+#elif defined(POLLIN) && defined(POLLRDNORM)
+#  define POLLREADFLAGS (POLLIN|POLLRDNORM)
+#elif defined(POLLIN)
+#  define POLLREADFLAGS POLLIN
+#elif defined(POLLRDNORM)
+#  define POLLREADFLAGS POLLRDNORM
+#endif
+
+/* Figure out what bits to set for write */
+#if defined(POLLOUT) && defined(POLLWRNORM)
+#  define POLLWRITEFLAGS (POLLOUT|POLLWRNORM)
+#elif defined(POLLOUT)
+#  define POLLWRITEFLAGS POLLOUT
+#elif defined(POLLWRNORM)
+#  define POLLWRITEFLAGS POLLWRNORM
+#endif
+
+/** Array of active Socket structures, indexed by file descriptor. */
+static struct Socket** sockList;
+/** Array of poll() active elements. */
+static struct pollfd* pollfdList;
+/** Number of pollfd elements currently used. */
+static unsigned int poll_count;
+/** Maximum file descriptor supported, plus one. */
+static unsigned int poll_max;
+
+/** Number of recent errors from poll(). */
+static int errors = 0;
+/** Periodic timer to forget errors. */
+static struct Timer clear_error;
+
+/** Decrement the error count (once per hour).
+ * @param[in] ev Expired timer event (ignored).
+ */
+static void
+error_clear(struct Event* ev)
+{
+  if (!--errors) /* remove timer when error count reaches 0 */
+    timer_del(ev_timer(ev));
+}
+
+/** Initialize the poll() engine.
+ * @param[in] max_sockets Maximum number of file descriptors to support.
+ * @return Non-zero on success, or zero on failure.
+ */
+static int
+engine_init(int max_sockets)
+{
+  int i;
+
+  /* allocate necessary memory */
+  sockList = (struct Socket**) MyMalloc(sizeof(struct Socket*) * max_sockets);
+  pollfdList = (struct pollfd*) MyMalloc(sizeof(struct pollfd) * max_sockets);
+
+  /* initialize the data */
+  for (i = 0; i < max_sockets; i++) {
+    sockList[i] = 0;
+    pollfdList[i].fd = -1;
+    pollfdList[i].events = 0;
+    pollfdList[i].revents = 0;
+  }
+
+  poll_count = 0; /* nothing in set */
+  poll_max = max_sockets; /* number of sockets allocated */
+
+  return 1;
+}
+
+/** Figure out what events go with a given state.
+ * @param[in] state %Socket state to consider.
+ * @param[in] events User-specified preferred event set.
+ * @return Actual set of preferred events.
+ */
+static unsigned int
+state_to_events(enum SocketState state, unsigned int events)
+{
+  switch (state) {
+  case SS_CONNECTING: /* connecting socket */
+    return SOCK_EVENT_WRITABLE;
+    break;
+
+  case SS_LISTENING: /* listening socket */
+  case SS_NOTSOCK: /* our signal socket */
+    return SOCK_EVENT_READABLE;
+    break;
+
+  case SS_CONNECTED: case SS_DATAGRAM: case SS_CONNECTDG:
+    return events; /* ordinary socket */
+    break;
+  }
+
+  /*NOTREACHED*/
+  return 0;
+}
+
+/** Set interest events in a pollfd as appropriate.
+ * @param[in] idx Index of pollfd to operate on.
+ * @param[in] clear Set of interest events to clear from socket.
+ * @param[in] set Set of interest events to set on socket.
+ */
+static void
+set_or_clear(int idx, unsigned int clear, unsigned int set)
+{
+  if ((clear ^ set) & SOCK_EVENT_READABLE) { /* readable has changed */
+    if (set & SOCK_EVENT_READABLE) /* it's set */
+      pollfdList[idx].events |= POLLREADFLAGS;
+    else /* clear it */
+      pollfdList[idx].events &= ~POLLREADFLAGS;
+  }
+
+  if ((clear ^ set) & SOCK_EVENT_WRITABLE) { /* writable has changed */
+    if (set & SOCK_EVENT_WRITABLE) /* it's set */
+      pollfdList[idx].events |= POLLWRITEFLAGS;
+    else /* clear it */
+      pollfdList[idx].events &= ~POLLWRITEFLAGS;
+  }
+}
+
+/** Add a socket to the event engine.
+ * @param[in] sock Socket to add to engine.
+ * @return Non-zero on success, or zero on error.
+ */
+static int
+engine_add(struct Socket* sock)
+{
+  int i;
+
+  assert(0 != sock);
+
+  for (i = 0; sockList[i] && i < poll_count; i++) /* Find an empty slot */
+    ;
+
+  Debug((DEBUG_ENGINE, "poll: Looking at slot %d, contents %p", i,
+        sockList[i]));
+
+  if (i >= poll_count) { /* ok, need to allocate another off the list */
+    if (poll_count >= poll_max) { /* bounds-check... */
+      log_write(LS_SYSTEM, L_ERROR, 0,
+               "Attempt to add socket %d (> %d) to event engine", sock->s_fd,
+               poll_max);
+      return 0;
+    }
+
+    i = poll_count++;
+    Debug((DEBUG_ENGINE, "poll: Allocating a new slot: %d", i));
+  }
+
+  s_ed_int(sock) = i; /* set engine data */
+  sockList[i] = sock; /* enter socket into data structures */
+  pollfdList[i].fd = s_fd(sock);
+
+  Debug((DEBUG_ENGINE, "poll: Adding socket %d to engine on %d [%p], state %s",
+        s_fd(sock), s_ed_int(sock), sock, state_to_name(s_state(sock))));
+
+  /* set the appropriate bits */
+  set_or_clear(i, 0, state_to_events(s_state(sock), s_events(sock)));
+
+  return 1; /* success */
+}
+
+/** Handle state transition for a socket.
+ * @param[in] sock Socket changing state.
+ * @param[in] new_state New state for socket.
+ */
+static void
+engine_state(struct Socket* sock, enum SocketState new_state)
+{
+  assert(0 != sock);
+  assert(sock == sockList[s_ed_int(sock)]);
+  assert(s_fd(sock) == pollfdList[s_ed_int(sock)].fd);
+
+  Debug((DEBUG_ENGINE, "poll: Changing state for socket %p to %s", sock,
+        state_to_name(new_state)));
+
+  /* set the correct events */
+  set_or_clear(s_ed_int(sock),
+              state_to_events(s_state(sock), s_events(sock)), /* old state */
+              state_to_events(new_state, s_events(sock))); /* new state */
+}
+
+/** Handle change to preferred socket events.
+ * @param[in] sock Socket getting new interest list.
+ * @param[in] new_events New set of interesting events for socket.
+ */
+static void
+engine_events(struct Socket* sock, unsigned int new_events)
+{
+  assert(0 != sock);
+  assert(sock == sockList[s_ed_int(sock)]);
+  assert(s_fd(sock) == pollfdList[s_ed_int(sock)].fd);
+
+  Debug((DEBUG_ENGINE, "poll: Changing event mask for socket %p to [%s]", sock,
+        sock_flags(new_events)));
+
+  /* set the correct events */
+  set_or_clear(s_ed_int(sock),
+              state_to_events(s_state(sock), s_events(sock)), /* old events */
+              state_to_events(s_state(sock), new_events)); /* new events */
+}
+
+/** Remove a socket from the event engine.
+ * @param[in] sock Socket being destroyed.
+ */
+static void
+engine_delete(struct Socket* sock)
+{
+  assert(0 != sock);
+  assert(sock == sockList[s_ed_int(sock)]);
+  assert(s_fd(sock) == pollfdList[s_ed_int(sock)].fd);
+
+  Debug((DEBUG_ENGINE, "poll: Deleting socket %d (%d) [%p], state %s",
+        s_fd(sock), s_ed_int(sock), sock, state_to_name(s_state(sock))));
+
+  /* clear the events */
+  pollfdList[s_ed_int(sock)].fd = -1;
+  pollfdList[s_ed_int(sock)].events = 0;
+
+  /* zero the socket list entry */
+  sockList[s_ed_int(sock)] = 0;
+
+  /* update poll_count */
+  while (poll_count > 0 && sockList[poll_count - 1] == 0)
+    poll_count--;
+}
+
+/** Run engine event loop.
+ * @param[in] gen Lists of generators of various types.
+ */
+static void
+engine_loop(struct Generators* gen)
+{
+  int wait;
+  int nfds;
+  int i;
+  int errcode;
+  socklen_t codesize;
+  struct Socket *sock;
+
+  while (running) {
+    wait = timer_next(gen) ? (timer_next(gen) - CurrentTime) * 1000 : -1;
+
+    Debug((DEBUG_INFO, "poll: delay: %Tu (%Tu) %d", timer_next(gen),
+          CurrentTime, wait));
+
+    /* check for active files */
+    nfds = poll(pollfdList, poll_count, wait);
+
+    CurrentTime = time(0); /* set current time... */
+
+    if (nfds < 0) {
+      if (errno != EINTR) { /* ignore poll interrupts */
+       /* Log the poll error */
+       log_write(LS_SOCKET, L_ERROR, 0, "poll() error: %m");
+       if (!errors++)
+         timer_add(timer_init(&clear_error), error_clear, 0, TT_PERIODIC,
+                   ERROR_EXPIRE_TIME);
+       else if (errors > POLL_ERROR_THRESHOLD) /* too many errors... */
+         server_restart("too many poll errors");
+      }
+      /* old code did a sleep(1) here; with usage these days,
+       * that may be too expensive
+       */
+      continue;
+    }
+
+    for (i = 0; nfds && i < poll_count; i++) {
+      if (!(sock = sockList[i])) /* skip empty socket elements */
+       continue;
+
+      assert(s_fd(sock) == pollfdList[i].fd);
+
+      gen_ref_inc(sock); /* can't have it going away on us */
+
+      Debug((DEBUG_ENGINE, "poll: Checking socket %p (fd %d, index %d, "
+            "state %s, events %s", sock, s_fd(sock), i,
+            state_to_name(s_state(sock)), sock_flags(s_events(sock))));
+
+      if (s_state(sock) != SS_NOTSOCK) {
+       errcode = 0; /* check for errors on socket */
+       codesize = sizeof(errcode);
+       if (getsockopt(s_fd(sock), SOL_SOCKET, SO_ERROR, &errcode,
+                      &codesize) < 0)
+         errcode = errno; /* work around Solaris implementation */
+
+       if (errcode) { /* an error occurred; generate an event */
+         Debug((DEBUG_ENGINE, "poll: Error %d on fd %d (index %d), socket %p",
+                errcode, s_fd(sock), i, sock));
+         event_generate(ET_ERROR, sock, errcode);
+         gen_ref_dec(sock); /* careful not to leak ref counts */
+         nfds--;
+         continue;
+       }
+      }
+
+#ifdef POLLHUP
+      if (pollfdList[i].revents & POLLHUP) { /* hang-up on socket */
+       Debug((DEBUG_ENGINE, "poll: EOF from client (POLLHUP)"));
+       event_generate(ET_EOF, sock, 0);
+       nfds--;
+       continue;
+      }
+#endif /* POLLHUP */
+
+      switch (s_state(sock)) {
+      case SS_CONNECTING:
+       if (pollfdList[i].revents & POLLWRITEFLAGS) { /* connect completed */
+         Debug((DEBUG_ENGINE, "poll: Connection completed"));
+         event_generate(ET_CONNECT, sock, 0);
+         nfds--;
+       }
+       break;
+
+      case SS_LISTENING:
+       if (pollfdList[i].revents & POLLREADFLAGS) { /* ready for accept */
+         Debug((DEBUG_ENGINE, "poll: Ready for accept"));
+         event_generate(ET_ACCEPT, sock, 0);
+         nfds--;
+       }
+       break;
+
+      case SS_NOTSOCK:
+       if (pollfdList[i].revents & POLLREADFLAGS) { /* data on socket */
+         /* can't peek; it's not a socket */
+         Debug((DEBUG_ENGINE, "poll: non-socket readable"));
+         event_generate(ET_READ, sock, 0);
+         nfds--;
+       }
+       break;
+
+      case SS_CONNECTED:
+       if (pollfdList[i].revents & POLLREADFLAGS) { /* data on socket */
+         char c;
+
+         switch (recv(s_fd(sock), &c, 1, MSG_PEEK)) { /* check EOF */
+         case -1: /* error occurred?!? */
+           if (errno == EAGAIN) {
+             Debug((DEBUG_ENGINE, "poll: Resource temporarily unavailable?"));
+             continue;
+           }
+           Debug((DEBUG_ENGINE, "poll: Uncaught error!"));
+           event_generate(ET_ERROR, sock, errno);
+           break;
+
+         case 0: /* EOF from client */
+           Debug((DEBUG_ENGINE, "poll: EOF from client"));
+           event_generate(ET_EOF, sock, 0);
+           break;
+
+         default: /* some data can be read */
+           Debug((DEBUG_ENGINE, "poll: Data to be read"));
+           event_generate(ET_READ, sock, 0);
+           break;
+         }
+       }
+       if (pollfdList[i].revents & POLLWRITEFLAGS) { /* socket writable */
+         Debug((DEBUG_ENGINE, "poll: Data can be written"));
+         event_generate(ET_WRITE, sock, 0);
+       }
+       if (pollfdList[i].revents & (POLLREADFLAGS | POLLWRITEFLAGS))
+         nfds--;
+       break;
+
+      case SS_DATAGRAM: case SS_CONNECTDG:
+       if (pollfdList[i].revents & POLLREADFLAGS) { /* socket readable */
+         Debug((DEBUG_ENGINE, "poll: Datagram to be read"));
+         event_generate(ET_READ, sock, 0);
+       }
+       if (pollfdList[i].revents & POLLWRITEFLAGS) { /* socket writable */
+         Debug((DEBUG_ENGINE, "poll: Datagram can be written"));
+         event_generate(ET_WRITE, sock, 0);
+       }
+       if (pollfdList[i].revents & (POLLREADFLAGS | POLLWRITEFLAGS))
+         nfds--;
+       break;
+      }
+
+      gen_ref_dec(sock); /* we're done with it */
+    }
+
+    timer_run(); /* execute any pending timers */
+  }
+}
+
+/** Descriptor for poll() event engine. */
+struct Engine engine_poll = {
+  "poll()",            /* Engine name */
+  engine_init,         /* Engine initialization function */
+  0,                   /* Engine signal registration function */
+  engine_add,          /* Engine socket registration function */
+  engine_state,                /* Engine socket state change function */
+  engine_events,       /* Engine socket events mask function */
+  engine_delete,       /* Engine socket deletion function */
+  engine_loop          /* Core engine event loop */
+};
diff --git a/ircd/engine_select.c b/ircd/engine_select.c
new file mode 100644 (file)
index 0000000..9ffc516
--- /dev/null
@@ -0,0 +1,425 @@
+/*
+ * IRC - Internet Relay Chat, ircd/engine_select.c
+ * Copyright (C) 2001 Kevin L. Mitchell <klmitch@mit.edu>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+/** @file
+ * @brief BSD sockets select() event engine.
+ * @version $Id: engine_select.c 1445 2005-07-12 03:10:59Z entrope $
+ */
+#include "config.h"
+
+/* On BSD, define FD_SETSIZE to what we want before including sys/types.h */
+#if  defined(__FreeBSD__) || defined(__NetBSD__) || defined(__bsdi__)
+# if !defined(FD_SETSIZE)
+#  define FD_SETSIZE ((MAXCONNECTIONS)+4)
+# endif
+#endif
+
+#include "ircd_events.h"
+
+#include "ircd.h"
+#include "ircd_log.h"
+#include "s_debug.h"
+
+/* #include <assert.h> -- Now using assert in ircd_log.h */
+#include <errno.h>
+#include <string.h> /* needed for bzero() on OS X */
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <time.h>
+#include <unistd.h>
+
+#if FD_SETSIZE < (MAXCONNECTIONS + 4)
+/*
+ * Sanity check
+ *
+ * All operating systems work when MAXCONNECTIONS <= 252.
+ * Most operating systems work when MAXCONNECTIONS <= 1020 and FD_SETSIZE is
+ *   updated correctly in the system headers (on BSD systems sys/types.h might
+ *   have abruptly redefined it so the check is still done), you might
+ *   already need to recompile your kernel.
+ * For larger FD_SETSIZE your mileage may vary (kernel patches may be needed).
+ */
+# error FD_SETSIZE is too small or MAXCONNECTIONS too large.
+#endif
+
+#define SELECT_ERROR_THRESHOLD 20      /**< after 20 select errors, restart */
+#define ERROR_EXPIRE_TIME      3600    /**< expire errors after an hour */
+
+/** Array of active Socket structures, indexed by file descriptor. */
+static struct Socket* sockList[FD_SETSIZE];
+/** Maximum file descriptor currently used. */
+static int highest_fd;
+/** Global read event interest bitmap. */
+static fd_set global_read_set;
+/** Global write event interest bitmap. */
+static fd_set global_write_set;
+
+/** Number of recent errors from select(). */
+static int errors = 0;
+/** Periodic timer to forget errors. */
+static struct Timer clear_error;
+
+/** Decrement the error count (once per hour).
+ * @param[in] ev Expired timer event (ignored).
+ */
+static void
+error_clear(struct Event* ev)
+{
+  if (!--errors) /* remove timer when error count reaches 0 */
+    timer_del(ev_timer(ev));
+}
+
+/** Initialize the select() engine.
+ * @param[in] max_sockets Maximum number of file descriptors to support.
+ * @return Non-zero on success, or zero on failure.
+ */
+static int
+engine_init(int max_sockets)
+{
+  int i;
+
+  if (max_sockets > FD_SETSIZE) { /* too many sockets */
+    log_write(LS_SYSTEM, L_WARNING, 0,
+             "select() engine cannot handle %d sockets (> %d)",
+             max_sockets, FD_SETSIZE);
+    return 0;
+  }
+
+  FD_ZERO(&global_read_set); /* zero the global fd sets */
+  FD_ZERO(&global_write_set);
+
+  for (i = 0; i < FD_SETSIZE; i++) /* zero the sockList */
+    sockList[i] = 0;
+
+  highest_fd = -1; /* No fds in set */
+
+  return 1; /* initialization successful */
+}
+
+/** Figure out what events go with a given state.
+ * @param[in] state %Socket state to consider.
+ * @param[in] events User-specified preferred event set.
+ * @return Actual set of preferred events.
+ */
+static unsigned int
+state_to_events(enum SocketState state, unsigned int events)
+{
+  switch (state) {
+  case SS_CONNECTING: /* connecting socket */
+    return SOCK_EVENT_WRITABLE;
+    break;
+
+  case SS_LISTENING: /* listening socket */
+  case SS_NOTSOCK: /* our signal socket */
+    return SOCK_EVENT_READABLE;
+    break;
+
+  case SS_CONNECTED: case SS_DATAGRAM: case SS_CONNECTDG:
+    return events; /* ordinary socket */
+    break;
+  }
+
+  /*NOTREACHED*/
+  return 0;
+}
+
+/** Set interest events in #global_read_set and #global_write_set as appropriate.
+ * @param[in] fd File descriptor to operate on.
+ * @param[in] clear Set of interest events to clear from socket.
+ * @param[in] set Set of interest events to set on socket.
+ */
+static void
+set_or_clear(int fd, unsigned int clear, unsigned int set)
+{
+  if ((clear ^ set) & SOCK_EVENT_READABLE) { /* readable has changed */
+    if (set & SOCK_EVENT_READABLE) /* it's set */
+      FD_SET(fd, &global_read_set);
+    else /* clear it */
+      FD_CLR(fd, &global_read_set);
+  }
+
+  if ((clear ^ set) & SOCK_EVENT_WRITABLE) { /* writable has changed */
+    if (set & SOCK_EVENT_WRITABLE) /* it's set */
+      FD_SET(fd, &global_write_set);
+    else /* clear it */
+      FD_CLR(fd, &global_write_set);
+  }
+}
+
+/** Add a socket to the event engine.
+ * @param[in] sock Socket to add to engine.
+ * @return Non-zero on success, or zero on error.
+ */
+static int
+engine_add(struct Socket* sock)
+{
+  assert(0 != sock);
+  assert(0 == sockList[s_fd(sock)]);
+
+  /* bounds-check... */
+  if (s_fd(sock) >= FD_SETSIZE) {
+    log_write(LS_SYSTEM, L_ERROR, 0,
+             "Attempt to add socket %d (> %d) to event engine", s_fd(sock),
+             FD_SETSIZE);
+    return 0;
+  }
+
+  sockList[s_fd(sock)] = sock; /* add to list */
+
+  if (s_fd(sock) >= highest_fd) /* update highest_fd */
+    highest_fd = s_fd(sock);
+
+  Debug((DEBUG_ENGINE, "select: Adding socket %d to engine [%p], state %s",
+        s_fd(sock), sock, state_to_name(s_state(sock))));
+
+  /* set the fd set bits */
+  set_or_clear(s_fd(sock), 0, state_to_events(s_state(sock), s_events(sock)));
+
+  return 1; /* success */
+}
+
+/** Handle state transition for a socket.
+ * @param[in] sock Socket changing state.
+ * @param[in] new_state New state for socket.
+ */
+static void
+engine_state(struct Socket* sock, enum SocketState new_state)
+{
+  assert(0 != sock);
+  assert(sock == sockList[s_fd(sock)]);
+
+  Debug((DEBUG_ENGINE, "select: Changing state for socket %p to %s", sock,
+        state_to_name(new_state)));
+
+  /* set the correct events */
+  set_or_clear(s_fd(sock),
+              state_to_events(s_state(sock), s_events(sock)), /* old state */
+              state_to_events(new_state, s_events(sock))); /* new state */
+}
+
+/** Handle change to preferred socket events.
+ * @param[in] sock Socket getting new interest list.
+ * @param[in] new_events New set of interesting events for socket.
+ */
+static void
+engine_events(struct Socket* sock, unsigned int new_events)
+{
+  assert(0 != sock);
+  assert(sock == sockList[s_fd(sock)]);
+
+  Debug((DEBUG_ENGINE, "select: Changing event mask for socket %p to [%s]",
+        sock, sock_flags(new_events)));
+
+  /* set the correct events */
+  set_or_clear(s_fd(sock),
+              state_to_events(s_state(sock), s_events(sock)), /* old events */
+              state_to_events(s_state(sock), new_events)); /* new events */
+}
+
+/** Remove a socket from the event engine.
+ * @param[in] sock Socket being destroyed.
+ */
+static void
+engine_delete(struct Socket* sock)
+{
+  assert(0 != sock);
+  assert(sock == sockList[s_fd(sock)]);
+
+  Debug((DEBUG_ENGINE, "select: Deleting socket %d [%p], state %s", s_fd(sock),
+        sock, state_to_name(s_state(sock))));
+
+  FD_CLR(s_fd(sock), &global_read_set); /* clear event set bits */
+  FD_CLR(s_fd(sock), &global_write_set);
+
+  sockList[s_fd(sock)] = 0; /* zero the socket list entry */
+
+  while (highest_fd > -1 && sockList[highest_fd] == 0) /* update highest_fd */
+    highest_fd--;
+}
+
+/** Run engine event loop.
+ * @param[in] gen Lists of generators of various types.
+ */
+static void
+engine_loop(struct Generators* gen)
+{
+  struct timeval wait;
+  fd_set read_set;
+  fd_set write_set;
+  int nfds;
+  int i;
+  int errcode;
+  size_t codesize;
+  struct Socket *sock;
+
+  while (running) {
+    read_set = global_read_set; /* all hail structure copy!! */
+    write_set = global_write_set;
+
+    /* set up the sleep time */
+    wait.tv_sec = timer_next(gen) ? (timer_next(gen) - CurrentTime) : -1;
+    wait.tv_usec = 0;
+
+    Debug((DEBUG_INFO, "select: delay: %Tu (%Tu) %Tu", timer_next(gen),
+          CurrentTime, wait.tv_sec));
+
+    /* check for active files */
+    nfds = select(highest_fd + 1, &read_set, &write_set, 0,
+                 wait.tv_sec < 0 ? 0 : &wait);
+
+    CurrentTime = time(0); /* set current time... */
+
+    if (nfds < 0) {
+      if (errno != EINTR) { /* ignore select interrupts */
+       /* Log the select error */
+       log_write(LS_SOCKET, L_ERROR, 0, "select() error: %m");
+       if (!errors++)
+         timer_add(timer_init(&clear_error), error_clear, 0, TT_PERIODIC,
+                   ERROR_EXPIRE_TIME);
+       else if (errors > SELECT_ERROR_THRESHOLD) /* too many errors... */
+         server_restart("too many select errors");
+      }
+      /* old code did a sleep(1) here; with usage these days,
+       * that may be too expensive
+       */
+      continue;
+    }
+
+    for (i = 0; nfds && i <= highest_fd; i++) {
+      if (!(sock = sockList[i])) /* skip empty socket elements */
+       continue;
+
+      assert(s_fd(sock) == i);
+
+      gen_ref_inc(sock); /* can't have it going away on us */
+
+      Debug((DEBUG_ENGINE, "select: Checking socket %p (fd %d) state %s, "
+            "events %s", sock, i, state_to_name(s_state(sock)),
+            sock_flags(s_events(sock))));
+
+      if (s_state(sock) != SS_NOTSOCK) {
+       errcode = 0; /* check for errors on socket */
+       codesize = sizeof(errcode);
+       if (getsockopt(i, SOL_SOCKET, SO_ERROR, &errcode, &codesize) < 0)
+         errcode = errno; /* work around Solaris implementation */
+
+       if (errcode) { /* an error occurred; generate an event */
+         Debug((DEBUG_ENGINE, "select: Error %d on fd %d, socket %p", errcode,
+                i, sock));
+         event_generate(ET_ERROR, sock, errcode);
+         gen_ref_dec(sock); /* careful not to leak reference counts */
+         continue;
+       }
+      }
+
+      switch (s_state(sock)) {
+      case SS_CONNECTING:
+       if (FD_ISSET(i, &write_set)) { /* connection completed */
+         Debug((DEBUG_ENGINE, "select: Connection completed"));
+         event_generate(ET_CONNECT, sock, 0);
+         nfds--;
+         continue;
+       }
+       break;
+
+      case SS_LISTENING:
+       if (FD_ISSET(i, &read_set)) { /* connection to be accepted */
+         Debug((DEBUG_ENGINE, "select: Ready for accept"));
+         event_generate(ET_ACCEPT, sock, 0);
+         nfds--;
+       }
+       break;
+
+      case SS_NOTSOCK:
+       if (FD_ISSET(i, &read_set)) { /* data on socket */
+         /* can't peek; it's not a socket */
+         Debug((DEBUG_ENGINE, "select: non-socket readable"));
+         event_generate(ET_READ, sock, 0);
+         nfds--;
+       }
+       break;
+
+      case SS_CONNECTED:
+       if (FD_ISSET(i, &read_set)) { /* data to be read from socket */
+         char c;
+
+         switch (recv(i, &c, 1, MSG_PEEK)) { /* check for EOF */
+         case -1: /* error occurred?!? */
+           if (errno == EAGAIN) {
+             Debug((DEBUG_ENGINE, "select: Resource temporarily "
+                    "unavailable?"));
+             continue;
+           }
+           Debug((DEBUG_ENGINE, "select: Uncaught error!"));
+           event_generate(ET_ERROR, sock, errno);
+           break;
+
+         case 0: /* EOF from client */
+           Debug((DEBUG_ENGINE, "select: EOF from client"));
+           event_generate(ET_EOF, sock, 0);
+           break;
+
+         default: /* some data can be read */
+           Debug((DEBUG_ENGINE, "select: Data to be read"));
+           event_generate(ET_READ, sock, 0);
+           break;
+         }
+       }
+       if (FD_ISSET(i, &write_set)) { /* data can be written to socket */
+         Debug((DEBUG_ENGINE, "select: Data can be written"));
+         event_generate(ET_WRITE, sock, 0);
+       }
+       if (FD_ISSET(i, &read_set) || FD_ISSET(i, &write_set))
+         nfds--;
+       break;
+
+      case SS_DATAGRAM: case SS_CONNECTDG:
+       if (FD_ISSET(i, &read_set)) { /* data to be read from socket */
+         Debug((DEBUG_ENGINE, "select: Datagram to be read"));
+         event_generate(ET_READ, sock, 0);
+       }
+       if (FD_ISSET(i, &write_set)) { /* data can be written to socket */
+         Debug((DEBUG_ENGINE, "select: Datagram can be written"));
+         event_generate(ET_WRITE, sock, 0);
+       }
+       if (FD_ISSET(i, &read_set) || FD_ISSET(i, &write_set))
+         nfds--;
+       break;
+      }
+
+      assert(s_fd(sock) == i);
+
+      gen_ref_dec(sock); /* we're done with it */
+    }
+
+    timer_run(); /* execute any pending timers */
+  }
+}
+
+/** Descriptor for select() event engine. */
+struct Engine engine_select = {
+  "select()",          /* Engine name */
+  engine_init,         /* Engine initialization function */
+  0,                   /* Engine signal registration function (none) */
+  engine_add,          /* Engine socket registration function */
+  engine_state,                /* Engine socket state change function */
+  engine_events,       /* Engine socket events mask function */
+  engine_delete,       /* Engine socket deletion function */
+  engine_loop          /* Core engine event loop */
+};
diff --git a/ircd/fileio.c b/ircd/fileio.c
new file mode 100644 (file)
index 0000000..950206d
--- /dev/null
@@ -0,0 +1,238 @@
+/*
+ * IRC - Internet Relay Chat, ircd/fileio.c
+ * Copyright (C) 1998 Thomas Helvey <tomh@inxpress.net>
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ *                  University of Oulu, Co Center
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+/** @file
+ * @brief ANSI FILE* clone API implementation.
+ * @version $Id: fileio.c 1334 2005-03-20 16:06:30Z entrope $
+ */
+#include "config.h"
+
+#include "fileio.h"
+#include "ircd_alloc.h"         /* MyMalloc, MyFree */
+#include "ircd_log.h"           /* assert */
+
+/* #include <assert.h> -- Now using assert in ircd_log.h */       /* assert */
+#include <fcntl.h>              /* O_RDONLY, O_WRONLY, ... */
+#include <stdio.h>              /* BUFSIZ, EOF */
+#include <sys/stat.h>           /* struct stat */
+#include <unistd.h>             /* read, write, open, close */
+#include <string.h>
+
+#define FB_EOF  0x01            /**< File has reached EOF. */
+#define FB_FAIL 0x02            /**< File operation failed. */
+
+/** Tracks status and buffer for a file on disk. */
+struct FileBuf {
+  int fd;                       /**< file descriptor */
+  char *endp;                   /**< one past the end */
+  char *ptr;                    /**< current read pos */
+  int flags;                    /**< file state */
+  char buf[BUFSIZ];             /**< buffer */
+};
+
+/** Open a new FBFILE.
+ * @param[in] filename Name of file to open.
+ * @param[in] mode fopen()-style mode string.
+ * @return Pointer to newly allocated FBFILE.
+ */
+FBFILE* fbopen(const char *filename, const char *mode)
+{
+  int openmode = 0;
+  int pmode = 0;
+  FBFILE *fb = NULL;
+  int fd;
+  assert(filename);
+  assert(mode);
+
+  while (*mode) {
+    switch (*mode) {
+    case 'r':
+      openmode = O_RDONLY;
+      break;
+    case 'w':
+      openmode = O_WRONLY | O_CREAT | O_TRUNC;
+      pmode = S_IRUSR | S_IWUSR;
+      break;
+    case 'a':
+      openmode = O_WRONLY | O_CREAT | O_APPEND;
+      pmode = S_IRUSR | S_IWUSR;
+      break;
+    case '+':
+      openmode &= ~(O_RDONLY | O_WRONLY);
+      openmode |= O_RDWR;
+      break;
+    default:
+      break;
+    }
+    ++mode;
+  }
+  /*
+   * stop NFS hangs...most systems should be able to open a file in
+   * 3 seconds. -avalon (courtesy of wumpus)
+   */
+  alarm(3);
+  if ((fd = open(filename, openmode, pmode)) == -1) {
+    alarm(0);
+    return fb;
+  }
+  alarm(0);
+
+  if (NULL == (fb = fdbopen(fd, NULL)))
+    close(fd);
+  return fb;
+}
+
+/** Open a FBFILE from a file descriptor.
+ * @param[in] fd File descriptor to use.
+ * @param[in] mode fopen()-style mode string (ignored).
+ */
+FBFILE* fdbopen(int fd, const char *mode)
+{
+  /*
+   * ignore mode, if file descriptor hasn't been opened with the
+   * correct mode, the first use will fail
+   */
+  FBFILE *fb = (FBFILE *) MyMalloc(sizeof(FBFILE));
+  assert(0 != fb);
+  fb->ptr   = fb->endp = fb->buf;
+  fb->fd    = fd;
+  fb->flags = 0;
+
+  return fb;
+}
+
+/** Close a FBFILE.
+ * @param[in] fb File buffer to close.
+ */
+void fbclose(FBFILE* fb)
+{
+  assert(fb);
+  close(fb->fd);
+  MyFree(fb);
+}
+
+/** Attempt to fill a file's buffer.
+ * @param[in] fb File to operate on.
+ * @return Number of bytes read into buffer, or a negative number on error.
+ */
+static int fbfill(FBFILE * fb)
+{
+  int n;
+  assert(fb);
+  if (fb->flags)
+    return -1;
+  n = read(fb->fd, fb->buf, BUFSIZ);
+  if (0 < n)
+  {
+    fb->ptr = fb->buf;
+    fb->endp = fb->buf + n;
+  }
+  else if (n < 0)
+    fb->flags |= FB_FAIL;
+  else
+    fb->flags |= FB_EOF;
+  return n;
+}
+
+/** Get a single character from a file.
+ * @param[in] fb File to fetch from.
+ * @return Character value read, or EOF on error or end-of-file.
+ */
+int fbgetc(FBFILE * fb)
+{
+  assert(fb);
+  if (fb->ptr < fb->endp || fbfill(fb) > 0)
+    return *fb->ptr++;
+  return EOF;
+}
+
+/** Get a line of input from a file.
+ * @param[out] buf Output buffer to read to.
+ * @param[in] len Maximum number of bytes to write to buffer
+ * (including terminating NUL).
+ * @param[in] fb File to read from.
+ */
+char *fbgets(char *buf, size_t len, FBFILE * fb)
+{
+  char *p = buf;
+  assert(buf);
+  assert(fb);
+  assert(0 < len);
+
+  if (fb->ptr == fb->endp && fbfill(fb) < 1)
+    return 0;
+  --len;
+  while (len--) {
+    *p = *fb->ptr++;
+    if ('\n' == *p)
+    {
+      ++p;
+      break;
+    }
+    /*
+     * deal with CR's
+     */
+    else if ('\r' == *p) {
+      if (fb->ptr < fb->endp || fbfill(fb) > 0) {
+        if ('\n' == *fb->ptr)
+          ++fb->ptr;
+      }
+      *p++ = '\n';
+      break;
+    }
+    ++p;
+    if (fb->ptr == fb->endp && fbfill(fb) < 1)
+      break;
+  }
+  *p = '\0';
+  return buf;
+}
+
+/** Write a string to a file.
+ * @param[in] str String to write to file.
+ * @param[in] fb File to write to.
+ * @return Number of bytes written, or -1 on error.
+ */
+int fbputs(const char *str, FBFILE * fb)
+{
+  int n = -1;
+  assert(str);
+  assert(fb);
+
+  if (0 == fb->flags) {
+    n = write(fb->fd, str, strlen(str));
+    if (-1 == n)
+      fb->flags |= FB_FAIL;
+  }
+  return n;
+}
+
+/** Get file status.
+ * @param[out] sb Receives file status.
+ * @param[in] fb File to get status for.
+ * @return Zero on success, -1 on error.
+ */
+int fbstat(struct stat *sb, FBFILE * fb)
+{
+  assert(sb);
+  assert(fb);
+  return fstat(fb->fd, sb);
+}
+
diff --git a/ircd/gline.c b/ircd/gline.c
new file mode 100644 (file)
index 0000000..e8c7b29
--- /dev/null
@@ -0,0 +1,1309 @@
+/*
+ * IRC - Internet Relay Chat, ircd/gline.c
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ *                    University of Oulu, Finland
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+/** @file
+ * @brief Implementation of Gline manipulation functions.
+ * @version $Id: gline.c 1904 2009-02-09 00:03:34Z entrope $
+ */
+#include "config.h"
+
+#include "gline.h"
+#include "channel.h"
+#include "client.h"
+#include "hash.h"
+#include "ircd.h"
+#include "ircd_alloc.h"
+#include "ircd_features.h"
+#include "ircd_log.h"
+#include "ircd_reply.h"
+#include "ircd_snprintf.h"
+#include "ircd_string.h"
+#include "match.h"
+#include "numeric.h"
+#include "s_bsd.h"
+#include "s_debug.h"
+#include "s_misc.h"
+#include "s_stats.h"
+#include "send.h"
+#include "struct.h"
+#include "sys.h"
+#include "msg.h"
+#include "numnicks.h"
+#include "numeric.h"
+
+/* #include <assert.h> -- Now using assert in ircd_log.h */
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#define CHECK_APPROVED    0    /**< Mask is acceptable */
+#define CHECK_OVERRIDABLE  1   /**< Mask is acceptable, but not by default */
+#define CHECK_REJECTED    2    /**< Mask is totally unacceptable */
+
+#define MASK_WILD_0    0x01    /**< Wildcards in the last position */
+#define MASK_WILD_1    0x02    /**< Wildcards in the next-to-last position */
+
+#define MASK_WILD_MASK 0x03    /**< Mask out the positional wildcards */
+
+#define MASK_WILDS     0x10    /**< Mask contains wildcards */
+#define MASK_IP                0x20    /**< Mask is an IP address */
+#define MASK_HALT      0x40    /**< Finished processing mask */
+
+/** List of user G-lines. */
+struct Gline* GlobalGlineList  = 0;
+/** List of BadChan G-lines. */
+struct Gline* BadChanGlineList = 0;
+
+/** Iterate through \a list of G-lines.  Use this like a for loop,
+ * i.e., follow it with braces and use whatever you passed as \a gl
+ * as a single G-line to be acted upon.
+ *
+ * @param[in] list List of G-lines to iterate over.
+ * @param[in] gl Name of a struct Gline pointer variable that will be made to point to the G-lines in sequence.
+ * @param[in] next Name of a scratch struct Gline pointer variable.
+ */
+/* There is some subtlety here with the boolean operators:
+ * (x || 1) is used to continue in a logical-and series even when !x.
+ * (x && 0) is used to continue in a logical-or series even when x.
+ */
+#ifdef OLD_OGN_IRCU_COMPAT
+    #define GL_EXPIRED(gl) ((gl)->gl_lifetime <= CurrentTime)
+#else
+    #define GL_EXPIRED(gl) ((gl)->gl_lifetime <= CurrentTime || (gl)->gl_expire <= CurrentTime)
+#endif
+#define gliter(list, gl, next)                         \
+  /* Iterate through the G-lines in the list */                \
+  for ((gl) = (list); (gl); (gl) = (next))             \
+    /* Figure out the next pointer in list... */       \
+    if ((((next) = (gl)->gl_next) || 1) &&             \
+       /* Then see if it's expired */                  \
+       GL_EXPIRED(gl)) \
+      /* Record has expired, so free the G-line */     \
+      gline_free((gl));                                        \
+    /* See if we need to expire the G-line */          \
+    else if ((((gl)->gl_expire > CurrentTime) ||        \
+             (((gl)->gl_flags &= ~GLINE_ACTIVE) && 0) ||       \
+             ((gl)->gl_state = GLOCAL_GLOBAL)) && 0)   \
+      ; /* empty statement */                          \
+    else
+
+/** Find canonical user and host for a string.
+ * If \a userhost starts with '$', assign \a userhost to *user_p and NULL to *host_p.
+ * Otherwise, if \a userhost contains '@', assign the earlier part of it to *user_p and the rest to *host_p.
+ * Otherwise, assign \a def_user to *user_p and \a userhost to *host_p.
+ *
+ * @param[in] userhost Input string from user.
+ * @param[out] user_p Gets pointer to user (or channel/realname) part of hostmask.
+ * @param[out] host_p Gets point to host part of hostmask (may be assigned NULL).
+ * @param[in] def_user Default value for user part.
+ */
+static void
+canon_userhost(char *userhost, char **user_p, char **host_p, char *def_user)
+{
+  char *tmp;
+
+  if (*userhost == '$') {
+    *user_p = userhost;
+    *host_p = NULL;
+    return;
+  }
+
+  if (!(tmp = strchr(userhost, '@'))) {
+    *user_p = def_user;
+    *host_p = userhost;
+  } else {
+    *user_p = userhost;
+    *(tmp++) = '\0';
+    *host_p = tmp;
+  }
+}
+
+/** Create a Gline structure.
+ * @param[in] user User part of mask.
+ * @param[in] host Host part of mask (NULL if not applicable).
+ * @param[in] reason Reason for G-line.
+ * @param[in] expire Expiration timestamp.
+ * @param[in] lastmod Last modification timestamp.
+ * @param[in] flags Bitwise combination of GLINE_* bits.
+ * @return Newly allocated G-line.
+ */
+static struct Gline *
+make_gline(char *user, char *host, char *reason, time_t expire, time_t lastmod,
+          time_t lifetime, unsigned int flags)
+{
+  struct Gline *gline;
+
+  assert(0 != expire);
+
+  gline = (struct Gline *)MyMalloc(sizeof(struct Gline)); /* alloc memory */
+  assert(0 != gline);
+
+  DupString(gline->gl_reason, reason); /* initialize gline... */
+  gline->gl_expire = expire;
+  gline->gl_lifetime = lifetime;
+  gline->gl_lastmod = lastmod;
+  gline->gl_flags = flags & GLINE_MASK;
+  gline->gl_state = GLOCAL_GLOBAL; /* not locally modified */
+
+  if (flags & GLINE_BADCHAN) { /* set a BADCHAN gline */
+    DupString(gline->gl_user, user); /* first, remember channel */
+    gline->gl_host = NULL;
+
+    gline->gl_next = BadChanGlineList; /* then link it into list */
+    gline->gl_prev_p = &BadChanGlineList;
+    if (BadChanGlineList)
+      BadChanGlineList->gl_prev_p = &gline->gl_next;
+    BadChanGlineList = gline;
+  } else {
+    DupString(gline->gl_user, user); /* remember them... */
+    if (*user != '$')
+      DupString(gline->gl_host, host);
+    else
+      gline->gl_host = NULL;
+
+    if (*user != '$' && ipmask_parse(host, &gline->gl_addr, &gline->gl_bits))
+      gline->gl_flags |= GLINE_IPMASK;
+
+    gline->gl_next = GlobalGlineList; /* then link it into list */
+    gline->gl_prev_p = &GlobalGlineList;
+    if (GlobalGlineList)
+      GlobalGlineList->gl_prev_p = &gline->gl_next;
+    GlobalGlineList = gline;
+  }
+
+  return gline;
+}
+
+/** Check local clients against a new G-line.
+ * If the G-line is inactive, return immediately.
+ * Otherwise, if any users match it, disconnect them.
+ * @param[in] cptr Peer connect that sent the G-line.
+ * @param[in] sptr Client that originated the G-line.
+ * @param[in] gline New G-line to check.
+ * @return Zero, unless \a sptr G-lined himself, in which case CPTR_KILLED.
+ */
+static int
+do_gline(struct Client *cptr, struct Client *sptr, struct Gline *gline)
+{
+  struct Client *acptr;
+  int fd, retval = 0, tval;
+  struct Membership *member, *nmember;
+  struct Channel *chptr, *nchptr;
+
+  if (feature_bool(FEAT_DISABLE_GLINES))
+    return 0; /* G-lines are disabled */
+
+  if (!GlineIsActive(gline)) /* no action taken on inactive glines */
+    return 0;
+
+    /* Kick all users out of BADCHANs. */
+    if(GlineIsBadChan(gline)) {
+        for(chptr = GlobalChannelList; chptr; chptr = nchptr) {
+            nchptr = chptr->next; /* save nchptr, we may delete him */
+            if(0 == match(GlineUser(gline), chptr->chname)) {
+                for(member = chptr->members; member; member = nmember) {
+                    nmember = member->next_member; /* save nmember, we may delete him */
+                    /* Do not kick opers. */
+                    if(!MyUser(member->user) || IsZombie(member) || IsAnOper(member->user)) continue;
+                    sendcmdto_serv_butone(&me, CMD_KICK, NULL, "%H %C :Badchanneled: %s", chptr, member->user, GlineReason(gline));
+                    sendcmdto_channel_butserv_butone(&me, CMD_KICK, chptr, NULL, 0, "%H %C :Badchanneled: %s", chptr, member->user, GlineReason(gline));
+                    make_zombie(member, member->user, &me, &me, chptr);
+                }
+                if(!string_has_wildcards(GlineUser(gline))) break;
+            }
+        }
+        return 0;
+    }
+
+  for (fd = HighestFd; fd >= 0; --fd) {
+    /*
+     * get the users!
+     */
+    if ((acptr = LocalClientArray[fd])) {
+      if (!cli_user(acptr))
+       continue;
+
+      if (GlineIsRealName(gline)) { /* Realname Gline */
+       Debug((DEBUG_DEBUG,"Realname Gline: %s %s",(cli_info(acptr)),
+                                       gline->gl_user+2));
+        if (match(gline->gl_user+2, cli_info(acptr)) != 0)
+            continue;
+        Debug((DEBUG_DEBUG,"Matched!"));
+      } else { /* Host/IP gline */
+        if (cli_user(acptr)->username &&
+            match(gline->gl_user, (cli_user(acptr))->username) != 0)
+          continue;
+
+        if (GlineIsIpMask(gline)) {
+          if (!ipmask_check(&cli_ip(acptr), &gline->gl_addr, gline->gl_bits))
+            continue;
+        }
+        else {
+          if (match(gline->gl_host, cli_sockhost(acptr)) != 0)
+            continue;
+        }
+      }
+
+      /* ok, here's one that got G-lined */
+      send_reply(acptr, SND_EXPLICIT | ERR_YOUREBANNEDCREEP, ":%s",
+          gline->gl_reason);
+
+      /* let the ops know about it */
+      sendto_opmask_butone(0, SNO_GLINE, "G-line active for %s",
+                           get_client_name(acptr, SHOW_IP));
+
+      /* and get rid of him */
+      if ((tval = exit_client_msg(cptr, acptr, &me, "G-lined (%s)",
+          gline->gl_reason)))
+        retval = tval; /* retain killed status */
+    }
+  }
+  return retval;
+}
+
+/**
+ * Implements the mask checking applied to local G-lines.
+ * Basically, host masks must have a minimum of two non-wild domain
+ * fields, and IP masks must have a minimum of 16 bits.  If the mask
+ * has even one wild-card, OVERRIDABLE is returned, assuming the other
+ * check doesn't fail.
+ * @param[in] mask G-line mask to check.
+ * @return One of CHECK_REJECTED, CHECK_OVERRIDABLE, or CHECK_APPROVED.
+ */
+static int
+gline_checkmask(char *mask)
+{
+  unsigned int flags = MASK_IP;
+  unsigned int dots = 0;
+  unsigned int ipmask = 0;
+
+  for (; *mask; mask++) { /* go through given mask */
+    if (*mask == '.') { /* it's a separator; advance positional wilds */
+      flags = (flags & ~MASK_WILD_MASK) | ((flags << 1) & MASK_WILD_MASK);
+      dots++;
+
+      if ((flags & (MASK_IP | MASK_WILDS)) == MASK_IP)
+       ipmask += 8; /* It's an IP with no wilds, count bits */
+    } else if (*mask == '*' || *mask == '?')
+      flags |= MASK_WILD_0 | MASK_WILDS; /* found a wildcard */
+    else if (*mask == '/') { /* n.n.n.n/n notation; parse bit specifier */
+      ++mask;
+      ipmask = strtoul(mask, &mask, 10);
+
+      /* sanity-check to date */
+      if (*mask || (flags & (MASK_WILDS | MASK_IP)) != MASK_IP)
+       return CHECK_REJECTED;
+      if (!dots) {
+        if (ipmask > 128)
+          return CHECK_REJECTED;
+        if (ipmask < 128)
+          flags |= MASK_WILDS;
+      } else {
+        if (dots != 3 || ipmask > 32)
+          return CHECK_REJECTED;
+        if (ipmask < 32)
+         flags |= MASK_WILDS;
+      }
+
+      flags |= MASK_HALT; /* Halt the ipmask calculation */
+      break; /* get out of the loop */
+    } else if (!IsIP6Char(*mask)) {
+      flags &= ~MASK_IP; /* not an IP anymore! */
+      ipmask = 0;
+    }
+  }
+
+  /* Sanity-check quads */
+  if (dots > 3 || (!(flags & MASK_WILDS) && dots < 3)) {
+    flags &= ~MASK_IP;
+    ipmask = 0;
+  }
+
+  /* update bit count if necessary */
+  if ((flags & (MASK_IP | MASK_WILDS | MASK_HALT)) == MASK_IP)
+    ipmask += 8;
+
+  /* Check to see that it's not too wide of a mask */
+  if (flags & MASK_WILDS &&
+      ((!(flags & MASK_IP) && (dots < 2 || flags & MASK_WILD_MASK)) ||
+       (flags & MASK_IP && ipmask < 16)))
+    return CHECK_REJECTED; /* to wide, reject */
+
+  /* Ok, it's approved; require override if it has wildcards, though */
+  return flags & MASK_WILDS ? CHECK_OVERRIDABLE : CHECK_APPROVED;
+}
+
+/** Forward a G-line to other servers.
+ * @param[in] cptr Client that sent us the G-line.
+ * @param[in] sptr Client that originated the G-line.
+ * @param[in] gline G-line to forward.
+ * @return Zero.
+ */
+static int
+gline_propagate(struct Client *cptr, struct Client *sptr, struct Gline *gline)
+{
+  if (GlineIsLocal(gline))
+    return 0;
+
+  assert(gline->gl_lastmod);
+
+#ifdef OLD_OGN_IRCU_COMPAT
+  sendcmdto_serv_butone(sptr, CMD_GLINE, cptr, "* %c%s%s%s %Tu %Tu :%s",
+                       GlineIsRemActive(gline) ? '+' : '-', gline->gl_user,
+                       gline->gl_host ? "@" : "",
+                       gline->gl_host ? gline->gl_host : "",
+                       gline->gl_expire - CurrentTime, gline->gl_lastmod,
+                       /*gline->gl_lifetime,*/ gline->gl_reason);
+#else
+  sendcmdto_serv_butone(sptr, CMD_GLINE, cptr, "* %c%s%s%s %Tu %Tu %Tu :%s",
+                       GlineIsRemActive(gline) ? '+' : '-', gline->gl_user,
+                       gline->gl_host ? "@" : "",
+                       gline->gl_host ? gline->gl_host : "",
+                       gline->gl_expire - CurrentTime, gline->gl_lastmod,
+                       gline->gl_lifetime, gline->gl_reason);
+#endif
+
+  return 0;
+}
+
+/** Count number of users who match \a mask.
+ * @param[in] mask user\@host or user\@ip mask to check.
+ * @param[in] flags Bitmask possibly containing the value GLINE_LOCAL, to limit searches to this server.
+ * @return Count of matching users.
+ */
+static int
+count_users(char *mask, int flags)
+{
+  struct irc_in_addr ipmask;
+  struct Client *acptr;
+  int count = 0;
+  int ipmask_valid;
+  char namebuf[USERLEN + HOSTLEN + 2];
+  char ipbuf[USERLEN + SOCKIPLEN + 2];
+  unsigned char ipmask_len;
+
+  ipmask_valid = ipmask_parse(mask, &ipmask, &ipmask_len);
+  for (acptr = GlobalClientList; acptr; acptr = cli_next(acptr)) {
+    if (!IsUser(acptr))
+      continue;
+    if ((flags & GLINE_LOCAL) && !MyConnect(acptr))
+      continue;
+
+    ircd_snprintf(0, namebuf, sizeof(namebuf), "%s@%s",
+                 cli_user(acptr)->username, cli_user(acptr)->host);
+    ircd_snprintf(0, ipbuf, sizeof(ipbuf), "%s@%s", cli_user(acptr)->username,
+                 ircd_ntoa(&cli_ip(acptr)));
+
+    if (!match(mask, namebuf)
+        || !match(mask, ipbuf)
+        || (ipmask_valid && ipmask_check(&cli_ip(acptr), &ipmask, ipmask_len)))
+      count++;
+  }
+
+  return count;
+}
+
+/** Count number of users with a realname matching \a mask.
+ * @param[in] mask Wildcard mask to match against realnames.
+ * @return Count of matching users.
+ */
+static int
+count_realnames(const char *mask)
+{
+  struct Client *acptr;
+  int minlen;
+  int count;
+  char cmask[BUFSIZE];
+
+  count = 0;
+  matchcomp(cmask, &minlen, NULL, mask);
+  for (acptr = GlobalClientList; acptr; acptr = cli_next(acptr)) {
+    if (!IsUser(acptr))
+      continue;
+    if (strlen(cli_info(acptr)) < minlen)
+      continue;
+    if (!matchexec(cli_info(acptr), cmask, minlen))
+      count++;
+  }
+  return count;
+}
+
+/** Create a new G-line and add it to global lists.
+ * \a userhost may be in one of four forms:
+ * \li A channel name, to add a BadChan.
+ * \li A string starting with $R and followed by a mask to match against their realname.
+ * \li A user\@IP mask (user\@ part optional) to create an IP-based ban.
+ * \li A user\@host mask (user\@ part optional) to create a hostname ban.
+ *
+ * @param[in] cptr Client that sent us the G-line.
+ * @param[in] sptr Client that originated the G-line.
+ * @param[in] userhost Text mask for the G-line.
+ * @param[in] reason Reason for G-line.
+ * @param[in] expire Expiration time of G-line.
+ * @param[in] lastmod Last modification time of G-line.
+ * @param[in] lifetime Lifetime of G-line.
+ * @param[in] flags Bitwise combination of GLINE_* flags.
+ * @return Zero or CPTR_KILLED, depending on whether \a sptr is suicidal.
+ */
+int
+gline_add(struct Client *cptr, struct Client *sptr, char *userhost,
+         char *reason, time_t expire, time_t lastmod, time_t lifetime,
+         unsigned int flags)
+{
+  struct Gline *agline;
+  char uhmask[USERLEN + HOSTLEN + 2];
+  char *user, *host;
+  int tmp;
+
+  assert(0 != userhost);
+  assert(0 != reason);
+  assert(((flags & (GLINE_GLOBAL | GLINE_LOCAL)) == GLINE_GLOBAL) ||
+         ((flags & (GLINE_GLOBAL | GLINE_LOCAL)) == GLINE_LOCAL));
+
+  Debug((DEBUG_DEBUG, "gline_add(\"%s\", \"%s\", \"%s\", \"%s\", %Tu, %Tu "
+        "%Tu, 0x%04x)", cli_name(cptr), cli_name(sptr), userhost, reason,
+        expire, lastmod, lifetime, flags));
+
+  if (*userhost == '#' || *userhost == '&') {
+    if ((flags & GLINE_LOCAL) && !HasPriv(sptr, PRIV_LOCAL_BADCHAN))
+      return send_reply(sptr, ERR_NOPRIVILEGES);
+
+    flags |= GLINE_BADCHAN;
+    user = userhost;
+    host = NULL;
+  } else if (*userhost == '$') {
+    switch (userhost[1]) {
+      case 'R': flags |= GLINE_REALNAME; break;
+      default:
+        /* uh, what to do here? */
+        /* The answer, my dear Watson, is we throw a protocol_violation()
+           -- hikari */
+        if (IsServer(cptr))
+          return protocol_violation(sptr,"%s has been smoking the sweet leaf and sent me a whacky gline",cli_name(sptr));
+        sendto_opmask_butone(NULL, SNO_GLINE, "%s has been smoking the sweet leaf and sent me a whacky gline", cli_name(sptr));
+        return 0;
+    }
+    user = userhost;
+    host = NULL;
+    if (MyUser(sptr) || (IsUser(sptr) && flags & GLINE_LOCAL)) {
+      tmp = count_realnames(userhost + 2);
+      if ((tmp >= feature_int(FEAT_GLINEMAXUSERCOUNT))
+         && !(flags & GLINE_OPERFORCE))
+       return send_reply(sptr, ERR_TOOMANYUSERS, tmp);
+    }
+  } else {
+    canon_userhost(userhost, &user, &host, "*");
+    if (sizeof(uhmask) <
+       ircd_snprintf(0, uhmask, sizeof(uhmask), "%s@%s", user, host))
+      return send_reply(sptr, ERR_LONGMASK);
+    else if (MyUser(sptr) || (IsUser(sptr) && flags & GLINE_LOCAL)) {
+      switch (gline_checkmask(host)) {
+      case CHECK_OVERRIDABLE: /* oper overrided restriction */
+       if (flags & GLINE_OPERFORCE)
+         break;
+       /*FALLTHROUGH*/
+      case CHECK_REJECTED:
+       return send_reply(sptr, ERR_MASKTOOWIDE, uhmask);
+       break;
+      }
+
+      if ((tmp = count_users(uhmask, flags)) >=
+         feature_int(FEAT_GLINEMAXUSERCOUNT) && !(flags & GLINE_OPERFORCE))
+       return send_reply(sptr, ERR_TOOMANYUSERS, tmp);
+    }
+  }
+
+  /*
+   * You cannot set a negative (or zero) expire time, nor can you set an
+   * expiration time for greater than GLINE_MAX_EXPIRE, it will be
+   * set to GLINE_MAX_EXPIRE
+   */
+  if(expire <= CurrentTime) {
+    if(!IsServer(sptr) && MyConnect(sptr))
+      send_reply(sptr, ERR_BADEXPIRE, expire);
+    return 0;
+  }
+  else if(expire > CurrentTime + GLINE_MAX_EXPIRE) {
+    if(!IsServer(sptr) && MyConnect(sptr))
+      send_reply(sptr, ERR_CHANGEDEXPIRE, expire, CurrentTime + GLINE_MAX_EXPIRE);
+    expire = CurrentTime + GLINE_MAX_EXPIRE;
+  }
+
+  if (!lifetime) /* no lifetime set, use expiration time */
+    lifetime = expire;
+
+  /* lifetime is already an absolute timestamp */
+
+  /* Inform ops... */
+  sendto_opmask_butone(0, ircd_strncmp(reason, "AUTO", 4) ? SNO_GLINE :
+                       SNO_AUTO, "%s adding %s%s %s for %s%s%s, expiring at "
+                       "%Tu: %s",
+                       (feature_bool(FEAT_HIS_SNOTICES) || IsServer(sptr)) ?
+                         cli_name(sptr) :
+                         cli_name((cli_user(sptr))->server),
+                       (flags & GLINE_ACTIVE) ? "" : "deactivated ",
+                      (flags & GLINE_LOCAL) ? "local" : "global",
+                      (flags & GLINE_BADCHAN) ? "BADCHAN" : "GLINE", user,
+                      (flags & (GLINE_BADCHAN|GLINE_REALNAME)) ? "" : "@",
+                      (flags & (GLINE_BADCHAN|GLINE_REALNAME)) ? "" : host,
+                      expire + TSoffset, reason);
+
+  /* and log it */
+  log_write(LS_GLINE, L_INFO, LOG_NOSNOTICE,
+           "%#C adding %s %s for %s%s%s, expiring at %Tu: %s", sptr,
+           flags & GLINE_LOCAL ? "local" : "global",
+           flags & GLINE_BADCHAN ? "BADCHAN" : "GLINE", user,
+           flags & (GLINE_BADCHAN|GLINE_REALNAME) ? "" : "@",
+           flags & (GLINE_BADCHAN|GLINE_REALNAME) ? "" : host,
+           expire + TSoffset, reason);
+
+  /* make the gline */
+  agline = make_gline(user, host, reason, expire, lastmod, lifetime, flags);
+
+  /* since we've disabled overlapped G-line checking, agline should
+   * never be NULL...
+   */
+  assert(agline);
+
+  gline_propagate(cptr, sptr, agline);
+
+  return do_gline(cptr, sptr, agline); /* knock off users if necessary */
+}
+
+/** Activate a currently inactive G-line.
+ * @param[in] cptr Peer that told us to activate the G-line.
+ * @param[in] sptr Client that originally thought it was a good idea.
+ * @param[in] gline G-line to activate.
+ * @param[in] lastmod New value for last modification timestamp.
+ * @param[in] flags 0 if the activation should be propagated, GLINE_LOCAL if not.
+ * @return Zero, unless \a sptr had a death wish (in which case CPTR_KILLED).
+ */
+int
+gline_activate(struct Client *cptr, struct Client *sptr, struct Gline *gline,
+              time_t lastmod, unsigned int flags)
+{
+  unsigned int saveflags = 0;
+
+  assert(0 != gline);
+
+  saveflags = gline->gl_flags;
+
+  if (flags & GLINE_LOCAL)
+    gline->gl_flags &= ~GLINE_LDEACT;
+  else {
+    gline->gl_flags |= GLINE_ACTIVE;
+
+    if (gline->gl_lastmod) {
+      if (gline->gl_lastmod >= lastmod) /* force lastmod to increase */
+       gline->gl_lastmod++;
+      else
+       gline->gl_lastmod = lastmod;
+    }
+  }
+
+  if ((saveflags & GLINE_ACTMASK) == GLINE_ACTIVE)
+    return 0; /* was active to begin with */
+
+  /* Inform ops and log it */
+  sendto_opmask_butone(0, SNO_GLINE, "%s activating global %s for %s%s%s, "
+                       "expiring at %Tu: %s",
+                       (feature_bool(FEAT_HIS_SNOTICES) || IsServer(sptr)) ?
+                         cli_name(sptr) :
+                         cli_name((cli_user(sptr))->server),
+                       GlineIsBadChan(gline) ? "BADCHAN" : "GLINE",
+                       gline->gl_user, gline->gl_host ? "@" : "",
+                       gline->gl_host ? gline->gl_host : "",
+                       gline->gl_expire + TSoffset, gline->gl_reason);
+  
+  log_write(LS_GLINE, L_INFO, LOG_NOSNOTICE,
+           "%#C activating global %s for %s%s%s, expiring at %Tu: %s", sptr,
+           GlineIsBadChan(gline) ? "BADCHAN" : "GLINE", gline->gl_user,
+           gline->gl_host ? "@" : "",
+           gline->gl_host ? gline->gl_host : "",
+           gline->gl_expire + TSoffset, gline->gl_reason);
+
+  if (!(flags & GLINE_LOCAL)) /* don't propagate local changes */
+    gline_propagate(cptr, sptr, gline);
+
+  return do_gline(cptr, sptr, gline);
+}
+
+/** Deactivate a G-line.
+ * @param[in] cptr Peer that gave us the message.
+ * @param[in] sptr Client that initiated the deactivation.
+ * @param[in] gline G-line to deactivate.
+ * @param[in] lastmod New value for G-line last modification timestamp.
+ * @param[in] flags GLINE_LOCAL to only deactivate locally, 0 to propagate.
+ * @return Zero.
+ */
+int
+gline_deactivate(struct Client *cptr, struct Client *sptr, struct Gline *gline,
+                time_t lastmod, unsigned int flags)
+{
+  unsigned int saveflags = 0;
+  char *msg;
+
+  assert(0 != gline);
+
+  saveflags = gline->gl_flags;
+
+  if (GlineIsLocal(gline))
+    msg = "removing local";
+  else if (!gline->gl_lastmod && !(flags & GLINE_LOCAL)) {
+    msg = "removing global";
+    gline->gl_flags &= ~GLINE_ACTIVE; /* propagate a -<mask> */
+  } else {
+    msg = "deactivating global";
+
+    if (flags & GLINE_LOCAL)
+      gline->gl_flags |= GLINE_LDEACT;
+    else {
+      gline->gl_flags &= ~GLINE_ACTIVE;
+
+      if (gline->gl_lastmod) {
+       if (gline->gl_lastmod >= lastmod)
+         gline->gl_lastmod++;
+       else
+         gline->gl_lastmod = lastmod;
+      }
+    }
+
+    if ((saveflags & GLINE_ACTMASK) != GLINE_ACTIVE)
+      return 0; /* was inactive to begin with */
+  }
+
+  /* Inform ops and log it */
+  sendto_opmask_butone(0, SNO_GLINE, "%s %s %s for %s%s%s, expiring at %Tu: "
+                      "%s",
+                       (feature_bool(FEAT_HIS_SNOTICES) || IsServer(sptr)) ?
+                         cli_name(sptr) :
+                         cli_name((cli_user(sptr))->server),
+                      msg, GlineIsBadChan(gline) ? "BADCHAN" : "GLINE",
+                      gline->gl_user, gline->gl_host ? "@" : "",
+                       gline->gl_host ? gline->gl_host : "",
+                      gline->gl_expire + TSoffset, gline->gl_reason);
+
+  log_write(LS_GLINE, L_INFO, LOG_NOSNOTICE,
+           "%#C %s %s for %s%s%s, expiring at %Tu: %s", sptr, msg,
+           GlineIsBadChan(gline) ? "BADCHAN" : "GLINE", gline->gl_user,
+           gline->gl_host ? "@" : "",
+           gline->gl_host ? gline->gl_host : "",
+           gline->gl_expire + TSoffset, gline->gl_reason);
+
+  if (!(flags & GLINE_LOCAL)) /* don't propagate local changes */
+    gline_propagate(cptr, sptr, gline);
+
+  /* if it's a local gline or a Uworld gline (and not locally deactivated).. */
+  if (GlineIsLocal(gline) || (!gline->gl_lastmod && !(flags & GLINE_LOCAL)))
+    gline_free(gline); /* get rid of it */
+
+  return 0;
+}
+
+/** Modify a global G-line.
+ * @param[in] cptr Client that sent us the G-line modification.
+ * @param[in] sptr Client that originated the G-line modification.
+ * @param[in] gline G-line being modified.
+ * @param[in] action Resultant status of the G-line.
+ * @param[in] reason Reason for G-line.
+ * @param[in] expire Expiration time of G-line.
+ * @param[in] lastmod Last modification time of G-line.
+ * @param[in] lifetime Lifetime of G-line.
+ * @param[in] flags Bitwise combination of GLINE_* flags.
+ * @return Zero or CPTR_KILLED, depending on whether \a sptr is suicidal.
+ */
+int
+gline_modify(struct Client *cptr, struct Client *sptr, struct Gline *gline,
+            enum GlineAction action, char *reason, time_t expire,
+            time_t lastmod, time_t lifetime, unsigned int flags)
+{
+  char buf[BUFSIZE], *op = "";
+  int pos = 0, disable_gl = 0;
+
+  assert(gline);
+  assert(!GlineIsLocal(gline));
+
+  Debug((DEBUG_DEBUG,  "gline_modify(\"%s\", \"%s\", \"%s%s%s\", %s, \"%s\", "
+        "%Tu, %Tu, %Tu, 0x%04x)", cli_name(cptr), cli_name(sptr),
+        gline->gl_user, gline->gl_host ? "@" : "",
+        gline->gl_host ? gline->gl_host : "",
+        action == GLINE_ACTIVATE ? "GLINE_ACTIVATE" :
+        (action == GLINE_DEACTIVATE ? "GLINE_DEACTIVATE" :
+         (action == GLINE_LOCAL_ACTIVATE ? "GLINE_LOCAL_ACTIVATE" :
+          (action == GLINE_LOCAL_DEACTIVATE ? "GLINE_LOCAL_DEACTIVATE" :
+           (action == GLINE_MODIFY ? "GLINE_MODIFY" : "<UNKNOWN>")))),
+        reason, expire, lastmod, lifetime, flags));
+
+  /* First, let's check lastmod... */
+  if (action != GLINE_LOCAL_ACTIVATE && action != GLINE_LOCAL_DEACTIVATE) {
+    if (GlineLastMod(gline) > lastmod) { /* we have a more recent version */
+      if (IsBurstOrBurstAck(cptr))
+       return 0; /* middle of a burst, it'll resync on its own */
+      return gline_resend(cptr, gline); /* resync the server */
+    } else if (GlineLastMod(gline) == lastmod)
+      return 0; /* we have that version of the G-line... */
+  }
+
+  /* All right, we know that there's a change of some sort.  What is it? */
+  /* first, check out the expiration time... */
+  if (flags & GLINE_EXPIRE) {
+    if (!(flags & GLINE_FORCE)) {
+      /* Allow to set times smaller than CurrentTime to allow the
+       * explicit deletion/deactivation of a gline.
+       */
+      if(expire > CurrentTime + GLINE_MAX_EXPIRE) {
+        if(!IsServer(sptr) && MyConnect(sptr))
+          send_reply(sptr, ERR_CHANGEDEXPIRE, expire, CurrentTime + GLINE_MAX_EXPIRE);
+        expire = CurrentTime + GLINE_MAX_EXPIRE;
+      }
+    }
+    if(expire <= CurrentTime) disable_gl = 1;
+#ifdef OLD_OGN_IRCU_COMPAT
+    /* Compatibility issue:
+     * The ircu prior to ircu-2.10.12.10 has no lifetime, therefore, we force
+     * the lifetime to be the same as the expiration time here. This allows to
+     * remove glines by setting the expiration-time to a smaller value than CurrentTime.
+     * This has to be removed when the full ircu-2.10.12.10 gline features
+     * want to be used on the whole network.
+     */
+    lifetime = expire;
+    flags |= GLINE_LIFETIME;
+#endif
+  } else {
+    flags &= ~GLINE_EXPIRE;
+    expire = 0;
+  }
+
+  /* Now check to see if there's any change... */
+  if ((flags & GLINE_EXPIRE) && expire == gline->gl_expire) {
+    flags &= ~GLINE_EXPIRE; /* no change to expiration time... */
+    expire = 0;
+  }
+
+  /* Next, check out lifetime--this one's a bit trickier... */
+  if (!(flags & GLINE_LIFETIME))
+    lifetime = gline->gl_lifetime; /* use G-line lifetime */
+
+  lifetime = IRCD_MAX(lifetime, expire); /* set lifetime to the max */
+
+#ifdef OLD_OGN_IRCU_COMPAT
+  flags |= GLINE_LIFETIME;
+#else
+  /* OK, let's see which is greater... */
+  if (lifetime > gline->gl_lifetime)
+    flags |= GLINE_LIFETIME; /* have to update lifetime */
+  else {
+    flags &= ~GLINE_LIFETIME; /* no change to lifetime */
+    lifetime = 0;
+  }
+#endif
+
+  /* Finally, let's see if the reason needs to be updated */
+  if ((flags & GLINE_REASON) && reason &&
+      !ircd_strcmp(gline->gl_reason, reason))
+    flags &= ~GLINE_REASON; /* no changes to the reason */
+
+  /* OK, now let's take a look at the action... */
+  if ((action == GLINE_ACTIVATE && (gline->gl_flags & GLINE_ACTIVE)) ||
+      (action == GLINE_DEACTIVATE && !(gline->gl_flags & GLINE_ACTIVE)) ||
+      (action == GLINE_LOCAL_ACTIVATE &&
+       (gline->gl_state == GLOCAL_ACTIVATED)) ||
+      (action == GLINE_LOCAL_DEACTIVATE &&
+       (gline->gl_state == GLOCAL_DEACTIVATED)) ||
+      /* can't activate an expired G-line */
+      IRCD_MAX(gline->gl_expire, expire) <= CurrentTime)
+    action = GLINE_MODIFY; /* no activity state modifications */
+
+  Debug((DEBUG_DEBUG,  "About to perform changes; flags 0x%04x, action %s",
+        flags, action == GLINE_ACTIVATE ? "GLINE_ACTIVATE" :
+        (action == GLINE_DEACTIVATE ? "GLINE_DEACTIVATE" :
+         (action == GLINE_LOCAL_ACTIVATE ? "GLINE_LOCAL_ACTIVATE" :
+          (action == GLINE_LOCAL_DEACTIVATE ? "GLINE_LOCAL_DEACTIVATE" :
+           (action == GLINE_MODIFY ? "GLINE_MODIFY" : "<UNKNOWN>"))))));
+
+  /* If there are no changes to perform, do no changes */
+  if (!(flags & GLINE_UPDATE) && action == GLINE_MODIFY)
+    return 0;
+
+  /* Now we know what needs to be changed, so let's process the changes... */
+
+  /* Start by updating lastmod, if indicated... */
+  if (action != GLINE_LOCAL_ACTIVATE && action != GLINE_LOCAL_DEACTIVATE)
+    gline->gl_lastmod = lastmod;
+
+  /* Then move on to activity status changes... */
+  switch (action) {
+  case GLINE_ACTIVATE: /* Globally activating G-line */
+    gline->gl_flags |= GLINE_ACTIVE; /* make it active... */
+    gline->gl_state = GLOCAL_GLOBAL; /* reset local activity state */
+    pos += ircd_snprintf(0, buf, sizeof(buf), " globally activating G-line");
+    op = "+"; /* operation for G-line propagation */
+    break;
+
+  case GLINE_DEACTIVATE: /* Globally deactivating G-line */
+    gline->gl_flags &= ~GLINE_ACTIVE; /* make it inactive... */
+    gline->gl_state = GLOCAL_GLOBAL; /* reset local activity state */
+    pos += ircd_snprintf(0, buf, sizeof(buf), " globally deactivating G-line");
+    op = "-"; /* operation for G-line propagation */
+    break;
+
+  case GLINE_LOCAL_ACTIVATE: /* Locally activating G-line */
+    gline->gl_state = GLOCAL_ACTIVATED; /* make it locally active */
+    pos += ircd_snprintf(0, buf, sizeof(buf), " locally activating G-line");
+    break;
+
+  case GLINE_LOCAL_DEACTIVATE: /* Locally deactivating G-line */
+    gline->gl_state = GLOCAL_DEACTIVATED; /* make it locally inactive */
+    pos += ircd_snprintf(0, buf, sizeof(buf), " locally deactivating G-line");
+    break;
+
+  case GLINE_MODIFY: /* no change to activity status */
+    break;
+  }
+
+  /* Handle expiration changes... */
+  if (flags & GLINE_EXPIRE) {
+    gline->gl_expire = expire; /* save new expiration time */
+    if (pos < BUFSIZE)
+      pos += ircd_snprintf(0, buf + pos, sizeof(buf) - pos,
+                          "%s%s changing expiration time to %Tu",
+                          pos ? ";" : "",
+                          pos && !(flags & (GLINE_LIFETIME | GLINE_REASON)) ?
+                          " and" : "", expire);
+  }
+
+  /* Next, handle lifetime changes... */
+  if (flags & GLINE_LIFETIME) {
+    gline->gl_lifetime = lifetime; /* save new lifetime */
+    if (pos < BUFSIZE)
+      pos += ircd_snprintf(0, buf + pos, sizeof(buf) - pos,
+                          "%s%s extending record lifetime to %Tu",
+                          pos ? ";" : "", pos && !(flags & GLINE_REASON) ?
+                          " and" : "", lifetime);
+  }
+
+  /* Now, handle reason changes... */
+  if (flags & GLINE_REASON) {
+    MyFree(gline->gl_reason); /* release old reason */
+    DupString(gline->gl_reason, reason); /* store new reason */
+    if (pos < BUFSIZE)
+      pos += ircd_snprintf(0, buf + pos, sizeof(buf) - pos,
+                          "%s%s changing reason to \"%s\"",
+                          pos ? ";" : "", pos ? " and" : "", reason);
+  }
+
+  /* All right, inform ops... */
+  if(disable_gl) {
+    /* We send a special message if the expiration time has been set below CurrentTime.
+     * However, we additionally save the exact message in the log, so we have both information
+     * in there. But the ops don't need to be bothered twice.
+     */
+    sendto_opmask_butone(0, SNO_GLINE, "%s deleting global %s for %s%s%s",
+                      (feature_bool(FEAT_HIS_SNOTICES) || IsServer(sptr)) ?
+                      cli_name(sptr) : cli_name((cli_user(sptr))->server),
+                      GlineIsBadChan(gline) ? "BADCHAN" : "GLINE",
+                      gline->gl_user, gline->gl_host ? "@" : "",
+                      gline->gl_host ? gline->gl_host : "");
+    log_write(LS_GLINE, L_INFO, LOG_NOSNOTICE,
+           "%#C deleting global %s for %s%s%s", sptr,
+           GlineIsBadChan(gline) ? "BADCHAN" : "GLINE", gline->gl_user,
+           gline->gl_host ? "@" : "", gline->gl_host ? gline->gl_host : "");
+  }
+  else {
+    sendto_opmask_butone(0, SNO_GLINE, "%s modifying global %s for %s%s%s:%s",
+                      (feature_bool(FEAT_HIS_SNOTICES) || IsServer(sptr)) ?
+                      cli_name(sptr) : cli_name((cli_user(sptr))->server),
+                      GlineIsBadChan(gline) ? "BADCHAN" : "GLINE",
+                      gline->gl_user, gline->gl_host ? "@" : "",
+                      gline->gl_host ? gline->gl_host : "", buf);
+  }
+
+  /* and log the change */
+  log_write(LS_GLINE, L_INFO, LOG_NOSNOTICE,
+           "%#C modifying global %s for %s%s%s:%s", sptr,
+           GlineIsBadChan(gline) ? "BADCHAN" : "GLINE", gline->gl_user,
+           gline->gl_host ? "@" : "", gline->gl_host ? gline->gl_host : "",
+           buf);
+
+  /* We'll be simple for this release, but we can update this to change
+   * the propagation syntax on future updates
+   */
+#ifdef OLD_OGN_IRCU_COMPAT
+  if (action != GLINE_LOCAL_ACTIVATE && action != GLINE_LOCAL_DEACTIVATE)
+    sendcmdto_serv_butone(sptr, CMD_GLINE, cptr,
+                         "* %s%s%s%s%s %Tu %Tu :%s",
+                         flags & GLINE_OPERFORCE ? "!" : "", op,
+                         gline->gl_user, gline->gl_host ? "@" : "",
+                         gline->gl_host ? gline->gl_host : "",
+                         gline->gl_expire, gline->gl_lastmod,
+                         /*gline->gl_lifetime,*/ gline->gl_reason);
+#else
+  if (action != GLINE_LOCAL_ACTIVATE && action != GLINE_LOCAL_DEACTIVATE)
+    sendcmdto_serv_butone(sptr, CMD_GLINE, cptr,
+                         "* %s%s%s%s%s %Tu %Tu %Tu :%s",
+                         flags & GLINE_OPERFORCE ? "!" : "", op,
+                         gline->gl_user, gline->gl_host ? "@" : "",
+                         gline->gl_host ? gline->gl_host : "",
+                         gline->gl_expire, gline->gl_lastmod,
+                         gline->gl_lifetime, gline->gl_reason);
+#endif
+
+  /* OK, let's do the G-line... */
+  if(disable_gl) return 0;
+  else return do_gline(cptr, sptr, gline);
+}
+
+/** Destroy a local G-line.
+ * @param[in] cptr Peer that gave us the message.
+ * @param[in] sptr Client that initiated the destruction.
+ * @param[in] gline G-line to destroy.
+ * @return Zero.
+ */
+int
+gline_destroy(struct Client *cptr, struct Client *sptr, struct Gline *gline)
+{
+  assert(gline);
+  assert(GlineIsLocal(gline));
+
+  /* Inform ops and log it */
+  sendto_opmask_butone(0, SNO_GLINE, "%s removing local %s for %s%s%s",
+                      (feature_bool(FEAT_HIS_SNOTICES) || IsServer(sptr)) ?
+                      cli_name(sptr) : cli_name((cli_user(sptr))->server),
+                      GlineIsBadChan(gline) ? "BADCHAN" : "GLINE",
+                      gline->gl_user, gline->gl_host ? "@" : "",
+                      gline->gl_host ? gline->gl_host : "");
+  log_write(LS_GLINE, L_INFO, LOG_NOSNOTICE,
+           "%#C removing local %s for %s%s%s", sptr,
+           GlineIsBadChan(gline) ? "BADCHAN" : "GLINE", gline->gl_user,
+           gline->gl_host ? "@" : "", gline->gl_host ? gline->gl_host : "");
+
+  gline_free(gline); /* get rid of the G-line */
+
+  return 0; /* convenience return */
+}
+
+/** Find a G-line for a particular mask, guided by certain flags.
+ * Certain bits in \a flags are interpreted specially:
+ * <dl>
+ * <dt>GLINE_ANY</dt><dd>Search both BadChans and user G-lines.</dd>
+ * <dt>GLINE_BADCHAN</dt><dd>Search BadChans.</dd>
+ * <dt>GLINE_GLOBAL</dt><dd>Only match global G-lines.</dd>
+ * <dt>GLINE_LOCAL</dt><dd>Only match local G-lines.</dd>
+ * <dt>GLINE_LASTMOD</dt><dd>Only match G-lines with a last modification time.</dd>
+ * <dt>GLINE_EXACT</dt><dd>Require an exact match of G-line mask.</dd>
+ * <dt>anything else</dt><dd>Search user G-lines.</dd>
+ * </dl>
+ * @param[in] userhost Mask to search for.
+ * @param[in] flags Bitwise combination of GLINE_* flags.
+ * @return First matching G-line, or NULL if none are found.
+ */
+struct Gline *
+gline_find(char *userhost, unsigned int flags)
+{
+  struct Gline *gline = 0;
+  struct Gline *sgline;
+  char *user, *host, *t_uh;
+
+  if (flags & (GLINE_BADCHAN | GLINE_ANY)) {
+    gliter(BadChanGlineList, gline, sgline) {
+        if ((flags & (GlineIsLocal(gline) ? GLINE_GLOBAL : GLINE_LOCAL)) ||
+         (flags & GLINE_LASTMOD && !gline->gl_lastmod))
+       continue;
+      else if ((flags & GLINE_EXACT ? ircd_strcmp(gline->gl_user, userhost) :
+               match(gline->gl_user, userhost)) == 0)
+       return gline;
+    }
+  }
+
+  if ((flags & (GLINE_BADCHAN | GLINE_ANY)) == GLINE_BADCHAN ||
+      *userhost == '#' || *userhost == '&')
+    return 0;
+
+  DupString(t_uh, userhost);
+  canon_userhost(t_uh, &user, &host, "*");
+
+  gliter(GlobalGlineList, gline, sgline) {
+    if ((flags & (GlineIsLocal(gline) ? GLINE_GLOBAL : GLINE_LOCAL)) ||
+       (flags & GLINE_LASTMOD && !gline->gl_lastmod))
+      continue;
+    else if (flags & GLINE_EXACT) {
+      if (((gline->gl_host && host && ircd_strcmp(gline->gl_host, host) == 0)
+           || (!gline->gl_host && !host)) &&
+          (ircd_strcmp(gline->gl_user, user) == 0))
+       break;
+    } else {
+      if (((gline->gl_host && host && match(gline->gl_host, host) == 0)
+           || (!gline->gl_host && !host)) &&
+         (match(gline->gl_user, user) == 0))
+       break;
+    }
+  }
+
+  MyFree(t_uh);
+
+  return gline;
+}
+
+/** Find a matching G-line for a user.
+ * @param[in] cptr Client to compare against.
+ * @param[in] flags Bitwise combination of GLINE_GLOBAL and/or
+ * GLINE_LASTMOD to limit matches.
+ * @return Matching G-line, or NULL if none are found.
+ */
+struct Gline *
+gline_lookup(struct Client *cptr, unsigned int flags)
+{
+  struct Gline *gline;
+  struct Gline *sgline;
+
+  gliter(GlobalGlineList, gline, sgline) {
+    if ((flags & GLINE_GLOBAL && gline->gl_flags & GLINE_LOCAL) ||
+        (flags & GLINE_LASTMOD && !gline->gl_lastmod))
+      continue;
+
+    if (GlineIsRealName(gline)) {
+      Debug((DEBUG_DEBUG,"realname gline: '%s' '%s'",gline->gl_user,cli_info(cptr)));
+      if (match(gline->gl_user+2, cli_info(cptr)) != 0)
+        continue;
+    }
+    else {
+      if (match(gline->gl_user, (cli_user(cptr))->username) != 0)
+        continue;
+
+      if (GlineIsIpMask(gline)) {
+        if (!ipmask_check(&cli_ip(cptr), &gline->gl_addr, gline->gl_bits))
+          continue;
+      }
+      else {
+        if (match(gline->gl_host, (cli_user(cptr))->realhost) != 0)
+          continue;
+      }
+    }
+    if (GlineIsActive(gline))
+      return gline;
+  }
+  /*
+   * No Glines matched
+   */
+  return 0;
+}
+
+/** Delink and free a G-line.
+ * @param[in] gline G-line to free.
+ */
+void
+gline_free(struct Gline *gline)
+{
+  assert(0 != gline);
+
+  *gline->gl_prev_p = gline->gl_next; /* squeeze this gline out */
+  if (gline->gl_next)
+    gline->gl_next->gl_prev_p = gline->gl_prev_p;
+
+  MyFree(gline->gl_user); /* free up the memory */
+  if (gline->gl_host)
+    MyFree(gline->gl_host);
+  MyFree(gline->gl_reason);
+  MyFree(gline);
+}
+
+/** Burst all known global G-lines to another server.
+ * @param[in] cptr Destination of burst.
+ */
+void
+gline_burst(struct Client *cptr)
+{
+  struct Gline *gline;
+  struct Gline *sgline;
+
+#ifdef OLD_OGN_IRCU_COMPAT
+  gliter(GlobalGlineList, gline, sgline) {
+    if (!GlineIsLocal(gline) && gline->gl_lastmod)
+      sendcmdto_one(&me, CMD_GLINE, cptr, "* %c%s%s%s %Tu %Tu :%s",
+                   GlineIsRemActive(gline) ? '+' : '-', gline->gl_user,
+                    gline->gl_host ? "@" : "",
+                    gline->gl_host ? gline->gl_host : "",
+                   gline->gl_expire - CurrentTime, gline->gl_lastmod,
+                    /*gline->gl_lifetime,*/ gline->gl_reason);
+  }
+  gliter(BadChanGlineList, gline, sgline) {
+    if (!GlineIsLocal(gline) && gline->gl_lastmod)
+      sendcmdto_one(&me, CMD_GLINE, cptr, "* %c%s %Tu %Tu :%s",
+                   GlineIsRemActive(gline) ? '+' : '-', gline->gl_user,
+                   gline->gl_expire - CurrentTime, gline->gl_lastmod,
+                   /*gline->gl_lifetime,*/ gline->gl_reason);
+  }
+#else
+  gliter(GlobalGlineList, gline, sgline) {
+    if (!GlineIsLocal(gline) && gline->gl_lastmod)
+      sendcmdto_one(&me, CMD_GLINE, cptr, "* %c%s%s%s %Tu %Tu %Tu :%s",
+                   GlineIsRemActive(gline) ? '+' : '-', gline->gl_user,
+                    gline->gl_host ? "@" : "",
+                    gline->gl_host ? gline->gl_host : "",
+                   gline->gl_expire - CurrentTime, gline->gl_lastmod,
+                    gline->gl_lifetime, gline->gl_reason);
+  }
+  gliter(BadChanGlineList, gline, sgline) {
+    if (!GlineIsLocal(gline) && gline->gl_lastmod)
+      sendcmdto_one(&me, CMD_GLINE, cptr, "* %c%s %Tu %Tu %Tu :%s",
+                   GlineIsRemActive(gline) ? '+' : '-', gline->gl_user,
+                   gline->gl_expire - CurrentTime, gline->gl_lastmod,
+                   gline->gl_lifetime, gline->gl_reason);
+  }
+#endif
+}
+
+/** Send a G-line to another server.
+ * @param[in] cptr Who to inform of the G-line.
+ * @param[in] gline G-line to send.
+ * @return Zero.
+ */
+int
+gline_resend(struct Client *cptr, struct Gline *gline)
+{
+  if (GlineIsLocal(gline) || !gline->gl_lastmod)
+    return 0;
+
+#ifdef OLD_OGN_IRCU_COMPAT
+  sendcmdto_one(&me, CMD_GLINE, cptr, "* %c%s%s%s %Tu %Tu :%s",
+               GlineIsRemActive(gline) ? '+' : '-', gline->gl_user,
+               gline->gl_host ? "@" : "",
+                gline->gl_host ? gline->gl_host : "",
+               gline->gl_expire - CurrentTime, gline->gl_lastmod,
+               /*gline->gl_lifetime,*/ gline->gl_reason);
+#else
+  sendcmdto_one(&me, CMD_GLINE, cptr, "* %c%s%s%s %Tu %Tu %Tu :%s",
+               GlineIsRemActive(gline) ? '+' : '-', gline->gl_user,
+               gline->gl_host ? "@" : "",
+                gline->gl_host ? gline->gl_host : "",
+               gline->gl_expire - CurrentTime, gline->gl_lastmod,
+               gline->gl_lifetime, gline->gl_reason);
+#endif
+
+  return 0;
+}
+
+/** Display one or all G-lines to a user.
+ * If \a userhost is not NULL, only send the first matching G-line.
+ * Otherwise send the whole list.
+ * @param[in] sptr User asking for G-line list.
+ * @param[in] userhost G-line mask to search for (or NULL).
+ * @return Zero.
+ */
+int
+gline_list(struct Client *sptr, char *userhost)
+{
+  struct Gline *gline;
+  struct Gline *sgline;
+
+  if (userhost) {
+    if (!(gline = gline_find(userhost, GLINE_ANY))) /* no such gline */
+      return send_reply(sptr, ERR_NOSUCHGLINE, userhost);
+
+    /* send gline information along */
+    send_reply(sptr, RPL_GLIST, gline->gl_user,
+               gline->gl_host ? "@" : "",
+               gline->gl_host ? gline->gl_host : "",
+              gline->gl_expire + TSoffset, gline->gl_lastmod,
+              gline->gl_lifetime + TSoffset,
+              GlineIsLocal(gline) ? cli_name(&me) : "*",
+              gline->gl_state == GLOCAL_ACTIVATED ? ">" :
+              (gline->gl_state == GLOCAL_DEACTIVATED ? "<" : ""),
+              GlineIsRemActive(gline) ? '+' : '-', gline->gl_reason);
+  } else {
+    gliter(GlobalGlineList, gline, sgline) {
+      send_reply(sptr, RPL_GLIST, gline->gl_user,
+                gline->gl_host ? "@" : "",
+                gline->gl_host ? gline->gl_host : "",
+                gline->gl_expire + TSoffset, gline->gl_lastmod,
+                gline->gl_lifetime + TSoffset,
+                GlineIsLocal(gline) ? cli_name(&me) : "*",
+                gline->gl_state == GLOCAL_ACTIVATED ? ">" :
+                (gline->gl_state == GLOCAL_DEACTIVATED ? "<" : ""),
+                GlineIsRemActive(gline) ? '+' : '-', gline->gl_reason);
+    }
+
+    gliter(BadChanGlineList, gline, sgline) {
+      send_reply(sptr, RPL_GLIST, gline->gl_user, "", "",
+                gline->gl_expire + TSoffset, gline->gl_lastmod,
+                gline->gl_lifetime + TSoffset,
+                GlineIsLocal(gline) ? cli_name(&me) : "*",
+                gline->gl_state == GLOCAL_ACTIVATED ? ">" :
+                (gline->gl_state == GLOCAL_DEACTIVATED ? "<" : ""),
+                GlineIsRemActive(gline) ? '+' : '-', gline->gl_reason);
+    }
+  }
+
+  /* end of gline information */
+  return send_reply(sptr, RPL_ENDOFGLIST);
+}
+
+/** Statistics callback to list G-lines.
+ * @param[in] sptr Client requesting statistics.
+ * @param[in] sd Stats descriptor for request (ignored).
+ * @param[in] param Extra parameter from user (ignored).
+ */
+void
+gline_stats(struct Client *sptr, const struct StatDesc *sd,
+            char *param)
+{
+  struct Gline *gline;
+  struct Gline *sgline;
+
+  gliter(GlobalGlineList, gline, sgline) {
+    send_reply(sptr, RPL_STATSGLINE, 'G', gline->gl_user,
+              gline->gl_host ? "@" : "",
+              gline->gl_host ? gline->gl_host : "",
+              gline->gl_expire + TSoffset, gline->gl_lastmod,
+              gline->gl_lifetime + TSoffset,
+              gline->gl_state == GLOCAL_ACTIVATED ? ">" :
+              (gline->gl_state == GLOCAL_DEACTIVATED ? "<" : ""),
+              GlineIsRemActive(gline) ? '+' : '-',
+              gline->gl_reason);
+  }
+}
+
+/** Calculate memory used by G-lines.
+ * @param[out] gl_size Number of bytes used by G-lines.
+ * @return Number of G-lines in use.
+ */
+int
+gline_memory_count(size_t *gl_size)
+{
+  struct Gline *gline;
+  unsigned int gl = 0;
+
+  for (gline = GlobalGlineList; gline; gline = gline->gl_next) {
+    gl++;
+    *gl_size += sizeof(struct Gline);
+    *gl_size += gline->gl_user ? (strlen(gline->gl_user) + 1) : 0;
+    *gl_size += gline->gl_host ? (strlen(gline->gl_host) + 1) : 0;
+    *gl_size += gline->gl_reason ? (strlen(gline->gl_reason) + 1) : 0;
+  }
+
+  for (gline = BadChanGlineList; gline; gline = gline->gl_next) {
+    gl++;
+    *gl_size += sizeof(struct Gline);
+    *gl_size += gline->gl_user ? (strlen(gline->gl_user) + 1) : 0;
+    *gl_size += gline->gl_host ? (strlen(gline->gl_host) + 1) : 0;
+    *gl_size += gline->gl_reason ? (strlen(gline->gl_reason) + 1) : 0;
+  }
+
+  return gl;
+}
diff --git a/ircd/hash.c b/ircd/hash.c
new file mode 100644 (file)
index 0000000..a862a59
--- /dev/null
@@ -0,0 +1,485 @@
+/*
+ * IRC - Internet Relay Chat, ircd/hash.c
+ * Copyright (C) 1998 Andrea Cocito, completely rewritten version.
+ * Previous version was Copyright (C) 1991 Darren Reed, the concept
+ * of linked lists for each hash bucket and the move-to-head 
+ * optimization has been borrowed from there.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#include "config.h"
+
+#include "hash.h"
+#include "client.h"
+#include "channel.h"
+#include "ircd_alloc.h"
+#include "ircd_chattr.h"
+#include "ircd_log.h"
+#include "ircd_reply.h"
+#include "ircd_string.h"
+#include "ircd.h"
+#include "match.h"
+#include "msg.h"
+#include "numeric.h"
+#include "random.h"
+#include "s_debug.h"
+#include "send.h"
+#include "struct.h"
+#include "sys.h"
+
+/* #include <assert.h> -- Now using assert in ircd_log.h */
+#include <limits.h>
+#include <stdlib.h>
+#include <string.h>
+
+
+/** @file
+ * @brief Hash table management.
+ * @version $Id: hash.c 1841 2007-11-05 03:01:34Z entrope $
+ *
+ * This file used to use some very complicated hash function.  Now it
+ * uses CRC-32, but effectively remaps each input byte according to a
+ * table initialized at startup.
+ */
+
+/** Hash table for clients. */
+static struct Client *clientTable[HASHSIZE];
+/** Hash table for channels. */
+static struct Channel *channelTable[HASHSIZE];
+/** CRC-32 update table. */
+static uint32_t crc32hash[256];
+
+/** Initialize the map used by the hash function. */
+void init_hash(void)
+{
+  unsigned int ii, jj, rand, poly;
+
+  /* First calculate a normal CRC-32 table. */
+  for (ii = 0, poly = 0xedb88320; ii < 256; ii++)
+  {
+    rand = ii;
+    for (jj = 0; jj < 8; jj++)
+      rand = (rand & 1) ? poly ^ (rand >> 1) : rand >> 1;
+    crc32hash[ii] = rand;
+  }
+
+  /* Now reorder the hash table. */
+  for (ii = 0, rand = 0; ii < 256; ii++)
+  {
+    if (!rand)
+      rand = ircrandom();
+    poly = ii + rand % (256 - ii);
+    jj = crc32hash[ii];
+    crc32hash[ii] = crc32hash[poly];
+    crc32hash[poly] = jj;
+    rand >>= 8;
+  }
+}
+
+/** Output type of hash function. */
+typedef unsigned int HASHREGS;
+
+/** Calculate hash value for a string.
+ * @param[in] n String to hash.
+ * @return Hash value for string.
+ */
+static HASHREGS strhash(const char *n)
+{
+  HASHREGS hash = crc32hash[ToLower(*n++) & 255];
+  while (*n)
+    hash = (hash >> 8) ^ crc32hash[(hash ^ ToLower(*n++)) & 255];
+  return hash % HASHSIZE;
+}
+
+/************************** Externally visible functions ********************/
+
+/* Optimization note: in these functions I supposed that the CSE optimization
+ * (Common Subexpression Elimination) does its work decently, this means that
+ * I avoided introducing new variables to do the work myself and I did let
+ * the optimizer play with more free registers, actual tests proved this
+ * solution to be faster than doing things like tmp2=tmp->hnext... and then
+ * use tmp2 myself which would have given less freedom to the optimizer.
+ */
+
+/** Prepend a client to the appropriate hash bucket.
+ * @param[in] cptr Client to add to hash table.
+ * @return Zero.
+ */
+int hAddClient(struct Client *cptr)
+{
+  HASHREGS hashv = strhash(cli_name(cptr));
+
+  cli_hnext(cptr) = clientTable[hashv];
+  clientTable[hashv] = cptr;
+
+  return 0;
+}
+
+/** Prepend a channel to the appropriate hash bucket.
+ * @param[in] chptr Channel to add to hash table.
+ * @return Zero.
+ */
+int hAddChannel(struct Channel *chptr)
+{
+  HASHREGS hashv = strhash(chptr->chname);
+
+  chptr->hnext = channelTable[hashv];
+  channelTable[hashv] = chptr;
+
+  return 0;
+}
+
+/** Remove a client from its hash bucket.
+ * @param[in] cptr Client to remove from hash table.
+ * @return Zero if the client is found and removed, -1 if not found.
+ */
+int hRemClient(struct Client *cptr)
+{
+  HASHREGS hashv = strhash(cli_name(cptr));
+  struct Client *tmp = clientTable[hashv];
+
+  if (tmp == cptr) {
+    clientTable[hashv] = cli_hnext(cptr);
+    cli_hnext(cptr) = cptr;
+    return 0;
+  }
+
+  while (tmp) {
+    if (cli_hnext(tmp) == cptr) {
+      cli_hnext(tmp) = cli_hnext(cli_hnext(tmp));
+      cli_hnext(cptr) = cptr;
+      return 0;
+    }
+    tmp = cli_hnext(tmp);
+  }
+  return -1;
+}
+
+/** Rename a client in the hash table.
+ * @param[in] cptr Client whose nickname is changing.
+ * @param[in] newname New nickname for client.
+ * @return Zero.
+ */
+int hChangeClient(struct Client *cptr, const char *newname)
+{
+  HASHREGS newhash = strhash(newname);
+
+  assert(0 != cptr);
+  hRemClient(cptr);
+
+  cli_hnext(cptr) = clientTable[newhash];
+  clientTable[newhash] = cptr;
+  return 0;
+}
+
+/** Remove a channel from its hash bucket.
+ * @param[in] chptr Channel to remove from hash table.
+ * @return Zero if the channel is found and removed, -1 if not found.
+ */
+int hRemChannel(struct Channel *chptr)
+{
+  HASHREGS hashv = strhash(chptr->chname);
+  struct Channel *tmp = channelTable[hashv];
+
+  if (tmp == chptr) {
+    channelTable[hashv] = chptr->hnext;
+    chptr->hnext = chptr;
+    return 0;
+  }
+
+  while (tmp) {
+    if (tmp->hnext == chptr) {
+      tmp->hnext = tmp->hnext->hnext;
+      chptr->hnext = chptr;
+      return 0;
+    }
+    tmp = tmp->hnext;
+  }
+
+  return -1;
+}
+
+/** Find a client by name, filtered by status mask.
+ * If a client is found, it is moved to the top of its hash bucket.
+ * @param[in] name Client name to search for.
+ * @param[in] TMask Bitmask of status bits, any of which are needed to match.
+ * @return Matching client, or NULL if none.
+ */
+struct Client* hSeekClient(const char *name, int TMask)
+{
+  HASHREGS hashv      = strhash(name);
+  struct Client *cptr = clientTable[hashv];
+
+  if (cptr) {
+    if (0 == (cli_status(cptr) & TMask) || 0 != ircd_strcmp(name, cli_name(cptr))) {
+      struct Client* prev;
+      while (prev = cptr, cptr = cli_hnext(cptr)) {
+        if ((cli_status(cptr) & TMask) && (0 == ircd_strcmp(name, cli_name(cptr)))) {
+          cli_hnext(prev) = cli_hnext(cptr);
+          cli_hnext(cptr) = clientTable[hashv];
+          clientTable[hashv] = cptr;
+          break;
+        }
+      }
+    }
+  }
+  return cptr;
+}
+
+/** Find a channel by name.
+ * If a channel is found, it is moved to the top of its hash bucket.
+ * @param[in] name Channel name to search for.
+ * @return Matching channel, or NULL if none.
+ */
+struct Channel* hSeekChannel(const char *name)
+{
+  HASHREGS hashv = strhash(name);
+  struct Channel *chptr = channelTable[hashv];
+
+  if (chptr) {
+    if (0 != ircd_strcmp(name, chptr->chname)) {
+      struct Channel* prev;
+      while (prev = chptr, chptr = chptr->hnext) {
+        if (0 == ircd_strcmp(name, chptr->chname)) {
+          prev->hnext = chptr->hnext;
+          chptr->hnext = channelTable[hashv];
+          channelTable[hashv] = chptr;
+          break;
+        }
+      }
+    }
+  }
+  return chptr;
+
+}
+
+/* I will add some useful(?) statistics here one of these days,
+   but not for DEBUGMODE: just to let the admins play with it,
+   coders are able to SIGCORE the server and look into what goes
+   on themselves :-) */
+
+/** Report hash table statistics to a client.
+ * @param[in] cptr Client that sent us this message.
+ * @param[in] sptr Client that originated the message.
+ * @param[in] parc Number of arguments.
+ * @param[in] parv Argument array.
+ * @return Zero.
+ */
+int m_hash(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
+{
+  int max_chain = 0;
+  int buckets   = 0;
+  int count     = 0;
+  struct Client*  cl;
+  struct Channel* ch;
+  int i;
+  
+  sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :Hash Table Statistics", sptr);
+
+  for (i = 0; i < HASHSIZE; ++i) {
+    if ((cl = clientTable[i])) {
+      int len = 0;
+      ++buckets;
+      for ( ; cl; cl = cli_hnext(cl))
+        ++len; 
+      if (len > max_chain)
+        max_chain = len;
+      count += len;
+    }
+  } 
+
+  sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :Client: entries: %d buckets: %d "
+               "max chain: %d", sptr, count, buckets, max_chain);
+
+  buckets = 0;
+  count   = 0;
+  max_chain = 0;
+
+  for (i = 0; i < HASHSIZE; ++i) {
+    if ((ch = channelTable[i])) {
+      int len = 0;
+      ++buckets;
+      for ( ; ch; ch = ch->hnext)
+        ++len; 
+      if (len > max_chain)
+        max_chain = len;
+      count += len;
+    }
+  } 
+
+  sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :Channel: entries: %d buckets: %d "
+               "max chain: %d", sptr, count, buckets, max_chain);
+  return 0;
+}
+
+/* Nick jupe utilities, these are in a static hash table with entry/bucket
+   ratio of one, collision shift up and roll in a circular fashion, the 
+   lowest 12 bits of the hash value are used, deletion is not supported,
+   only addition, test for existence and cleanup of the table are.. */
+
+/** Number of bits in jupe hash value. */
+#define JUPEHASHBITS 12         /* 4096 entries, 64 nick jupes allowed */
+/** Size of jupe hash table. */
+#define JUPEHASHSIZE (1<<JUPEHASHBITS)
+/** Bitmask to select into jupe hash table. */
+#define JUPEHASHMASK (JUPEHASHSIZE-1)
+/** Maximum number of jupes allowed. */
+#define JUPEMAX      (1<<(JUPEHASHBITS-6))
+
+/** Hash table for jupes. */
+static char jupeTable[JUPEHASHSIZE][NICKLEN + 1];       /* About 40k */
+/** Count of jupes. */
+static int jupesCount;
+
+/** Check whether a nickname is juped.
+ * @param[in] nick Nickname to check.
+ * @return Non-zero of the nickname is juped, zero if not.
+ */
+int isNickJuped(const char *nick)
+{
+  int pos;
+
+  if (nick && *nick) {
+    //for (pos = strhash(nick); (pos &= JUPEHASHMASK), jupeTable[pos][0]; pos++) {
+      for (pos = 0; pos < JUPEHASHSIZE; pos++) {
+      //if (0 == ircd_strcmp(nick, jupeTable[pos]))
+      //Debug((DEBUG_DEBUG, "NickJupe match: %s %s %i",jupeTable[pos], nick, match(jupeTable[pos], nick)));
+      if (0 == match(jupeTable[pos], nick))
+        return 1;
+    }
+  }
+  return 0;                     /* A bogus pointer is NOT a juped nick, right ? :) */
+}
+
+/** Add a comma-separated list of nick jupes.
+ * @param[in] nicks List of nicks to jupe, separated by commas.
+ * @return Zero on success, non-zero on error.
+ */
+int addNickJupes(const char *nicks)
+{
+  static char temp[BUFSIZE + 1];
+  char* one;
+  char* p;
+  int   pos;
+
+  if (nicks && *nicks)
+  {
+    ircd_strncpy(temp, nicks, BUFSIZE);
+    temp[BUFSIZE] = '\0';
+    p = NULL;
+    for (one = ircd_strtok(&p, temp, ","); one; one = ircd_strtok(&p, NULL, ","))
+    {
+      if (!*one)
+        continue;
+      pos = strhash(one);
+loop:
+      pos &= JUPEHASHMASK;
+      if (!jupeTable[pos][0])
+      {
+        if (jupesCount == JUPEMAX)
+          return 1;             /* Error: Jupe table is full ! */
+        jupesCount++;
+        ircd_strncpy(jupeTable[pos], one, NICKLEN);
+        jupeTable[pos][NICKLEN] = '\000';       /* Better safe than sorry :) */
+        continue;
+      }
+      if (0 == ircd_strcmp(one, jupeTable[pos]))
+        continue;
+      ++pos;
+      goto loop;
+    }
+  }
+  return 0;
+}
+
+/** Empty the table of juped nicknames. */
+void clearNickJupes(void)
+{
+  int i;
+  jupesCount = 0;
+  for (i = 0; i < JUPEHASHSIZE; i++)
+    jupeTable[i][0] = '\000';
+}
+
+/** Report all nick jupes to a user.
+ * @param[in] to Client requesting statistics.
+ * @param[in] sd Stats descriptor for request (ignored).
+ * @param[in] param Extra parameter from user (ignored).
+ */
+void
+stats_nickjupes(struct Client* to, const struct StatDesc* sd, char* param)
+{
+  int i;
+  for (i = 0; i < JUPEHASHSIZE; i++)
+    if (jupeTable[i][0])
+      send_reply(to, RPL_STATSJLINE, jupeTable[i]);
+}
+
+/** Send more channels to a client in mid-LIST.
+ * @param[in] cptr Client to send the list to.
+ */
+void list_next_channels(struct Client *cptr)
+{
+  struct ListingArgs *args;
+  struct Channel *chptr;
+
+  /* Walk consecutive buckets until we hit the end. */
+  for (args = cli_listing(cptr); args->bucket < HASHSIZE; args->bucket++)
+  {
+    /* Send all the matching channels in the bucket. */
+    for (chptr = channelTable[args->bucket]; chptr; chptr = chptr->hnext)
+    {
+      if (chptr->users > args->min_users
+          && chptr->users < args->max_users
+          && chptr->creationtime > args->min_time
+          && chptr->creationtime < args->max_time
+          && (!args->wildcard[0] || (args->flags & LISTARG_NEGATEWILDCARD) ||
+              (!match(args->wildcard, chptr->chname)))
+          && (!(args->flags & LISTARG_NEGATEWILDCARD) ||
+              match(args->wildcard, chptr->chname))
+          && (!(args->flags & LISTARG_TOPICLIMITS)
+              || (chptr->topic[0]
+                  && chptr->topic_time > args->min_topic_time
+                  && chptr->topic_time < args->max_topic_time))
+          && ((args->flags & LISTARG_SHOWSECRET)
+              || ShowChannel(cptr, chptr)))
+      {
+        if (args->flags & LISTARG_SHOWMODES) {
+          char modebuf[MODEBUFLEN];
+          char parabuf[MODEBUFLEN];
+
+          modebuf[0] = modebuf[1] = parabuf[0] = '\0';
+          channel_modes(cptr, modebuf, parabuf, sizeof(parabuf), chptr, NULL);
+          send_reply(cptr, RPL_LIST | SND_EXPLICIT, "%s %u %s %s :%s",
+                     chptr->chname, chptr->users, modebuf, parabuf, chptr->topic);
+        } else {
+          send_reply(cptr, RPL_LIST, chptr->chname, chptr->users, chptr->topic);
+        }
+      }
+    }
+    /* If, at the end of the bucket, client sendq is more than half
+     * full, stop. */
+    if (MsgQLength(&cli_sendQ(cptr)) > cli_max_sendq(cptr) / 2)
+      break;
+  }
+
+  /* If we did all buckets, clean the client and send RPL_LISTEND. */
+  if (args->bucket >= HASHSIZE)
+  {
+    MyFree(cli_listing(cptr));
+    cli_listing(cptr) = NULL;
+    send_reply(cptr, RPL_LISTEND);
+  }
+}
diff --git a/ircd/ircd.c b/ircd/ircd.c
new file mode 100644 (file)
index 0000000..693ac88
--- /dev/null
@@ -0,0 +1,770 @@
+/*
+ * IRC - Internet Relay Chat, ircd/ircd.c
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ *                    University of Oulu, Computing Center
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+/** @file
+ * @brief Entry point and other initialization functions for the daemon.
+ * @version $Id: ircd.c 1907 2009-02-09 04:11:04Z entrope $
+ */
+#include "config.h"
+
+#include "ircd.h"
+#include "IPcheck.h"
+#include "class.h"
+#include "client.h"
+#include "crule.h"
+#include "destruct_event.h"
+#include "hash.h"
+#include "ircd_alloc.h"
+#include "ircd_events.h"
+#include "ircd_features.h"
+#include "ircd_log.h"
+#include "ircd_reply.h"
+#include "ircd_signal.h"
+#include "ircd_string.h"
+#include "ircd_crypt.h"
+#include "jupe.h"
+#include "list.h"
+#include "match.h"
+#include "motd.h"
+#include "msg.h"
+#include "numeric.h"
+#include "numnicks.h"
+#include "opercmds.h"
+#include "parse.h"
+#include "res.h"
+#include "s_auth.h"
+#include "s_bsd.h"
+#include "s_conf.h"
+#include "s_debug.h"
+#include "s_misc.h"
+#include "s_stats.h"
+#include "send.h"
+#include "ssl.h"
+#include "sys.h"
+#include "uping.h"
+#include "userload.h"
+#include "version.h"
+#include "whowas.h"
+
+/* #include <assert.h> -- Now using assert in ircd_log.h */
+#include <errno.h>
+#include <fcntl.h>
+#include <netdb.h>
+#include <pwd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/time.h>
+#ifdef HAVE_SYS_RESOURCE_H
+#include <sys/resource.h>
+#endif
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+
+
+/*----------------------------------------------------------------------------
+ * External stuff
+ *--------------------------------------------------------------------------*/
+extern void init_counters(void);
+extern void mem_dbg_initialise(void);
+
+/*----------------------------------------------------------------------------
+ * Constants / Enums
+ *--------------------------------------------------------------------------*/
+enum {
+  BOOT_DEBUG = 1,  /**< Enable debug output. */
+  BOOT_TTY   = 2,  /**< Stay connected to TTY. */
+  BOOT_CHKCONF = 4 /**< Exit after reading configuration file. */
+};
+
+
+/*----------------------------------------------------------------------------
+ * Global data (YUCK!)
+ *--------------------------------------------------------------------------*/
+struct Client  me;                      /**< That's me */
+struct Connection me_con;              /**< That's me too */
+struct Client *GlobalClientList  = &me; /**< Pointer to beginning of
+                                          Client list */
+time_t         TSoffset          = 0;   /**< Offset of timestamps to system clock */
+int            GlobalRehashFlag  = 0;   /**< do a rehash if set */
+int            GlobalRestartFlag = 0;   /**< do a restart if set */
+time_t         CurrentTime;             /**< Updated every time we leave select() */
+
+char          *configfile        = CPATH; /**< Server configuration file */
+int            debuglevel        = -1;    /**< Server debug level  */
+char          *debugmode         = "";    /**< Server debug level */
+char          *dpath             = DPATH; /**< Working directory for daemon */
+static char   *dbg_client;                /**< Client specifier for chkconf */
+
+static struct Timer connect_timer; /**< timer structure for try_connections() */
+static struct Timer ping_timer; /**< timer structure for check_pings() */
+static struct Timer destruct_event_timer; /**< timer structure for exec_expired_destruct_events() */
+
+/** Daemon information. */
+static struct Daemon thisServer  = { 0, 0, 0, 0, 0, 0, -1 };
+
+/** Non-zero until we want to exit. */
+int running = 1;
+
+
+/*----------------------------------------------------------------------------
+ * API: server_die
+ *--------------------------------------------------------------------------*/
+/** Terminate the server with a message.
+ * @param[in] message Message to log and send to operators.
+ */
+void server_die(const char *message)
+{
+  /* log_write will send out message to both log file and as server notice */
+  log_write(LS_SYSTEM, L_CRIT, 0, "Server terminating: %s", message);
+  flush_connections(0);
+  close_connections(1);
+  running = 0;
+}
+
+/*----------------------------------------------------------------------------
+ * API: server_panic
+ *--------------------------------------------------------------------------*/
+/** Immediately terminate the server with a message.
+ * @param[in] message Message to log, but not send to operators.
+ */
+void server_panic(const char *message)
+{
+  /* inhibit sending server notice--we may be panicking due to low memory */
+  log_write(LS_SYSTEM, L_CRIT, LOG_NOSNOTICE, "Server panic: %s", message);
+  flush_connections(0);
+  log_close();
+  close_connections(1);
+  exit(1);
+}
+
+/*----------------------------------------------------------------------------
+ * API: server_restart
+ *--------------------------------------------------------------------------*/
+/** Restart the server with a message.
+ * @param[in] message Message to log and send to operators.
+ */
+void server_restart(const char *message)
+{
+  static int restarting = 0;
+
+  /* inhibit sending any server notices; we may be in a loop */
+  log_write(LS_SYSTEM, L_WARNING, LOG_NOSNOTICE, "Restarting Server: %s",
+           message);
+  if (restarting++) /* increment restarting to prevent looping */
+    return;
+
+  sendto_opmask_butone(0, SNO_OLDSNO, "Restarting server: %s", message);
+  Debug((DEBUG_NOTICE, "Restarting server..."));
+  flush_connections(0);
+
+  log_close();
+
+  close_connections(!(thisServer.bootopt & (BOOT_TTY | BOOT_DEBUG | BOOT_CHKCONF)));
+
+  reap_children();
+
+  execv(SPATH, thisServer.argv);
+
+  /* Have to reopen since it has been closed above */
+  log_reopen();
+
+  log_write(LS_SYSTEM, L_CRIT, 0, "execv(%s,%s) failed: %m", SPATH,
+           *thisServer.argv);
+
+  Debug((DEBUG_FATAL, "Couldn't restart server \"%s\": %s",
+         SPATH, (strerror(errno)) ? strerror(errno) : ""));
+  exit(8);
+}
+
+
+/*----------------------------------------------------------------------------
+ * outofmemory:  Handler for out of memory conditions...
+ *--------------------------------------------------------------------------*/
+/** Handle out-of-memory condition. */
+static void outofmemory(void) {
+  Debug((DEBUG_FATAL, "Out of memory: restarting server..."));
+  server_restart("Out of Memory");
+}
+
+
+/*----------------------------------------------------------------------------
+ * write_pidfile
+ *--------------------------------------------------------------------------*/
+/** Write process ID to PID file. */
+static void write_pidfile(void) {
+  char buff[20];
+
+  if (thisServer.pid_fd >= 0) {
+    memset(buff, 0, sizeof(buff));
+    sprintf(buff, "%5d\n", (int)getpid());
+    if (write(thisServer.pid_fd, buff, strlen(buff)) == -1)
+      Debug((DEBUG_NOTICE, "Error writing to pid file %s: %m",
+            feature_str(FEAT_PPATH)));
+    return;
+  }
+  Debug((DEBUG_NOTICE, "Error opening pid file %s: %m",
+        feature_str(FEAT_PPATH)));
+}
+
+/** Try to create the PID file.
+ * @return Zero on success; non-zero on any error.
+ */
+static int check_pid(void)
+{
+  struct flock lock;
+
+  lock.l_type = F_WRLCK;
+  lock.l_start = 0;
+  lock.l_whence = SEEK_SET;
+  lock.l_len = 0;
+
+  if ((thisServer.pid_fd = open(feature_str(FEAT_PPATH), O_CREAT | O_RDWR,
+                               0600)) >= 0)
+    return fcntl(thisServer.pid_fd, F_SETLK, &lock) == -1;
+
+  return 1;
+}
+
+
+/** Look for any connections that we should try to initiate.
+ * Reschedules itself to run again at the appropriate time.
+ * @param[in] ev Timer event (ignored).
+ */
+static void try_connections(struct Event* ev) {
+  struct ConfItem*  aconf;
+  struct ConfItem** pconf;
+  time_t            next;
+  struct Jupe*      ajupe;
+  int               hold;
+  int               done;
+
+  assert(ET_EXPIRE == ev_type(ev));
+  assert(0 != ev_timer(ev));
+
+  Debug((DEBUG_NOTICE, "Connection check at   : %s", myctime(CurrentTime)));
+  next = CurrentTime + feature_int(FEAT_CONNECTFREQUENCY);
+  done = 0;
+
+  for (aconf = GlobalConfList; aconf; aconf = aconf->next) {
+    /* Only consider server items with non-zero port and non-zero
+     * connect times that are not actively juped.
+     */
+    if (!(aconf->status & CONF_SERVER)
+        || aconf->address.port == 0
+        || !(aconf->flags & CONF_AUTOCONNECT)
+        || ((ajupe = jupe_find(aconf->name)) && JupeIsActive(ajupe)))
+      continue;
+
+    /* Do we need to postpone this connection further? */
+    hold = aconf->hold > CurrentTime;
+
+    /* Update next possible connection check time. */
+    if (hold && next > aconf->hold)
+        next = aconf->hold;
+
+    /* Do not try to connect if its use is still on hold until future,
+     * we have already initiated a connection this try_connections(),
+     * too many links in its connection class, it is already linked,
+     * or if connect rules forbid a link now.
+     */
+    if (hold || done
+        || (ConfLinks(aconf) > ConfMaxLinks(aconf))
+        || FindServer(aconf->name)
+        || conf_eval_crule(aconf->name, CRULE_MASK))
+      continue;
+
+    /* Ensure it is at the end of the list for future checks. */
+    if (aconf->next) {
+      /* Find aconf's location in the list and splice it out. */
+      for (pconf = &GlobalConfList; *pconf; pconf = &(*pconf)->next)
+        if (*pconf == aconf)
+          *pconf = aconf->next;
+      /* Reinsert it at the end of the list (where pconf is now). */
+      *pconf = aconf;
+      aconf->next = 0;
+    }
+
+    /* Activate the connection itself. */
+    if (connect_server(aconf, 0))
+      sendto_opmask_butone(0, SNO_OLDSNO, "Connection to %s activated.",
+                          aconf->name);
+
+    /* And stop looking for further candidates. */
+    done = 1;
+  }
+
+  Debug((DEBUG_NOTICE, "Next connection check : %s", myctime(next)));
+  timer_add(&connect_timer, try_connections, 0, TT_ABSOLUTE, next);
+}
+
+
+/** Check for clients that have not sent a ping response recently.
+ * Reschedules itself to run again at the appropriate time.
+ * @param[in] ev Timer event (ignored).
+ */
+static void check_pings(struct Event* ev) {
+  int expire     = 0;
+  int next_check = CurrentTime;
+  int max_ping   = 0;
+  int i;
+
+  assert(ET_EXPIRE == ev_type(ev));
+  assert(0 != ev_timer(ev));
+
+  next_check += feature_int(FEAT_PINGFREQUENCY);
+  
+  /* Scan through the client table */
+  for (i=0; i <= HighestFd; i++) {
+    struct Client *cptr = LocalClientArray[i];
+   
+    if (!cptr)
+      continue;
+     
+    assert(&me != cptr);  /* I should never be in the local client array! */
+   
+
+    /* Remove dead clients. */
+    if (IsDead(cptr)) {
+      exit_client(cptr, cptr, &me, cli_info(cptr));
+      continue;
+    }
+
+    max_ping = IsRegistered(cptr) ? client_get_ping(cptr) :
+      feature_int(FEAT_CONNECTTIMEOUT);
+   
+    Debug((DEBUG_DEBUG, "check_pings(%s)=status:%s limit: %d current: %d",
+          cli_name(cptr),
+          IsPingSent(cptr) ? "[Ping Sent]" : "[]", 
+          max_ping, (int)(CurrentTime - cli_lasttime(cptr))));
+
+    /* If it's a server and we have not sent an AsLL lately, do so. */
+    if (IsServer(cptr)) {
+      if (CurrentTime - cli_serv(cptr)->asll_last >= max_ping) {
+        char *asll_ts;
+
+        SetPingSent(cptr);
+        cli_serv(cptr)->asll_last = CurrentTime;
+        expire = cli_serv(cptr)->asll_last + max_ping;
+        asll_ts = militime_float(NULL);
+        sendcmdto_prio_one(&me, CMD_PING, cptr, "!%s %s %s", asll_ts,
+                           cli_name(cptr), asll_ts);
+      }
+
+      expire = cli_serv(cptr)->asll_last + max_ping;
+      if (expire < next_check)
+        next_check = expire;
+    }
+
+    /* Ok, the thing that will happen most frequently, is that someone will
+     * have sent something recently.  Cover this first for speed.
+     * -- 
+     * If it's an unregistered client and hasn't managed to register within
+     * max_ping then it's obviously having problems (broken client) or it's
+     * just up to no good, so we won't skip it, even if its been sending
+     * data to us. 
+     * -- hikari
+     */
+    if ((CurrentTime-cli_lasttime(cptr) < max_ping) && IsRegistered(cptr)) {
+      expire = cli_lasttime(cptr) + max_ping;
+      if (expire < next_check) 
+       next_check = expire;
+      continue;
+    }
+
+    /* Unregistered clients pingout after max_ping seconds, they don't
+     * get given a second chance - if they were then people could not quite
+     * finish registration and hold resources without being subject to k/g
+     * lines
+     */
+    if (!IsRegistered(cptr)) {
+      assert(!IsServer(cptr));
+      /* If client authorization time has expired, ask auth whether they
+       * should be checked again later. */
+      if ((CurrentTime-cli_firsttime(cptr) >= max_ping)
+          && auth_ping_timeout(cptr))
+        continue;
+      /* OK, they still have enough time left, so we'll just skip to the
+       * next client.  Set the next check to be when their time is up, if
+       * that's before the currently scheduled next check -- hikari */
+      expire = cli_firsttime(cptr) + max_ping;
+      if (expire < next_check)
+        next_check = expire;
+      continue;
+    }
+
+    /* Quit the client after max_ping*2 - they should have answered by now */
+    if (CurrentTime-cli_lasttime(cptr) >= (max_ping*2) )
+    {
+      /* If it was a server, then tell ops about it. */
+      if (IsServer(cptr) || IsConnecting(cptr) || IsHandshake(cptr))
+        sendto_opmask_butone(0, SNO_OLDSNO,
+                             "No response from %s, closing link",
+                             cli_name(cptr));
+      exit_client_msg(cptr, cptr, &me, "Ping timeout");
+      continue;
+    }
+    
+    if (!IsPingSent(cptr))
+    {
+      /* If we haven't PINGed the connection and we haven't heard from it in a
+       * while, PING it to make sure it is still alive.
+       */
+      SetPingSent(cptr);
+
+      /* If we're late in noticing don't hold it against them :) */
+      cli_lasttime(cptr) = CurrentTime - max_ping;
+      
+      if (IsUser(cptr))
+        sendrawto_one(cptr, MSG_PING " :%s", cli_name(&me));
+      else
+        sendcmdto_prio_one(&me, CMD_PING, cptr, ":%s", cli_name(&me));
+    }
+    
+    expire = cli_lasttime(cptr) + max_ping * 2;
+    if (expire < next_check)
+      next_check=expire;
+  }
+  
+  assert(next_check >= CurrentTime);
+  
+  Debug((DEBUG_DEBUG, "[%i] check_pings() again in %is",
+        CurrentTime, next_check-CurrentTime));
+  
+  timer_add(&ping_timer, check_pings, 0, TT_ABSOLUTE, next_check);
+}
+
+
+/** Parse command line arguments.
+ * Global variables are updated to reflect the arguments.
+ * As a side effect, makes sure the process's effective user id is the
+ * same as the real user id.
+ * @param[in] argc Number of arguments on command line.
+ * @param[in,out] argv Command-lne arguments.
+ */
+static void parse_command_line(int argc, char** argv) {
+  const char *options = "d:f:h:nktvx:c:";
+  int opt;
+
+  if (thisServer.euid != thisServer.uid)
+    setuid(thisServer.uid);
+
+  /* Do we really need to sanity check the non-NULLness of optarg?  That's
+   * getopt()'s job...  Removing those... -zs
+   */
+  while ((opt = getopt(argc, argv, options)) != EOF)
+    switch (opt) {
+    case 'k':  thisServer.bootopt |= BOOT_CHKCONF | BOOT_TTY; break;
+    case 'c':  dbg_client = optarg;                    break;
+    case 'n':
+    case 't':  thisServer.bootopt |= BOOT_TTY;         break;
+    case 'd':  dpath      = optarg;                    break;
+    case 'f':  configfile = optarg;                    break;
+    case 'h':  ircd_strncpy(cli_name(&me), optarg, HOSTLEN); break;
+    case 'v':
+      printf("ircd %s\n", version);
+      printf("Event engines: ");
+#ifdef USE_KQUEUE
+      printf("kqueue() ");
+#endif
+#ifdef USE_DEVPOLL
+      printf("/dev/poll ");
+#endif
+#ifdef USE_EPOLL
+      printf("epoll_*() ");
+#endif
+#ifdef USE_POLL
+      printf("poll()");
+#else
+      printf("select()");
+#endif
+      printf("\nCompiled for a maximum of %d connections.\n", MAXCONNECTIONS);
+
+
+      exit(0);
+      break;
+
+    case 'x':
+      debuglevel = atoi(optarg);
+      if (debuglevel < 0)
+       debuglevel = 0;
+      debugmode = optarg;
+      thisServer.bootopt |= BOOT_DEBUG;
+#ifndef DEBUGMODE
+      printf("WARNING: DEBUGMODE disabled; -x has no effect.\n");
+#endif
+      break;
+
+    default:
+      printf("Usage: ircd [-f config] [-h servername] [-x loglevel] [-ntv] [-k [-c clispec]]\n"
+             "\n -f config\t specify explicit configuration file"
+             "\n -x loglevel\t set debug logging verbosity"
+             "\n -n or -t\t don't detach"
+             "\n -v\t\t display version"
+             "\n -k\t\t exit after checking config"
+             "\n -c clispec\t search for client/kill blocks matching client"
+             "\n\t\t clispec is comma-separated list of user@host,"
+             "\n\t\t user@ip, $Rrealname, and port number"
+             "\n\nServer not started.\n");
+      exit(1);
+    }
+}
+
+
+/** Become a daemon.
+ * @param[in] no_fork If non-zero, do not fork into the background.
+ */
+static void daemon_init(int no_fork) {
+  if (no_fork)
+    return;
+
+  if (fork())
+    exit(0);
+
+#ifdef TIOCNOTTY
+  {
+    int fd;
+    if ((fd = open("/dev/tty", O_RDWR)) > -1) {
+      ioctl(fd, TIOCNOTTY, 0);
+      close(fd);
+    }
+  }
+#endif
+
+  setsid();
+}
+
+/** Check that we have access to a particular file.
+ * If we do not have access to the file, complain on stderr.
+ * @param[in] path File name to check for access.
+ * @param[in] which Configuration character associated with file.
+ * @param[in] mode Bitwise combination of R_OK, W_OK, X_OK and/or F_OK.
+ * @return Non-zero if we have the necessary access, zero if not.
+ */
+static char check_file_access(const char *path, char which, int mode) {
+  if (!access(path, mode))
+    return 1;
+
+  fprintf(stderr, 
+         "Check on %cPATH (%s) failed: %s\n"
+         "Please create this file and/or rerun `configure' "
+         "using --with-%cpath and recompile to correct this.\n",
+         which, path, strerror(errno), which);
+
+  return 0;
+}
+
+
+/*----------------------------------------------------------------------------
+ * set_core_limit
+ *--------------------------------------------------------------------------*/
+#if defined(HAVE_SETRLIMIT) && defined(RLIMIT_CORE)
+/** Set the core size soft limit to the same as the hard limit. */
+static void set_core_limit(void) {
+  struct rlimit corelim;
+
+  if (getrlimit(RLIMIT_CORE, &corelim)) {
+    fprintf(stderr, "Read of rlimit core size failed: %s\n", strerror(errno));
+    corelim.rlim_max = RLIM_INFINITY;   /* Try to recover */
+  }
+
+  corelim.rlim_cur = corelim.rlim_max;
+  if (setrlimit(RLIMIT_CORE, &corelim))
+    fprintf(stderr, "Setting rlimit core size failed: %s\n", strerror(errno));
+}
+#endif
+
+
+
+/** Complain to stderr if any user or group ID belongs to the superuser.
+ * @return Non-zero if all IDs are okay, zero if some are 0.
+ */
+static int set_userid_if_needed(void) {
+  if (getuid() == 0 || geteuid() == 0 ||
+      getgid() == 0 || getegid() == 0) {
+    fprintf(stderr, "ERROR:  This server will not run as superuser.\n");
+    return 0;
+  }
+
+  return 1;
+}
+
+
+/*----------------------------------------------------------------------------
+ * main - entrypoint
+ *
+ * TODO:  This should set the basic environment up and start the main loop.
+ *        we're doing waaaaaaaaay too much server initialization here.  I hate
+ *        long and ugly control paths...  -smd
+ *--------------------------------------------------------------------------*/
+/** Run the daemon.
+ * @param[in] argc Number of arguments in \a argv.
+ * @param[in] argv Arguments to program execution.
+ */
+int main(int argc, char **argv) {
+  CurrentTime = time(NULL);
+  printf("Starting IRCu 2.10.12.10 by pk910.\n");
+  printf("you are not allowed to use this version without my permission\n");
+  thisServer.argc = argc;
+  thisServer.argv = argv;
+  thisServer.uid  = getuid();
+  thisServer.euid = geteuid();
+
+#ifdef MDEBUG
+  mem_dbg_initialise();
+#endif
+
+#if defined(HAVE_SETRLIMIT) && defined(RLIMIT_CORE)
+  set_core_limit();
+#endif
+
+  umask(077);                   /* better safe than sorry --SRB */
+  memset(&me, 0, sizeof(me));
+  memset(&me_con, 0, sizeof(me_con));
+  cli_connect(&me) = &me_con;
+  cli_fd(&me) = -1;
+
+  parse_command_line(argc, argv);
+
+  if (chdir(dpath)) {
+    fprintf(stderr, "Fail: Cannot chdir(%s): %s, check DPATH\n", dpath, strerror(errno));
+    return 2;
+  }
+
+  if (!set_userid_if_needed())
+    return 3;
+
+  /* Check paths for accessibility */
+  if (!check_file_access(SPATH, 'S', X_OK) ||
+      !check_file_access(configfile, 'C', R_OK))
+    return 4;
+
+  if (!init_connection_limits())
+    return 9;
+
+  close_connections(!(thisServer.bootopt & (BOOT_DEBUG | BOOT_TTY | BOOT_CHKCONF)));
+
+  /* daemon_init() must be before event_init() because kqueue() FDs
+   * are, perversely, not inherited across fork().
+   */
+  daemon_init(thisServer.bootopt & BOOT_TTY);
+
+#ifdef DEBUGMODE
+  /* Must reserve fd 2... */
+  if (debuglevel >= 0 && !(thisServer.bootopt & BOOT_TTY)) {
+    int fd;
+    if ((fd = open("/dev/null", O_WRONLY)) < 0) {
+      fprintf(stderr, "Unable to open /dev/null (to reserve fd 2): %s\n",
+             strerror(errno));
+      return 8;
+    }
+    if (fd != 2 && dup2(fd, 2) < 0) {
+      fprintf(stderr, "Unable to reserve fd 2; dup2 said: %s\n",
+             strerror(errno));
+      return 8;
+    }
+  }
+#endif
+
+  event_init(MAXCONNECTIONS);
+
+  setup_signals();
+  feature_init(); /* initialize features... */
+  log_init(*argv);
+  set_nomem_handler(outofmemory);
+
+  initload();
+  init_list();
+  init_hash();
+  init_class();
+  initwhowas();
+  initmsgtree();
+  initstats();
+
+  /* we need this for now, when we're modular this 
+     should be removed -- hikari */
+  ircd_crypt_init();
+
+  motd_init();
+
+  if (!init_conf()) {
+    log_write(LS_SYSTEM, L_CRIT, 0, "Failed to read configuration file %s",
+             configfile);
+    return 7;
+  }
+
+  if (thisServer.bootopt & BOOT_CHKCONF) {
+    if (dbg_client)
+      conf_debug_iline(dbg_client);
+    fprintf(stderr, "Configuration file %s checked okay.\n", configfile);
+    return 0;
+  }
+
+  debug_init(thisServer.bootopt & BOOT_TTY);
+  if (check_pid()) {
+    Debug((DEBUG_FATAL, "Failed to acquire PID file lock after fork"));
+    exit(2);
+  }
+
+  init_server_identity();
+
+  uping_init();
+  ssl_init();
+  stats_init();
+
+  IPcheck_init();
+  timer_add(timer_init(&connect_timer), try_connections, 0, TT_RELATIVE, 1);
+  timer_add(timer_init(&ping_timer), check_pings, 0, TT_RELATIVE, 1);
+  timer_add(timer_init(&destruct_event_timer), exec_expired_destruct_events, 0, TT_PERIODIC, 60);
+
+  CurrentTime = time(NULL);
+
+  SetMe(&me);
+  cli_magic(&me) = CLIENT_MAGIC;
+  cli_from(&me) = &me;
+  make_server(&me);
+
+  cli_serv(&me)->timestamp = TStime();  /* Abuse own link timestamp as start TS */
+  cli_serv(&me)->prot      = atoi(MAJOR_PROTOCOL);
+  cli_serv(&me)->up        = &me;
+  cli_serv(&me)->down      = NULL;
+  cli_handler(&me)         = SERVER_HANDLER;
+
+  SetYXXCapacity(&me, MAXCLIENTS);
+
+  cli_lasttime(&me) = cli_since(&me) = cli_firsttime(&me) = CurrentTime;
+
+  hAddClient(&me);
+  SetIPv6(&me);
+
+  write_pidfile();
+  init_counters();
+
+  Debug((DEBUG_NOTICE, "Server ready..."));
+  log_write(LS_SYSTEM, L_NOTICE, 0, "Server Ready");
+
+  event_loop();
+
+  return 0;
+}
+
+
diff --git a/ircd/ircd_alloc.c b/ircd/ircd_alloc.c
new file mode 100644 (file)
index 0000000..c222737
--- /dev/null
@@ -0,0 +1,105 @@
+/************************************************************************
+ *   IRC - Internet Relay Chat, ircd/ircd_alloc.c
+ *   Copyright (C) 1999 Thomas Helvey (BleepSoft)
+ *
+ *   See file AUTHORS in IRC package for additional names of
+ *   the programmers.
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 1, or (at your option)
+ *   any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+/** @file
+ * @brief IRC daemon memory allocation functions.
+ * @version $Id: ircd_alloc.c 1306 2005-01-27 04:07:46Z entrope $
+ */
+#include "config.h"
+
+#include "ircd_alloc.h"
+#include "ircd_log.h"
+#include "ircd_string.h"
+#include "s_debug.h"
+
+/* #include <assert.h> -- Now using assert in ircd_log.h */
+#include <string.h>
+
+static void nomem_handler(void);
+
+/** Variable holding out-of-memory callback. */
+static OutOfMemoryHandler noMemHandler = nomem_handler;
+
+/** Default handler for out-of-memory conditions. */
+static void
+nomem_handler(void)
+{
+#ifdef MDEBUG
+  assert(0);
+#else
+  Debug((DEBUG_FATAL, "Out of memory, exiting"));
+  exit(2);
+#endif
+}
+
+/** Set callback function for out-of-memory conditions. */
+void
+set_nomem_handler(OutOfMemoryHandler handler)
+{
+  noMemHandler = handler;
+}
+
+#ifndef MDEBUG
+/** Allocate memory.
+ * @param[in] size Number of bytes to allocate.
+ * @param[in] x Type of allocation (ignored).
+ * @param[in] y Name of file doing allocation (ignored).
+ * @param[in] z Line number doing allocation (ignored).
+ * @return Newly allocated block of memory.
+ */
+void* DoMalloc(size_t size, const char* x, const char* y, int z)
+{
+  void* t = malloc(size);
+  if (!t)
+    (*noMemHandler)();
+  return t;
+}
+
+/** Allocate zero-initialized memory.
+ * @param[in] size Number of bytes to allocate.
+ * @param[in] x Type of allocation (ignored).
+ * @param[in] y Name of file doing allocation (ignored).
+ * @param[in] z Line number doing allocation (ignored).
+ * @return Newly allocated block of memory.
+ */
+void* DoMallocZero(size_t size, const char* x, const char* y, int z)
+{
+  void* t = malloc(size);
+  if (!t)
+    (*noMemHandler)();
+  memset(t, 0, size);
+  return t;
+}
+
+/** Resize an allocated block of memory.
+ * @param[in] orig Original block to resize.
+ * @param[in] size Minimum size for new block.
+ * @param[in] file Name of file doing reallocation (ignored).
+ * @param[in] line Line number doing reallocation (ignored).
+ */
+void* DoRealloc(void *orig, size_t size, const char *file, int line)
+{
+  void* t = realloc(orig, size);
+  if (!t)
+    (*noMemHandler)();
+  return t;
+}
+#endif
diff --git a/ircd/ircd_crypt.c b/ircd/ircd_crypt.c
new file mode 100644 (file)
index 0000000..21e6e8c
--- /dev/null
@@ -0,0 +1,246 @@
+/*
+ * IRC - Internet Relay Chat, ircd/ircd_crypt.c
+ * Copyright (C) 2002 hikari
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+/**
+ * @file
+ * @brief Core password encryption routines.
+ * @version $Id: ircd_crypt.c 1435 2005-06-24 13:57:21Z a1kmm $
+ * 
+ * This is a new look crypto API for ircu, it can handle different
+ * password formats by the grace of magic tokens at the beginning of the 
+ * password e.g. $SMD5 for Salted MD5, $CRYPT for native crypt(), etc.
+ *
+ * Currently crypt routines are implemented for: the native crypt() 
+ * function, Salted MD5 and a plain text mechanism which should only
+ * be used for testing.  I intend to add Blowfish, 3DES and possibly
+ * SHA1 support as well at some point, but I'll need to check the
+ * possible problems that'll cause with stupid crypto laws.
+ *
+ * It's also designed to be "ready" for the modularisation of ircu, so 
+ * someone get round to doing it, because I'm not doing it ;)
+ * 
+ * The plan for Stage B is to semi-modularise the authentication
+ * mechanism to allow authentication against some other sources than 
+ * the conf file (whatever takes someones fancy, kerberos, ldap, sql, etc).
+ *
+ *                   -- blessed be, hikari.
+ */
+
+#include "config.h"
+#include "ircd_crypt.h"
+#include "ircd_alloc.h"
+#include "ircd_features.h"
+#include "ircd_log.h"
+#include "ircd_string.h"
+#include "s_debug.h"
+
+/* while we're not modular, we need their init functions */
+#include "ircd_crypt_native.h"
+#include "ircd_crypt_plain.h"
+#include "ircd_crypt_smd5.h"
+
+/* #include <assert.h> -- Now using assert in ircd_log.h */
+#include <unistd.h>
+#include <string.h>
+
+/* evil global */
+crypt_mechs_t* crypt_mechs_root;
+
+/** Add a crypt mechanism to the list 
+ * @param mechanism Pointer to the mechanism details struct
+ * @return 0 on success, anything else on fail.
+ * 
+ * This routine registers a new crypt mechanism in the loaded mechanisms list, 
+ * making it availabe for comparing passwords.
+*/
+int ircd_crypt_register_mech(crypt_mech_t* mechanism)
+{
+crypt_mechs_t* crypt_mech;
+
+ Debug((DEBUG_INFO, "ircd_crypt_register_mech: registering mechanism: %s", mechanism->shortname));
+
+ /* try to allocate some memory for the new mechanism */
+ if ((crypt_mech = (crypt_mechs_t*)MyMalloc(sizeof(crypt_mechs_t))) == NULL)
+ {
+  /* aww poot, we couldn't get any memory, scream a little then back out */
+  Debug((DEBUG_MALLOC, "ircd_crypt_register_mech: could not allocate memory for %s", mechanism->shortname));
+  return -1;
+ }
+
+ /* ok, we have memory, initialise it */
+ memset(crypt_mech, 0, sizeof(crypt_mechs_t));
+
+ /* assign the data */
+ crypt_mech->mech = mechanism;
+ crypt_mech->next = crypt_mech->prev = NULL;
+
+ /* first of all, is there anything there already? */
+ if(crypt_mechs_root->next == NULL)
+ {
+  /* nope, just add ourself */
+  crypt_mechs_root->next = crypt_mechs_root->prev = crypt_mech;
+ } else {
+  /* nice and simple, put ourself at the end */
+  crypt_mech->prev = crypt_mechs_root->prev;
+  crypt_mech->next = NULL;
+  crypt_mechs_root->prev = crypt_mech->prev->next = crypt_mech;
+ }
+  
+ /* we're done */
+ Debug((DEBUG_INFO, "ircd_crypt_register_mech: registered mechanism: %s, crypt_function is at 0x%X.", crypt_mech->mech->shortname, &crypt_mech->mech->crypt_function));
+ Debug((DEBUG_INFO, "ircd_crypt_register_mech: %s: %s", crypt_mech->mech->shortname, crypt_mech->mech->description));
+ return 0;
+}
+
+/** Remove a crypt mechanism from the list 
+ * @param mechanism Pointer to the mechanism we want to remove
+ * @return 0 on success, anything else on fail.
+*/
+int ircd_crypt_unregister_mech(crypt_mech_t* mechanism)
+{
+
+return 0;
+}
+
+/** Wrapper for generating a hashed password passed on the supplied password
+ * @param key Pointer to the password we want crypted
+ * @param salt Pointer to the password we're comparing to (for the salt)
+ * @return Pointer to the generated password (must be MyFree()'d).
+ *
+ * This is a wrapper function which attempts to establish the password
+ * format and funnel it off to the correct mechanism handler function.  The
+ * returned password is compared in the oper_password_match() routine.
+*/
+char* ircd_crypt(const char* key, const char* salt)
+{
+char *hashed_pass = NULL;
+const char *temp_hashed_pass, *mysalt;
+crypt_mechs_t* crypt_mech;
+
+ assert(NULL != key);
+ assert(NULL != salt);
+
+ Debug((DEBUG_DEBUG, "ircd_crypt: key is %s", key));
+ Debug((DEBUG_DEBUG, "ircd_crypt: salt is %s", salt));
+
+ crypt_mech = crypt_mechs_root->next;
+
+ /* by examining the first n characters of a password string we
+  * can discover what kind of password it is.  hopefully. */
+ for (;crypt_mech;)
+ {
+  if (strlen(salt) < crypt_mech->mech->crypt_token_size)
+  {
+   /* try the next mechanism instead */
+   Debug((DEBUG_DEBUG, "ircd_crypt: salt is too short, will try next mech at 0x%X", crypt_mech->next));
+   crypt_mech = crypt_mech->next;
+   continue;
+  }
+
+  Debug((DEBUG_DEBUG, "ircd_crypt: comparing %s with %s", 
+   salt, crypt_mech->mech->crypt_token));
+
+  if(0 == ircd_strncmp(crypt_mech->mech->crypt_token, salt, crypt_mech->mech->crypt_token_size))
+  {
+   Debug((DEBUG_DEBUG, "ircd_crypt: type is %s", 
+    crypt_mech->mech->shortname));
+
+   /* before we send this all off to the crypt_function, we need to remove
+      the tag from it */
+
+   /* make sure we won't end up with a password comprised entirely of 
+      a single \0 */
+   if(strlen(salt) < crypt_mech->mech->crypt_token_size + 1)
+    return NULL;
+
+   mysalt = salt + crypt_mech->mech->crypt_token_size;
+
+   if(NULL == (temp_hashed_pass = crypt_mech->mech->crypt_function(key, mysalt)))
+    return NULL;
+
+   Debug((DEBUG_DEBUG, "ircd_crypt: untagged pass is %s", temp_hashed_pass));
+
+   /* ok, now we need to prefix the password we just got back
+      with the right tag */
+   if(NULL == (hashed_pass = (char *)MyMalloc(sizeof(char)*strlen(temp_hashed_pass) + crypt_mech->mech->crypt_token_size + 1)))
+   {
+    Debug((DEBUG_MALLOC, "ircd_crypt: unable to allocate memory for temp_hashed_pass"));
+    return NULL;
+   }
+   memset(hashed_pass, 0, sizeof(char)*strlen(temp_hashed_pass)
+    +crypt_mech->mech->crypt_token_size + 1);
+   ircd_strncpy(hashed_pass, crypt_mech->mech->crypt_token, 
+    crypt_mech->mech->crypt_token_size);
+   ircd_strncpy(hashed_pass + crypt_mech->mech->crypt_token_size, temp_hashed_pass, strlen(temp_hashed_pass));
+   Debug((DEBUG_DEBUG, "ircd_crypt: tagged pass is %s", hashed_pass));
+  } else {
+   Debug((DEBUG_DEBUG, "ircd_crypt: will try next mechanism at 0x%X", 
+    crypt_mech->next));
+   crypt_mech = crypt_mech->next;
+   continue;
+  }
+  return hashed_pass;
+ }
+
+ /* try to use native crypt for an old-style (untagged) password */
+ if (strlen(salt) > 2)
+ {
+   char *s;
+   temp_hashed_pass = (char*)ircd_crypt_native(key, salt);
+   if (!ircd_strcmp(temp_hashed_pass, salt))
+   {
+     DupString(s, temp_hashed_pass);
+     return s;
+   }
+ }
+
+ return NULL;
+}
+
+/** Some basic init.
+ * This function loads initalises the crypt mechanisms linked list and 
+ * currently loads the default mechanisms (Salted MD5, Crypt() and PLAIN).  
+ * The last step is only needed while ircu is not properly modular.
+ *  
+ * When ircu is modular this will be the entry function for the ircd_crypt
+ * module.
+ * 
+*/
+void ircd_crypt_init(void)
+{
+
+ if((crypt_mechs_root = MyMalloc(sizeof(crypt_mechs_t))) == NULL)
+ {
+  /* awooga - can't allocate memory for the root structure */
+  Debug((DEBUG_MALLOC, "init_crypt: Could not allocate memory for crypt_mechs_root"));
+  return;
+ }
+
+ crypt_mechs_root->mech = NULL;
+ crypt_mechs_root->next = crypt_mechs_root->prev = NULL;
+
+/* temporary kludge until we're modular.  manually call the
+   register functions for crypt mechanisms */
+ ircd_register_crypt_smd5();
+ ircd_register_crypt_plain();
+ ircd_register_crypt_native();
+
+return;
+}
diff --git a/ircd/ircd_crypt_native.c b/ircd/ircd_crypt_native.c
new file mode 100644 (file)
index 0000000..f45654b
--- /dev/null
@@ -0,0 +1,85 @@
+/*
+ * IRC - Internet Relay Chat, ircd/ircd_xopen.c
+ * Copyright (C) 1990, 1991 Armin Gruner
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+/**
+ * @file
+ * @brief Native crypt() function routines
+ * @version $Id: ircd_crypt_native.c 1577 2005-12-14 03:01:38Z entrope $
+ * 
+ * Routines for handling passwords encrypted with the system's native crypt()
+ * function (typically a DES encryption routine, but can be anything nowadays).
+ * 
+ */
+#define _XOPEN_SOURCE 500
+
+#include "config.h"
+#include "ircd_crypt.h"
+#include "ircd_crypt_native.h"
+#include "ircd_log.h"
+#include "s_debug.h"
+#include "ircd_alloc.h"
+
+/* #include <assert.h> -- Now using assert in ircd_log.h */
+#include <unistd.h>
+#ifdef HAVE_CRYPT_H
+#include <crypt.h>
+#endif
+
+/** Simple routine that just calls crypt() with the supplied password and salt
+ * @param key The password we're encrypting.
+ * @param salt The salt we're using to encrypt key
+ * @return The encrypted password.
+ * 
+ * Well this bit is (kinda) intact from the original oper password routines :) 
+ * It's a very simple wrapper routine that just calls crypt and returns the 
+ * result.
+ *   -- hikari
+ */
+const char* ircd_crypt_native(const char* key, const char* salt)
+{
+ assert(NULL != key);
+ assert(NULL != salt);
+
+ Debug((DEBUG_DEBUG, "ircd_crypt_native: key is %s", key));
+ Debug((DEBUG_DEBUG, "ircd_crypt_native: salt is %s", salt));
+
+ return (const char*)crypt(key, salt);
+}
+
+/* register ourself with the list of crypt mechanisms -- hikari */
+void ircd_register_crypt_native(void)
+{
+crypt_mech_t* crypt_mech;
+
+ if ((crypt_mech = (crypt_mech_t*)MyMalloc(sizeof(crypt_mech_t))) == NULL)
+ {
+  Debug((DEBUG_MALLOC, "Could not allocate space for crypt_native"));
+  return;
+ }
+
+ crypt_mech->mechname = "native";
+ crypt_mech->shortname = "crypt_native";
+ crypt_mech->description = "System native crypt() function mechanism.";
+ crypt_mech->crypt_function = &ircd_crypt_native;
+ crypt_mech->crypt_token = "$CRYPT$";
+ crypt_mech->crypt_token_size = 7;
+
+ ircd_crypt_register_mech(crypt_mech);
+return;
+}
diff --git a/ircd/ircd_crypt_plain.c b/ircd/ircd_crypt_plain.c
new file mode 100644 (file)
index 0000000..f03db40
--- /dev/null
@@ -0,0 +1,85 @@
+/*
+ * IRC - Internet Relay Chat, ircd/ircd_crypt_plain.c
+ * Copyright (C) 2002 hikari
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+/**
+ * @file
+ * @brief Routines for PLAIN passwords.
+ * @version $Id: ircd_crypt_plain.c 1271 2004-12-11 05:14:07Z klmitch $
+ * 
+ * PLAIN text encryption.  Oxymoron and a half that.
+ */
+#include "config.h"
+#include "ircd_crypt.h"
+#include "ircd_crypt_plain.h"
+#include "ircd_log.h"
+#include "s_debug.h"
+#include "ircd_alloc.h"
+
+/* #include <assert.h> -- Now using assert in ircd_log.h */
+#include <unistd.h>
+
+/** Just sends back the supplied password.
+ * @param key The password
+ * @param salt The salt
+ * @return The password
+ * 
+ * Yes I know it's an oxymoron, but still, it's handy for testing.
+ * 
+ * What you need more help with seeing what this does?
+ * 
+ */
+const char* ircd_crypt_plain(const char* key, const char* salt)
+{
+  assert(NULL != salt);
+  assert(NULL != key);
+
+ Debug((DEBUG_DEBUG, "ircd_crypt_plain: key is %s", key));
+ Debug((DEBUG_DEBUG, "ircd_crypt_plain: salt is %s", salt));
+
+  /* yes, that's it.  we just send key back out again, 
+     pointless I know */
+  return key;
+}
+
+/** register ourself with the list of crypt mechanisms 
+ * Registers the PLAIN mechanism in the list of available crypt mechanisms.  
+ * When we're modular this will be the entry function for the module.
+ * 
+ * -- hikari */
+void ircd_register_crypt_plain(void)
+{
+crypt_mech_t* crypt_mech;
+
+ if ((crypt_mech = (crypt_mech_t*)MyMalloc(sizeof(crypt_mech_t))) == NULL)
+ {
+  Debug((DEBUG_MALLOC, "Could not allocate space for crypt_plain"));
+  return;
+ }
+
+ crypt_mech->mechname = "plain";
+ crypt_mech->shortname = "crypt_plain";
+ crypt_mech->description = "Plain text \"crypt\" mechanism.";
+ crypt_mech->crypt_function = &ircd_crypt_plain;
+ crypt_mech->crypt_token = "$PLAIN$";
+ crypt_mech->crypt_token_size = 7;
+
+ ircd_crypt_register_mech(crypt_mech);
+return;
+}
diff --git a/ircd/ircd_crypt_smd5.c b/ircd/ircd_crypt_smd5.c
new file mode 100644 (file)
index 0000000..3688564
--- /dev/null
@@ -0,0 +1,233 @@
+/*
+ * IRC - Internet Relay Chat, ircd/ircd_crypt_smd5.c
+ * Copyright (C) 2002 hikari
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+/** 
+ * @file
+ * @brief Routines for Salted MD5 passwords
+ * @version $Id: ircd_crypt_smd5.c 1334 2005-03-20 16:06:30Z entrope $
+ * 
+ * ircd_crypt_smd5 is largely taken from md5_crypt.c from the Linux PAM 
+ * source code.  it's been modified to fit in with ircu and some of the 
+ * unneeded code has been removed.  the source file md5_crypt.c has the 
+ * following license, so if any of our opers or admins are in Denmark
+ * they better go buy them a drink ;) -- hikari
+ *
+ * ----------------------------------------------------------------------------
+ * "THE BEER-WARE LICENSE" (Revision 42):
+ * <phk@login.dknet.dk> wrote this file.  As long as you retain this notice you
+ * can do whatever you want with this stuff. If we meet some day, and you think
+ * this stuff is worth it, you can buy me a beer in return.   Poul-Henning Kamp
+ * ----------------------------------------------------------------------------
+ *
+ */
+#include "config.h"
+#include "ircd_crypt.h"
+#include "ircd_crypt_smd5.h"
+#include "ircd_log.h"
+#include "ircd_md5.h"
+#include "s_debug.h"
+#include "ircd_alloc.h"
+
+/* #include <assert.h> -- Now using assert in ircd_log.h */
+#include <string.h>
+#include <unistd.h>
+
+static unsigned char itoa64[] = /* 0 ... 63 => ascii - 64 */
+"./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
+
+/** Converts a binary value into a BASE64 encoded string.
+ * @param s Pointer to the output string
+ * @param v The unsigned long we're working on
+ * @param n The number of bytes we're working with
+ *  
+ * This is used to produce the normal MD5 hash everyone is familiar with.  
+ * It takes the value v and converts n bytes of it it into an ASCII string in 
+ * 6-bit chunks, the resulting string is put at the address pointed to by s.
+ * 
+ */
+static void to64(char *s, unsigned long v, int n)
+{
+ while (--n >= 0) {
+  *s++ = itoa64[v & 0x3f];
+  v >>= 6;
+ }
+}
+
+/** Produces a Salted MD5 crypt of a password using the supplied salt
+ * @param key The password we're encrypting
+ * @param salt The salt we're using to encrypt it
+ * @return The Salted MD5 password of key and salt
+ * 
+ * Erm does exactly what the brief comment says.  If you think I'm writing a 
+ * description of how MD5 works, you have another think coming.  Go and read
+ * Applied Cryptography by Bruce Schneier.  The only difference is we use a 
+ * salt at the beginning of the password to perturb it so that the same password
+ * doesn't always produce the same hash.
+ * 
+ */ 
+const char* ircd_crypt_smd5(const char* key, const char* salt)
+{
+const char *magic = "$1$";
+static char passwd[120];
+char *p;
+const char *sp, *ep;
+unsigned char final[16];
+int sl, pl, i, j;
+MD5_CTX ctx, ctx1;
+unsigned long l;
+
+ assert(NULL != key);
+ assert(NULL != salt);
+
+ Debug((DEBUG_DEBUG, "ircd_crypt_smd5: key = %s", key));
+ Debug((DEBUG_DEBUG, "ircd_crypt_smd5: salt = %s", salt));
+
+ /* Refine the Salt first */
+ ep = sp = salt;
+
+ for (ep = sp; *ep && *ep != '$' && ep < (sp + 8); ep++)
+  continue;
+
+ /* get the length of the true salt */
+ sl = ep - sp;
+
+ MD5Init(&ctx);
+
+ /* The password first, since that is what is most unknown */
+ MD5Update(&ctx,(unsigned const char *)key,strlen(key));
+
+ /* Then our magic string */
+ MD5Update(&ctx,(unsigned const char *)magic,strlen(magic));
+
+ /* Then the raw salt */
+ MD5Update(&ctx,(unsigned const char *)sp,sl);
+
+ /* Then just as many characters of the MD5(key,salt,key) */
+ MD5Init(&ctx1);
+ MD5Update(&ctx1,(unsigned const char *)key,strlen(key));
+ MD5Update(&ctx1,(unsigned const char *)sp,sl);
+ MD5Update(&ctx1,(unsigned const char *)key,strlen(key));
+ MD5Final(final,&ctx1);
+ for (pl = strlen(key); pl > 0; pl -= 16)
+  MD5Update(&ctx,(unsigned const char *)final,pl>16 ? 16 : pl);
+
+ /* Don't leave anything around in vm they could use. */
+ memset(final, 0, sizeof final);
+
+ /* Then something really weird... */
+ for (j = 0, i = strlen(key); i; i >>= 1)
+  if (i & 1)
+   MD5Update(&ctx, (unsigned const char *)final+j, 1);
+  else
+   MD5Update(&ctx, (unsigned const char *)key+j, 1);
+
+ /* Now make the output string. */
+ memset(passwd, 0, 120);
+ strncpy(passwd, sp, sl);
+ strcat(passwd, "$");
+
+ MD5Final(final,&ctx);
+
+ /*
+  * and now, just to make sure things don't run too fast
+  * On a 60 Mhz Pentium this takes 34 msec, so you would
+  * need 30 seconds to build a 1000 entry dictionary...
+  */
+ for (i = 0; i < 1000; i++) {
+  MD5Init(&ctx1);
+
+  if (i & 1)
+   MD5Update(&ctx1,(unsigned const char *)key,strlen(key));
+  else
+   MD5Update(&ctx1,(unsigned const char *)final,16);
+
+  if (i % 3)
+   MD5Update(&ctx1,(unsigned const char *)sp,sl);
+
+  if (i % 7)
+   MD5Update(&ctx1,(unsigned const char *)key,strlen(key));
+
+  if (i & 1)
+   MD5Update(&ctx1,(unsigned const char *)final,16);
+  else
+   MD5Update(&ctx1,(unsigned const char *)key,strlen(key));
+
+  MD5Final(final,&ctx1);
+ }
+
+ p = passwd + strlen(passwd);
+
+ Debug((DEBUG_DEBUG, "passwd = %s", passwd));
+
+ /* Turn the encrypted binary data into a BASE64 encoded string we can read
+  * and display -- hikari */
+ l = (final[0] << 16) | (final[6] << 8) | final[12];
+ to64(p, l, 4);
+ p += 4;
+ l = (final[1] << 16) | (final[7] << 8) | final[13];
+ to64(p, l, 4);
+ p += 4;
+ l = (final[2] << 16) | (final[8] << 8) | final[14];
+ to64(p, l, 4);
+ p += 4;
+ l = (final[3] << 16) | (final[9] << 8) | final[15];
+ to64(p, l, 4);
+ p += 4;
+ l = (final[4] << 16) | (final[10] << 8) | final[5];
+ to64(p, l, 4);
+ p += 4;
+ l = final[11];
+ to64(p, l, 2);
+ p += 2;
+ *p = '\0';
+
+ /* Don't leave anything around in vm they could use. */
+ memset(final, 0, sizeof final);
+
+return passwd;
+}
+
+/* end borrowed code */
+
+/** Register ourself with the list of crypt mechanisms 
+ * Registers the SMD5 mechanism in the list of available crypt mechanisms.  When 
+ * we're modular this will be the entry function for the module.
+ * 
+ */
+void ircd_register_crypt_smd5(void)
+{
+crypt_mech_t* crypt_mech;
+
+ if ((crypt_mech = (crypt_mech_t*)MyMalloc(sizeof(crypt_mech_t))) == NULL)
+ {
+  Debug((DEBUG_MALLOC, "Could not allocate space for crypt_smd5"));
+  return;
+ }
+
+ crypt_mech->mechname = "smd5";
+ crypt_mech->shortname = "crypt_smd5";
+ crypt_mech->description = "Salted MD5 password hash mechanism.";
+ crypt_mech->crypt_function = &ircd_crypt_smd5;
+ crypt_mech->crypt_token = "$SMD5$";
+ crypt_mech->crypt_token_size = 6 ;
+
+ ircd_crypt_register_mech(crypt_mech);
+return;
+}
diff --git a/ircd/ircd_events.c b/ircd/ircd_events.c
new file mode 100644 (file)
index 0000000..7810980
--- /dev/null
@@ -0,0 +1,899 @@
+/*
+ * IRC - Internet Relay Chat, ircd/ircd_events.c
+ * Copyright (C) 2001 Kevin L. Mitchell <klmitch@mit.edu>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+/** @file
+ * @brief Implementation of event loop mid-layer.
+ * @version $Id: ircd_events.c 1794 2007-04-01 02:11:41Z entrope $
+ */
+#include "config.h"
+
+#include "ircd_events.h"
+
+#include "ircd.h"
+#include "ircd_alloc.h"
+#include "ircd_log.h"
+#include "ircd_snprintf.h"
+#include "s_debug.h"
+
+/* #include <assert.h> -- Now using assert in ircd_log.h */
+#include <signal.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#define SIGS_PER_SOCK  10      /**< number of signals to process per socket
+                                  readable event */
+
+#ifdef USE_KQUEUE
+extern struct Engine engine_kqueue;
+#define ENGINE_KQUEUE  &engine_kqueue,
+#else
+/** Address of kqueue engine (if used). */
+#define ENGINE_KQUEUE
+#endif /* USE_KQUEUE */
+
+#ifdef USE_DEVPOLL
+extern struct Engine engine_devpoll;
+#define ENGINE_DEVPOLL &engine_devpoll,
+#else
+/** Address of /dev/poll engine (if used). */
+#define ENGINE_DEVPOLL
+#endif /* USE_DEVPOLL */
+
+#ifdef USE_EPOLL
+extern struct Engine engine_epoll;
+#define ENGINE_EPOLL &engine_epoll,
+#else
+/** Address of epoll engine (if used). */
+#define ENGINE_EPOLL
+#endif /* USE_EPOLL */
+
+#ifdef USE_POLL
+extern struct Engine engine_poll;
+/** Address of fallback (poll) engine. */
+#define ENGINE_FALLBACK        &engine_poll,
+#else
+extern struct Engine engine_select;
+/** Address of fallback (select) engine. */
+#define ENGINE_FALLBACK        &engine_select,
+#endif /* USE_POLL */
+
+/** list of engines to try */
+static const struct Engine *evEngines[] = {
+  ENGINE_KQUEUE
+  ENGINE_EPOLL
+  ENGINE_DEVPOLL
+  ENGINE_FALLBACK
+  0
+};
+
+/** Signal routines pipe data.
+ * This is used if an engine does not implement signal handling itself
+ * (when Engine::eng_signal is NULL).
+ */
+static struct {
+  int          fd;     /**< signal routine's fd */
+  struct Socket        sock;   /**< and its struct Socket */
+} sigInfo = { -1 };
+
+/** All the thread info */
+static struct {
+  struct Generators    gens;           /**< List of all generators */
+  struct Event*               events_free;     /**< struct Event free list */
+  unsigned int        events_alloc;    /**< count of allocated struct Events */
+  const struct Engine* engine;         /**< core engine being used */
+#ifdef IRCD_THREADED
+  struct GenHeader*    genq_head;      /**< head of generator event queue */
+  struct GenHeader*    genq_tail;      /**< tail of generator event queue */
+  unsigned int        genq_count;      /**< count of generators on queue */
+#endif
+} evInfo = {
+  { 0, 0, 0 },
+  0, 0, 0
+#ifdef IRCD_THREADED
+  , 0, 0, 0
+#endif
+};
+
+/** Initialize a struct GenHeader.
+ * @param[in,out] gen GenHeader to initialize.
+ * @param[in] call Callback for generated events.
+ * @param[in] data User data pointer.
+ * @param[in] next Pointer to next generator.
+ * @param[in,out] prev_p Pointer to previous pointer for this list.
+ */
+static void
+gen_init(struct GenHeader* gen, EventCallBack call, void* data,
+        struct GenHeader* next, struct GenHeader** prev_p)
+{
+  assert(0 != gen);
+
+  gen->gh_next = next;
+  gen->gh_prev_p = prev_p;
+#ifdef IRCD_THREADED
+  gen->gh_qnext = 0;
+  gen->gh_qprev_p = 0;
+  gen->gh_head = 0;
+  gen->gh_tail = 0;
+#endif
+  gen->gh_flags = GEN_ACTIVE;
+  gen->gh_ref = 0;
+  gen->gh_call = call;
+  gen->gh_data = data;
+  gen->gh_engdata.ed_int = 0;
+
+  if (prev_p) { /* Going to link into list? */
+    if (next) /* do so */
+      next->gh_prev_p = &gen->gh_next;
+    *prev_p = gen;
+  }
+}
+
+/** Execute an event.
+ * Optimizations should inline this.
+ * @param[in] event Event to execute.
+ */
+static void
+event_execute(struct Event* event)
+{
+  assert(0 != event);
+  assert(0 == event->ev_prev_p); /* must be off queue first */
+  assert(event->ev_gen.gen_header->gh_flags & GEN_ACTIVE);
+
+  if (event->ev_type == ET_DESTROY) /* turn off active flag *before* destroy */
+    event->ev_gen.gen_header->gh_flags &= ~GEN_ACTIVE;
+  if (event->ev_type == ET_ERROR) /* turn on error flag before callback */
+    event->ev_gen.gen_header->gh_flags |= GEN_ERROR;
+
+  (*event->ev_gen.gen_header->gh_call)(event); /* execute the event */
+
+  /* The logic here is very careful; if the event was an ET_DESTROY,
+   * then we must assume the generator is now invalid; fortunately, we
+   * don't need to do anything to it if so.  Otherwise, we decrement
+   * the reference count; if reference count goes to zero, AND we need
+   * to destroy the generator, THEN we generate a DESTROY event.
+   */
+  if (event->ev_type != ET_DESTROY)
+    gen_ref_dec(event->ev_gen.gen_header);
+
+  event->ev_gen.gen_header = 0; /* clear event data */
+  event->ev_type = ET_DESTROY;
+
+  event->ev_next = evInfo.events_free; /* add to free list */
+  evInfo.events_free = event;
+}
+
+#ifndef IRCD_THREADED
+/** we synchronously execute the event when not threaded */
+#define event_add(event)       \
+do {                                                                         \
+  struct Event* _ev = (event);                                               \
+  _ev->ev_next = 0;                                                          \
+  _ev->ev_prev_p = 0;                                                        \
+  event_execute(_ev);                                                        \
+} while (0)
+
+#else
+/** Add an event to the work queue.
+ * @param[in] event Event to enqueue.
+ */
+/* This is just a placeholder; don't expect ircd to be threaded soon */
+/* There should be locks all over the place in here */
+static void
+event_add(struct Event* event)
+{
+  struct GenHeader* gen;
+
+  assert(0 != event);
+
+  gen = event->ev_gen.gen_header;
+
+  /* First, place event on generator's event queue */
+  event->ev_next = 0;
+  if (gen->gh_head) {
+    assert(0 != gen->gh_tail);
+
+    event->ev_prev_p = &gen->gh_tail->ev_next;
+    gen->gh_tail->ev_next = event;
+    gen->gh_tail = event;
+  } else { /* queue was empty */
+    assert(0 == gen->gh_tail);
+
+    event->ev_prev_p = &gen->gh_head;
+    gen->gh_head = event;
+    gen->gh_tail = event;
+  }
+
+  /* Now, if the generator isn't on the queue yet... */
+  if (!gen->gh_qprev_p) {
+    gen->gh_qnext = 0;
+    if (evInfo.genq_head) {
+      assert(0 != evInfo.genq_tail);
+
+      gen->gh_qprev_p = &evInfo.genq_tail->gh_qnext;
+      evInfo.genq_tail->gh_qnext = gen;
+      evInfo.genq_tail = gen;
+    } else { /* queue was empty */
+      assert(0 == evInfo.genq_tail);
+
+      gen->gh_qprev_p = &evInfo.genq_head;
+      evInfo.genq_head = gen;
+      evInfo.genq_tail = gen;
+    }
+
+    /* We'd also have to signal the work crew here */
+  }
+}
+#endif /* IRCD_THREADED */
+
+/** Place a timer in the correct spot on the queue.
+ * @param[in] timer Timer to enqueue.
+ */
+static void
+timer_enqueue(struct Timer* timer)
+{
+  struct GenHeader** ptr_p;
+
+  assert(0 != timer);
+  assert(0 == timer->t_header.gh_prev_p); /* not already on queue */
+  assert(timer->t_header.gh_flags & GEN_ACTIVE); /* timer is active */
+
+  /* Calculate expire time */
+  switch (timer->t_type) {
+  case TT_ABSOLUTE: /* no need to consider it relative */
+    timer->t_expire = timer->t_value;
+    break;
+
+  case TT_RELATIVE: case TT_PERIODIC: /* relative timer */
+    timer->t_expire = timer->t_value + CurrentTime;
+    break;
+  }
+
+  /* Find a slot to insert timer */
+  for (ptr_p = &evInfo.gens.g_timer; ;
+       ptr_p = &(*ptr_p)->gh_next)
+    if (!*ptr_p || timer->t_expire < ((struct Timer*)*ptr_p)->t_expire)
+      break;
+
+  /* link it in the right place */
+  timer->t_header.gh_next = *ptr_p;
+  timer->t_header.gh_prev_p = ptr_p;
+  if (*ptr_p)
+    (*ptr_p)->gh_prev_p = &timer->t_header.gh_next;
+  *ptr_p = &timer->t_header;
+}
+
+/** &Signal handler for writing signal notification to pipe.
+ * @param[in] sig Signal number that just happened.
+ */
+static void
+signal_handler(int sig)
+{
+  unsigned char c;
+
+  assert(sigInfo.fd >= 0);
+
+  c = (unsigned char) sig; /* only write 1 byte to identify sig */
+
+  write(sigInfo.fd, &c, 1);
+}
+
+/** Callback for signal "socket" (really pipe) events.
+ * @param[in] event Event activity descriptor.
+ */
+static void
+signal_callback(struct Event* event)
+{
+  unsigned char sigstr[SIGS_PER_SOCK];
+  int sig, n_sigs, i;
+  struct GenHeader* ptr;
+
+  assert(event->ev_type == ET_READ); /* readable events only */
+
+  n_sigs = read(event->ev_gen.gen_socket->s_fd, sigstr, sizeof(sigstr));
+
+  for (i = 0; i < n_sigs; i++) {
+    sig = (int) sigstr[i]; /* get signal */
+
+    for (ptr = evInfo.gens.g_signal; ptr;
+        ptr = ptr->gh_next)
+      if (((struct Signal*)ptr)->sig_signal == sig) /* find its descriptor... */
+       break;
+
+    if (ptr)
+      event_generate(ET_SIGNAL, ptr, sig); /* generate signal event */
+  }
+}
+
+/** Remove a generator from its queue.
+ * @param[in] arg Pointer to a GenHeader to dequeue.
+ */
+void
+gen_dequeue(void* arg)
+{
+  struct GenHeader* gen = (struct GenHeader*) arg;
+
+  if (gen->gh_next) /* clip it out of the list */
+    gen->gh_next->gh_prev_p = gen->gh_prev_p;
+  if (gen->gh_prev_p)
+    *gen->gh_prev_p = gen->gh_next;
+
+  gen->gh_next = 0; /* mark that it's not in the list anymore */
+  gen->gh_prev_p = 0;
+}
+
+/** Initializes the event system.
+ * @param[in] max_sockets Maximum number of sockets to support.
+ */
+void
+event_init(int max_sockets)
+{
+  int i, p[2];
+
+  for (i = 0; evEngines[i]; i++) { /* look for an engine... */
+    assert(0 != evEngines[i]->eng_name);
+    assert(0 != evEngines[i]->eng_init);
+
+    if ((*evEngines[i]->eng_init)(max_sockets))
+      break; /* Found an engine that'll work */
+  }
+
+  assert(0 != evEngines[i]);
+
+  evInfo.engine = evEngines[i]; /* save engine */
+
+  if (!evInfo.engine->eng_signal) { /* engine can't do signals */
+    if (pipe(p)) {
+      log_write(LS_SYSTEM, L_CRIT, 0, "Failed to open signal pipe");
+      exit(8);
+    }
+
+    sigInfo.fd = p[1]; /* write end of pipe */
+    socket_add(&sigInfo.sock, signal_callback, 0, SS_NOTSOCK,
+              SOCK_EVENT_READABLE, p[0]); /* read end of pipe */
+  }
+}
+
+/** Do the event loop. */
+void
+event_loop(void)
+{
+  assert(0 != evInfo.engine);
+  assert(0 != evInfo.engine->eng_loop);
+
+  (*evInfo.engine->eng_loop)(&evInfo.gens);
+}
+
+/** Generate an event and add it to the queue (or execute it).
+ * @param[in] type Type of event to generate.
+ * @param[in] arg Pointer to an event generator (GenHeader).
+ * @param[in] data Extra data for event.
+ */
+void
+event_generate(enum EventType type, void* arg, int data)
+{
+  struct Event* ptr;
+  struct GenHeader* gen = (struct GenHeader*) arg;
+
+  assert(0 != gen);
+
+  /* don't create events (other than ET_DESTROY) for destroyed generators */
+  if (type != ET_DESTROY && (gen->gh_flags & GEN_DESTROY))
+    return;
+
+  Debug((DEBUG_LIST, "Generating event type %s for generator %p (%s)",
+        event_to_name(type), gen, gen_flags(gen->gh_flags)));
+
+  if ((ptr = evInfo.events_free))
+    evInfo.events_free = ptr->ev_next; /* pop one off the freelist */
+  else { /* allocate another structure */
+    ptr = (struct Event*) MyMalloc(sizeof(struct Event));
+    evInfo.events_alloc++; /* count of allocated events */
+  }
+
+  ptr->ev_type = type; /* Record event type */
+  ptr->ev_data = data;
+
+  ptr->ev_gen.gen_header = (struct GenHeader*) gen;
+  ptr->ev_gen.gen_header->gh_ref++;
+
+  event_add(ptr); /* add event to queue */
+}
+
+#if 0
+/* Try to verify the timer list */
+void
+timer_verify(void)
+{
+  struct Timer* ptr;
+  struct Timer** ptr_p = &evInfo.gens.g_timer;
+  time_t lasttime = 0;
+
+  for (ptr = evInfo.gens.g_timer; ptr;
+       ptr = (struct Timer*) ptr->t_header.gh_next) {
+    /* verify timer is supposed to be in the list */
+    assert(ptr->t_header.gh_prev_p);
+    /* verify timer is correctly ordered */
+    assert((struct Timer**) ptr->t_header.gh_prev_p == ptr_p);
+    /* verify timer is active */
+    assert(ptr->t_header.gh_flags & GEN_ACTIVE);
+    /* verify timer ordering is correct */
+    assert(lasttime <= ptr->t_expire);
+
+    lasttime = ptr->t_expire; /* store time for ordering check */
+    ptr_p = (struct Timer**) &ptr->t_header.gh_next; /* store prev pointer */
+  }
+}
+#endif
+
+/** Initialize a timer structure.
+ * @param[in,out] timer Timer to initialize.
+ * @return The pointer \a timer.
+ */
+struct Timer*
+timer_init(struct Timer* timer)
+{
+  gen_init(&timer->t_header, 0, 0, 0, 0);
+
+  timer->t_header.gh_flags = 0; /* turn off active flag */
+
+  return timer; /* convenience return */
+}
+
+/** Add a timer to be processed.
+ * @param[in] timer Timer to add.
+ * @param[in] call Callback for when the timer expires or is removed.
+ * @param[in] data User data pointer for the timer.
+ * @param[in] type Timer type.
+ * @param[in] value Timer expiration, duration or interval (per \a type).
+ */
+void
+timer_add(struct Timer* timer, EventCallBack call, void* data,
+         enum TimerType type, time_t value)
+{
+  assert(0 != timer);
+  assert(0 != call);
+
+  Debug((DEBUG_LIST, "Adding timer %p; time out %Tu (type %s)", timer, value,
+        timer_to_name(type)));
+
+  /* initialize a timer... */
+  timer->t_header.gh_flags |= GEN_ACTIVE;
+  if (timer->t_header.gh_flags & GEN_MARKED)
+    timer->t_header.gh_flags |= GEN_READD;
+
+  timer->t_header.gh_ref = 0;
+  timer->t_header.gh_call = call;
+  timer->t_header.gh_data = data;
+
+  timer->t_type = type;
+  timer->t_value = value;
+  timer->t_expire = 0;
+
+  if (!(timer->t_header.gh_flags & GEN_MARKED))
+    timer_enqueue(timer); /* and enqueue it */
+}
+
+/** Remove a timer from the processing queue.
+ * @param[in] timer Timer to remove.
+ */
+void
+timer_del(struct Timer* timer)
+{
+  assert(0 != timer);
+
+  timer->t_header.gh_flags &= ~GEN_READD;
+
+  if (timer->t_header.gh_flags & GEN_MARKED)
+    return; /* timer is being used */
+
+  Debug((DEBUG_LIST, "Deleting timer %p (type %s)", timer,
+        timer_to_name(timer->t_type)));
+
+  gen_dequeue(timer);
+  event_generate(ET_DESTROY, timer, 0);
+}
+
+/** Change the time a timer expires.
+ * @param[in] timer Timer to update.
+ * @param[in] type New timer type.
+ * @param[in] value New timer expiration value.
+ */
+void
+timer_chg(struct Timer* timer, enum TimerType type, time_t value)
+{
+  assert(0 != timer);
+  assert(0 != value);
+  assert(TT_PERIODIC != timer->t_type);
+  assert(TT_PERIODIC != type);
+
+  Debug((DEBUG_LIST, "Changing timer %p from type %s timeout %Tu to type %s "
+        "timeout %Tu", timer, timer_to_name(timer->t_type), timer->t_value,
+        timer_to_name(type), value));
+
+  timer->t_type = type; /* Set the new type and value */
+  timer->t_value = value;
+  timer->t_expire = 0;
+
+  /* If the timer expiration callback tries to change the timer
+   * expiration, flag the timer but do not dequeue it yet.
+   */
+  if (timer->t_header.gh_flags & GEN_MARKED)
+  {
+    timer->t_header.gh_flags |= GEN_READD;
+    return;
+  }
+  gen_dequeue(timer); /* remove the timer from the queue */
+  timer_enqueue(timer); /* re-queue the timer */
+}
+
+/** Execute all expired timers. */
+void
+timer_run(void)
+{
+  struct Timer* ptr;
+
+  /* go through queue... */
+  while ((ptr = (struct Timer*)evInfo.gens.g_timer)) {
+    if (CurrentTime < ptr->t_expire)
+      break; /* processed all pending timers */
+
+    gen_dequeue(ptr); /* must dequeue timer here */
+    ptr->t_header.gh_flags |= (GEN_MARKED |
+                              (ptr->t_type == TT_PERIODIC ? GEN_READD : 0));
+
+    event_generate(ET_EXPIRE, ptr, 0); /* generate expire event */
+
+    ptr->t_header.gh_flags &= ~GEN_MARKED;
+
+    if (!(ptr->t_header.gh_flags & GEN_READD)) {
+      Debug((DEBUG_LIST, "Destroying timer %p", ptr));
+      event_generate(ET_DESTROY, ptr, 0);
+    } else {
+      Debug((DEBUG_LIST, "Re-enqueuing timer %p", ptr));
+      timer_enqueue(ptr); /* re-queue timer */
+      ptr->t_header.gh_flags &= ~GEN_READD;
+    }
+  }
+}
+
+/** Adds a signal to the event callback system.
+ * @param[in] signal Signal event generator to use.
+ * @param[in] call Callback function to use.
+ * @param[in] data User data pointer for generator.
+ * @param[in] sig Signal number to hook.
+ */
+void
+signal_add(struct Signal* signal, EventCallBack call, void* data, int sig)
+{
+  struct sigaction act;
+
+  assert(0 != signal);
+  assert(0 != call);
+  assert(0 != evInfo.engine);
+
+  /* set up struct */
+  gen_init(&signal->sig_header, call, data,
+          evInfo.gens.g_signal,
+          &evInfo.gens.g_signal);
+
+  signal->sig_signal = sig;
+
+  if (evInfo.engine->eng_signal)
+    (*evInfo.engine->eng_signal)(signal); /* tell engine */
+  else {
+    act.sa_handler = signal_handler; /* set up signal handler */
+    act.sa_flags = 0;
+    sigemptyset(&act.sa_mask);
+    sigaction(sig, &act, 0);
+  }
+}
+
+/** Adds a socket to the event system.
+ * @param[in] sock Socket event generator to use.
+ * @param[in] call Callback function to use.
+ * @param[in] data User data pointer for the generator.
+ * @param[in] state Current socket state.
+ * @param[in] events Event interest mask for connected or connectionless sockets.
+ * @param[in] fd &Socket file descriptor.
+ * @return Zero on error, non-zero on success.
+ */
+int
+socket_add(struct Socket* sock, EventCallBack call, void* data,
+          enum SocketState state, unsigned int events, int fd)
+{
+  assert(0 != sock);
+  assert(0 != call);
+  assert(fd >= 0);
+  assert(0 != evInfo.engine);
+  assert(0 != evInfo.engine->eng_add);
+
+  /* set up struct */
+  gen_init(&sock->s_header, call, data,
+          evInfo.gens.g_socket,
+          &evInfo.gens.g_socket);
+
+  sock->s_state = state;
+  sock->s_events = events & SOCK_EVENT_MASK;
+  sock->s_fd = fd;
+  sock->ssl = NULL;
+
+  return (*evInfo.engine->eng_add)(sock); /* tell engine about it */
+}
+
+/** Deletes (or marks for deletion) a socket generator.
+ * @param[in] sock Event generator to clear.
+ */
+void
+socket_del(struct Socket* sock)
+{
+  assert(0 != sock);
+  assert(!(sock->s_header.gh_flags & GEN_DESTROY));
+  assert(0 != evInfo.engine);
+  assert(0 != evInfo.engine->eng_closing);
+
+  /* tell engine socket is going away */
+  (*evInfo.engine->eng_closing)(sock);
+
+  sock->s_header.gh_flags |= GEN_DESTROY;
+
+  if (!sock->s_header.gh_ref) { /* not in use; destroy right now */
+    gen_dequeue(sock);
+    event_generate(ET_DESTROY, sock, 0);
+  }
+}
+
+/** Sets the socket state to something else.
+ * @param[in] sock Socket generator to update.
+ * @param[in] state New socket state.
+ */
+void
+socket_state(struct Socket* sock, enum SocketState state)
+{
+  assert(0 != sock);
+  assert(0 != evInfo.engine);
+  assert(0 != evInfo.engine->eng_state);
+
+  /* assertions for invalid socket state transitions */
+  assert(sock->s_state != state); /* not changing states ?! */
+  assert(sock->s_state != SS_LISTENING); /* listening socket to...?! */
+  assert(sock->s_state != SS_CONNECTED); /* connected socket to...?! */
+  /* connecting socket now connected */
+  assert(sock->s_state != SS_CONNECTING || state == SS_CONNECTED);
+  /* unconnected datagram socket now connected */
+  assert(sock->s_state != SS_DATAGRAM || state == SS_CONNECTDG);
+  /* connected datagram socket now unconnected */
+  assert(sock->s_state != SS_CONNECTDG || state == SS_DATAGRAM);
+
+  /* Don't continue if an error occurred or the socket got destroyed */
+  if (sock->s_header.gh_flags & (GEN_DESTROY | GEN_ERROR))
+    return;
+
+  /* tell engine we're changing socket state */
+  (*evInfo.engine->eng_state)(sock, state);
+
+  sock->s_state = state; /* set new state */
+}
+
+/** Sets the events a socket's interested in.
+ * @param[in] sock Socket generator to update.
+ * @param[in] events New event interest mask.
+ */
+void
+socket_events(struct Socket* sock, unsigned int events)
+{
+  unsigned int new_events = 0;
+
+  assert(0 != sock);
+  assert(0 != evInfo.engine);
+  assert(0 != evInfo.engine->eng_events);
+
+  /* Don't continue if an error occurred or the socket got destroyed */
+  if (sock->s_header.gh_flags & (GEN_DESTROY | GEN_ERROR))
+    return;
+
+  switch (events & SOCK_ACTION_MASK) {
+  case SOCK_ACTION_SET: /* set events to given set */
+    new_events = events & SOCK_EVENT_MASK;
+    break;
+
+  case SOCK_ACTION_ADD: /* add some events */
+    new_events = sock->s_events | (events & SOCK_EVENT_MASK);
+    break;
+
+  case SOCK_ACTION_DEL: /* remove some events */
+    new_events = sock->s_events & ~(events & SOCK_EVENT_MASK);
+    break;
+  }
+
+  if (sock->s_events == new_events)
+    return; /* no changes have been made */
+
+  /* tell engine about event mask change */
+  (*evInfo.engine->eng_events)(sock, new_events);
+
+  sock->s_events = new_events; /* set new events */
+}
+
+/** Returns the current engine's name for informational purposes.
+ * @return Pointer to a static buffer containing the engine name.
+ */
+const char*
+engine_name(void)
+{
+  assert(0 != evInfo.engine);
+  assert(0 != evInfo.engine->eng_name);
+
+  return evInfo.engine->eng_name;
+}
+
+#ifdef DEBUGMODE
+/* These routines pretty-print names for states and types for debug printing */
+
+/** Declares a struct variable containing name(s) and value(s) of \a TYPE. */
+#define NS(TYPE) \
+struct {       \
+  char *name;  \
+  TYPE value;  \
+}
+
+/** Declares an element initialize for an NS() struct. */
+#define NM(name)       { #name, name }
+
+/** Declares end of an NS() struct array. */
+#define NE             { 0 }
+
+/** Looks up name for a socket state.
+ * @param[in] state &Socket state to look up.
+ * @return Pointer to a static buffer containing the name, or "Undefined socket state".
+ */
+const char*
+state_to_name(enum SocketState state)
+{
+  int i;
+  NS(enum SocketState) map[] = {
+    NM(SS_CONNECTING),
+    NM(SS_LISTENING),
+    NM(SS_CONNECTED),
+    NM(SS_DATAGRAM),
+    NM(SS_CONNECTDG),
+    NM(SS_NOTSOCK),
+    NE
+  };
+
+  for (i = 0; map[i].name; i++)
+    if (map[i].value == state)
+      return map[i].name;
+
+  return "Undefined socket state";
+}
+
+/** Looks up name for a timer type.
+ * @param[in] type &Timer type to look up.
+ * @return Pointer to a static buffer containing the name, or "Undefined timer type".
+ */
+const char*
+timer_to_name(enum TimerType type)
+{
+  int i;
+  NS(enum TimerType) map[] = {
+    NM(TT_ABSOLUTE),
+    NM(TT_RELATIVE),
+    NM(TT_PERIODIC),
+    NE
+  };
+
+  for (i = 0; map[i].name; i++)
+    if (map[i].value == type)
+      return map[i].name;
+
+  return "Undefined timer type";
+}
+
+/** Looks up name for an event type.
+ * @param[in] type &Event type to look up.
+ * @return Pointer to a static buffer containing the name, or "Undefined event type".
+ */
+const char*
+event_to_name(enum EventType type)
+{
+  int i;
+  NS(enum EventType) map[] = {
+    NM(ET_READ),
+    NM(ET_WRITE),
+    NM(ET_ACCEPT),
+    NM(ET_CONNECT),
+    NM(ET_EOF),
+    NM(ET_ERROR),
+    NM(ET_SIGNAL),
+    NM(ET_EXPIRE),
+    NM(ET_DESTROY),
+    NE
+  };
+
+  for (i = 0; map[i].name; i++)
+    if (map[i].value == type)
+      return map[i].name;
+
+  return "Undefined event type";
+}
+
+/** Constructs a string describing certain generator flags.
+ * @param[in] flags Bitwise combination of generator flags.
+ * @return Pointer to a static buffer containing the names of flags set in \a flags.
+ */
+const char*
+gen_flags(unsigned int flags)
+{
+  int i, loc = 0;
+  static char buf[256];
+  NS(unsigned int) map[] = {
+    NM(GEN_DESTROY),
+    NM(GEN_MARKED),
+    NM(GEN_ACTIVE),
+    NM(GEN_READD),
+    NM(GEN_ERROR),
+    NE
+  };
+
+  buf[0] = '\0';
+
+  for (i = 0; map[i].name; i++)
+    if (map[i].value & flags) {
+      if (loc != 0)
+       buf[loc++] = ' ';
+      loc += ircd_snprintf(0, buf + loc, sizeof(buf) - loc, "%s", map[i].name);
+      if (loc >= sizeof(buf))
+       return buf; /* overflow case */
+    }
+
+  return buf;
+}
+
+/** Constructs a string describing certain socket flags.
+ * @param[in] flags Bitwise combination of socket flags.
+ * @return Pointer to a static buffer containing the names of flags set in \a flags.
+ */
+const char*
+sock_flags(unsigned int flags)
+{
+  int i, loc = 0;
+  static char buf[256];
+  NS(unsigned int) map[] = {
+    NM(SOCK_EVENT_READABLE),
+    NM(SOCK_EVENT_WRITABLE),
+    NM(SOCK_ACTION_SET),
+    NM(SOCK_ACTION_ADD),
+    NM(SOCK_ACTION_DEL),
+    NE
+  };
+
+  buf[0] = '\0';
+
+  for (i = 0; map[i].name; i++)
+    if (map[i].value & flags) {
+      if (loc != 0)
+       buf[loc++] = ' ';
+      loc += ircd_snprintf(0, buf + loc, sizeof(buf) - loc, "%s", map[i].name);
+      if (loc >= sizeof(buf))
+       return buf; /* overflow case */
+    }
+
+  return buf;
+}
+
+#endif /* DEBUGMODE */
diff --git a/ircd/ircd_features.c b/ircd/ircd_features.c
new file mode 100644 (file)
index 0000000..ca268bc
--- /dev/null
@@ -0,0 +1,918 @@
+/*
+ * IRC - Internet Relay Chat, ircd/features.c
+ * Copyright (C) 2000 Kevin L. Mitchell <klmitch@mit.edu>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+/** @file
+ * @brief Implementation of configurable feature support.
+ * @version $Id: ircd_features.c 1907 2009-02-09 04:11:04Z entrope $
+ */
+#include "config.h"
+
+#include "ircd_features.h"
+#include "channel.h"   /* list_set_default */
+#include "class.h"
+#include "client.h"
+#include "hash.h"
+#include "ircd.h"
+#include "ircd_alloc.h"
+#include "ircd_log.h"
+#include "ircd_reply.h"
+#include "ircd_string.h"
+#include "match.h"
+#include "motd.h"
+#include "msg.h"
+#include "numeric.h"
+#include "numnicks.h"
+#include "random.h"    /* random_seed_set */
+#include "s_bsd.h"
+#include "s_debug.h"
+#include "s_misc.h"
+#include "send.h"
+#include "struct.h"
+#include "sys.h"    /* FALSE bleah */
+#include "whowas.h"    /* whowas_realloc */
+
+/* #include <assert.h> -- Now using assert in ircd_log.h */
+#include <stdlib.h>
+#include <string.h>
+
+struct Client his;
+
+/** List of log output types that can be set */
+static struct LogTypes {
+  char *type; /**< Settable name. */
+  int (*set)(const char *, const char *); /**< Function to set the value. */
+  char *(*get)(const char *); /**< Function to get the value. */
+} logTypes[] = {
+  { "FILE", log_set_file, log_get_file },
+  { "FACILITY", log_set_facility, log_get_facility },
+  { "SNOMASK", log_set_snomask, log_get_snomask },
+  { "LEVEL", log_set_level, log_get_level },
+  { 0, 0, 0 }
+};
+
+/** Look up a struct LogType given the type string.
+ * @param[in] from &Client requesting type, or NULL.
+ * @param[in] type Name of log type to find.
+ * @return Pointer to the found LogType, or NULL if none was found.
+ */
+static struct LogTypes *
+feature_log_desc(struct Client* from, const char *type)
+{
+  int i;
+
+  assert(0 != type);
+
+  for (i = 0; logTypes[i].type; i++) /* find appropriate descriptor */
+    if (!ircd_strcmp(type, logTypes[i].type))
+      return &logTypes[i];
+
+  Debug((DEBUG_ERROR, "Unknown log feature type \"%s\"", type));
+  if (from) /* send an error; if from is NULL, called from conf parser */
+    send_reply(from, ERR_BADLOGTYPE, type);
+  else
+    log_write(LS_CONFIG, L_ERROR, 0, "Unknown log feature type \"%s\"", type);
+
+  return 0; /* not found */
+}
+
+/** Set the value of a log output type for a log subsystem.
+ * @param[in] from &Client trying to set the log type, or NULL.
+ * @param[in] fields Array of parameters to set.
+ * @param[in] count Number of parameters in \a fields.
+ * @return -1 to clear the mark, 0 to leave the mask alone, 1 to set the mask.
+ */
+static int
+feature_log_set(struct Client* from, const char* const* fields, int count)
+{
+  struct LogTypes *desc;
+  char *subsys;
+
+  if (count < 2) { /* set default facility */
+    if (log_set_default(count < 1 ? 0 : fields[0])) {
+      assert(count >= 1); /* should always accept default */
+
+      if (from) /* send an error */
+       send_reply(from, ERR_BADLOGVALUE, fields[0]);
+      else
+       log_write(LS_CONFIG, L_ERROR, 0,
+                 "Bad value \"%s\" for default facility", fields[0]);
+    } else
+      return count < 1 ? -1 : 1; /* tell feature to set or clear mark */
+  } else if (!(subsys = log_canon(fields[0]))) { /* no such subsystem */
+    if (from) /* send an error */
+      send_reply(from, ERR_BADLOGSYS, fields[0]);
+    else
+      log_write(LS_CONFIG, L_ERROR, 0,
+               "No such logging subsystem \"%s\"", fields[0]);
+  } else if ((desc = feature_log_desc(from, fields[1]))) { /* set value */
+    if ((*desc->set)(fields[0], count < 3 ? 0 : fields[2])) {
+      assert(count >= 3); /* should always accept default */
+
+      if (from) /* send an error */
+       send_reply(from, ERR_BADLOGVALUE, fields[2]);
+      else
+       log_write(LS_CONFIG, L_ERROR, 0,
+                 "Bad value \"%s\" for log type %s (subsystem %s)",
+                 fields[2], desc->type, subsys);
+    }
+  }
+
+  return 0;
+}
+
+/** Reset a log type for a subsystem to its default value.
+ * @param[in] from &Client trying to reset the subsystem.
+ * @param[in] fields Array of parameters to reset.
+ * @param[in] count Number of fields in \a fields.
+ * @return -1 to unmark the entry, or zero to leave it alone.
+ */
+static int
+feature_log_reset(struct Client* from, const char* const* fields, int count)
+{
+  struct LogTypes *desc;
+  char *subsys;
+
+  assert(0 != from); /* Never called by the .conf parser */
+
+  if (count < 1) { /* reset default facility */
+    log_set_default(0);
+    return -1; /* unmark this entry */
+  } else if (count < 2)
+    need_more_params(from, "RESET");
+  else if (!(subsys = log_canon(fields[0]))) /* no such subsystem */
+    send_reply(from, ERR_BADLOGSYS, fields[0]);
+  else if ((desc = feature_log_desc(from, fields[1]))) /* reset value */
+    (*desc->set)(fields[0], 0); /* default should always be accepted */
+
+  return 0;
+}
+
+/** Handle an update to FEAT_HIS_SERVERNAME. */
+static void
+feature_notify_servername(void)
+{
+  ircd_strncpy(cli_name(&his), feature_str(FEAT_HIS_SERVERNAME), HOSTLEN);
+}
+
+/** Handle an update to FEAT_HIS_SERVERINFO. */
+static void
+feature_notify_serverinfo(void)
+{
+  ircd_strncpy(cli_info(&his), feature_str(FEAT_HIS_SERVERINFO), REALLEN);
+}
+
+/** Report the value of a log setting.
+ * @param[in] from &Client asking for details.
+ * @param[in] fields Array of parameters to get.
+ * @param[in] count Number of fields in \a fields.
+ */
+static void
+feature_log_get(struct Client* from, const char* const* fields, int count)
+{
+  struct LogTypes *desc;
+  char *value, *subsys;
+
+  assert(0 != from); /* never called by .conf parser */
+
+  if (count < 1) /* return default facility */
+    send_reply(from, SND_EXPLICIT | RPL_FEATURE, ":Log facility: %s",
+              log_get_default());
+  else if (count < 2)
+    need_more_params(from, "GET");
+  else if (!(subsys = log_canon(fields[0]))) { /* no such subsystem */
+    send_reply(from, ERR_BADLOGSYS, fields[0]);
+  } else if ((desc = feature_log_desc(from, fields[1]))) {
+    if ((value = (*desc->get)(fields[0]))) /* send along value */
+      send_reply(from, SND_EXPLICIT | RPL_FEATURE,
+                ":Log %s for subsystem %s: %s", desc->type, subsys,
+                (*desc->get)(subsys));
+    else
+      send_reply(from, SND_EXPLICIT | RPL_FEATURE,
+                ":No log %s is set for subsystem %s", desc->type, subsys);
+  }
+}
+
+/** Update whether #me is a hub or not.
+ */
+static void
+feature_notify_hub(void)
+{
+  if (feature_bool(FEAT_HUB))
+    SetHub(&me);
+  else
+    ClearHub(&me);
+}
+
+/** Sets a feature to the given value.
+ * @param[in] from Client trying to set parameters.
+ * @param[in] fields Array of parameters to set.
+ * @param[in] count Number of fields in \a count.
+ * @return <0 to clear the feature mark, 0 to leave it, >0 to set the feature mark.
+ */
+typedef int  (*feat_set_call)(struct Client* from, const char* const* fields, int count);
+/** Gets the value of a feature.
+ * @param[in] from Client trying to get parameters.
+ * @param[in] fields Array of parameters to set.
+ * @param[in] count Number of fields in \a count.
+ */
+typedef void (*feat_get_call)(struct Client* from, const char* const* fields, int count);
+/** Callback to notify of a feature's change. */
+typedef void (*feat_notify_call)(void);
+/** Unmarks all sub-feature values prior to reading .conf. */
+typedef void (*feat_unmark_call)(void);
+/** Resets to defaults all currently unmarked values.
+ * @param[in] marked Non-zero if the feature is marked.
+ */
+typedef int  (*feat_mark_call)(int marked);
+/* Reports features as a /stats f list.
+ * @param[in] sptr Client asking for feature list.
+ * @param[in] marked Non-zero if the feature is marked.
+ */
+typedef void (*feat_report_call)(struct Client* sptr, int marked);
+
+#define FEAT_NONE   0x0000     /**< no value */
+#define FEAT_INT    0x0001     /**< set if entry contains an integer value */
+#define FEAT_BOOL   0x0002     /**< set if entry contains a boolean value */
+#define FEAT_STR    0x0003     /**< set if entry contains a string value */
+#define FEAT_MASK   0x000f     /**< possible value types */
+
+#define FEAT_MARK   0x0010     /**< set if entry has been changed */
+#define FEAT_NULL   0x0020     /**< NULL string is permitted */
+#define FEAT_CASE   0x0040     /**< string is case-sensitive */
+
+#define FEAT_OPER   0x0100     /**< set to display only to opers */
+#define FEAT_MYOPER 0x0200     /**< set to display only to local opers */
+#define FEAT_NODISP 0x0400     /**< feature must never be displayed */
+
+#define FEAT_READ   0x1000     /**< feature is read-only (for now, perhaps?) */
+
+/** Declare a feature with custom behavior. */
+#define F_N(type, flags, set, reset, get, notify, unmark, mark, report)              \
+  { FEAT_ ## type, #type, FEAT_NONE | (flags), 0, 0, 0, 0,                   \
+    (set), (reset), (get), (notify), (unmark), (mark), (report) }
+/** Declare a feature that takes integer values. */
+#define F_I(type, flags, v_int, notify)                                              \
+  { FEAT_ ## type, #type, FEAT_INT | (flags), 0, (v_int), 0, 0,                      \
+    0, 0, 0, (notify), 0, 0, 0 }
+/** Declare a feature that takes boolean values. */
+#define F_B(type, flags, v_int, notify)                                              \
+  { FEAT_ ## type, #type, FEAT_BOOL | (flags), 0, (v_int), 0, 0,             \
+    0, 0, 0, (notify), 0, 0, 0 }
+/** Declare a feature that takes string values. */
+#define F_S(type, flags, v_str, notify)                                              \
+  { FEAT_ ## type, #type, FEAT_STR | (flags), 0, 0, 0, (v_str),                      \
+    0, 0, 0, (notify), 0, 0, 0 }
+
+/** Table of feature descriptions. */
+static struct FeatureDesc {
+  enum Feature    feat;    /**< feature identifier */
+  char*                   type;    /**< string describing type */
+  unsigned int     flags;   /**< flags for feature */
+  int             v_int;   /**< integer value */
+  int             def_int; /**< default value */
+  char*                   v_str;   /**< string value */
+  char*                   def_str; /**< default value */
+  feat_set_call           set;     /**< set feature values */
+  feat_set_call           reset;   /**< reset feature values to defaults */
+  feat_get_call           get;     /**< get feature values */
+  feat_notify_call notify;  /**< notify of value change */
+  feat_unmark_call unmark;  /**< unmark all feature change values */
+  feat_mark_call   mark;    /**< reset to defaults all unchanged features */
+  feat_report_call report;  /**< report feature values */
+} features[] = {
+  /* Misc. features */
+  F_N(LOG, FEAT_MYOPER, feature_log_set, feature_log_reset, feature_log_get,
+      0, log_feature_unmark, log_feature_mark, log_feature_report),
+  F_S(DOMAINNAME, 0, DOMAINNAME, 0),
+  F_B(RELIABLE_CLOCK, 0, 0, 0),
+  F_I(BUFFERPOOL, 0, 27000000, 0),
+  F_B(HAS_FERGUSON_FLUSHER, 0, 0, 0),
+  F_I(CLIENT_FLOOD, 0, 1024, 0),
+  F_I(SERVER_PORT, FEAT_OPER, 4400, 0),
+  F_B(NODEFAULTMOTD, 0, 1, 0),
+  F_S(MOTD_BANNER, FEAT_NULL, 0, 0),
+  F_S(PROVIDER, FEAT_NULL, 0, 0),
+  F_B(KILL_IPMISMATCH, FEAT_OPER, 0, 0),
+  F_B(IDLE_FROM_MSG, 0, 1, 0),
+  F_B(HUB, 0, 0, feature_notify_hub),
+  F_B(WALLOPS_OPER_ONLY, 0, 0, 0),
+  F_B(NODNS, 0, 0, 0),
+  F_N(RANDOM_SEED, FEAT_NODISP, random_seed_set, 0, 0, 0, 0, 0, 0),
+  F_S(DEFAULT_LIST_PARAM, FEAT_NULL, 0, list_set_default),
+  F_I(NICKNAMEHISTORYLENGTH, 0, 800, whowas_realloc),
+  F_B(HOST_HIDING, 0, 1, 0),
+  F_S(HIDDEN_HOST, FEAT_CASE, "users.undernet.org", 0),
+  F_S(HIDDEN_IP, 0, "127.0.0.1", 0),
+  F_B(CONNEXIT_NOTICES, 0, 0, 0),
+  F_B(OPLEVELS, 0, 1, 0),
+  F_B(ZANNELS, 0, 1, 0),
+  F_B(LOCAL_CHANNELS, 0, 1, 0),
+  F_B(TOPIC_BURST, 0, 0, 0),
+  F_B(AWAY_BURST, 0, 0, 0),
+  F_B(DISABLE_GLINES, 0, 0, 0),
+  F_B(FAKE_WEBIRC, 0, 1, 0),
+  F_B(WEBIRC_UMODE, 0, 1, 0),
+  F_B(WEBIRC_REJECT, 0, 1, 0),
+  F_B(LOC_ENABLE, 0, 0, 0),
+  F_S(LOC_TARGET, FEAT_NULL, 0, 0),
+  F_B(EXCEPT_ENABLE, 0, 1, 0),
+  F_I(NOAMSG_TIME, 0, 0, 0),
+  F_I(NOAMSG_NUM, 0, 1, 0),
+
+  /* features that probably should not be touched */
+  F_I(KILLCHASETIMELIMIT, 0, 30, 0),
+  F_I(MAXCHANNELSPERUSER, 0, 10, 0),
+  F_I(NICKLEN, 0, 12, 0),
+  F_I(AVBANLEN, 0, 40, 0),
+  F_I(MAXBANS, 0, 45, 0),
+  F_I(MAXSILES, 0, 15, 0),
+  F_I(HANGONGOODLINK, 0, 300, 0),
+  F_I(HANGONRETRYDELAY, 0, 10, 0),
+  F_I(CONNECTTIMEOUT, 0, 90, 0),
+  F_I(MAXIMUM_LINKS, 0, 1, init_class), /* reinit class 0 as needed */
+  F_I(PINGFREQUENCY, 0, 120, init_class),
+  F_I(CONNECTFREQUENCY, 0, 600, init_class),
+  F_I(DEFAULTMAXSENDQLENGTH, 0, 40000, init_class),
+  F_I(GLINEMAXUSERCOUNT, 0, 20, 0),
+  F_I(SOCKSENDBUF, 0, SERVER_TCP_WINDOW, 0),
+  F_I(SOCKRECVBUF, 0, SERVER_TCP_WINDOW, 0),
+  F_I(IPCHECK_CLONE_LIMIT, 0, 4, 0),
+  F_I(IPCHECK_CLONE_PERIOD, 0, 40, 0),
+  F_I(IPCHECK_CLONE_DELAY, 0, 600, 0),
+  F_I(CHANNELLEN, 0, 200, 0),
+
+  /* Some misc. default paths */
+  F_S(MPATH, FEAT_CASE | FEAT_MYOPER, "ircd.motd", motd_init),
+  F_S(RPATH, FEAT_CASE | FEAT_MYOPER, "remote.motd", motd_init),
+  F_S(PPATH, FEAT_CASE | FEAT_MYOPER | FEAT_READ, "ircd.pid", 0),
+
+  /* Networking features */
+  F_I(TOS_SERVER, 0, 0x08, 0),
+  F_I(TOS_CLIENT, 0, 0x08, 0),
+  F_I(POLLS_PER_LOOP, 0, 200, 0),
+  F_I(IRCD_RES_RETRIES, 0, 2, 0),
+  F_I(IRCD_RES_TIMEOUT, 0, 4, 0),
+  F_I(AUTH_TIMEOUT, 0, 9, 0),
+  F_B(ANNOUNCE_INVITES, 0, 0, 0),
+
+  /* features that affect all operators */
+  F_B(CONFIG_OPERCMDS, 0, 0, 0),
+
+  /* HEAD_IN_SAND Features */
+  F_B(HIS_SNOTICES, 0, 1, 0),
+  F_B(HIS_SNOTICES_OPER_ONLY, 0, 1, 0),
+  F_B(HIS_DEBUG_OPER_ONLY, 0, 1, 0),
+  F_B(HIS_WALLOPS, 0, 1, 0),
+  F_B(HIS_MAP, 0, 1, 0),
+  F_B(HIS_LINKS, 0, 1, 0),
+  F_B(HIS_TRACE, 0, 1, 0),
+  F_B(HIS_STATS_a, 0, 1, 0),
+  F_B(HIS_STATS_c, 0, 1, 0),
+  F_B(HIS_STATS_d, 0, 1, 0),
+  F_B(HIS_STATS_e, 0, 1, 0),
+  F_B(HIS_STATS_f, 0, 1, 0),
+  F_B(HIS_STATS_g, 0, 1, 0),
+  F_B(HIS_STATS_i, 0, 1, 0),
+  F_B(HIS_STATS_j, 0, 1, 0),
+  F_B(HIS_STATS_J, 0, 1, 0),
+  F_B(HIS_STATS_k, 0, 1, 0),
+  F_B(HIS_STATS_l, 0, 1, 0),
+  F_B(HIS_STATS_L, 0, 1, 0),
+  F_B(HIS_STATS_M, 0, 1, 0),
+  F_B(HIS_STATS_m, 0, 1, 0),
+  F_B(HIS_STATS_o, 0, 1, 0),
+  F_B(HIS_STATS_p, 0, 1, 0),
+  F_B(HIS_STATS_q, 0, 1, 0),
+  F_B(HIS_STATS_R, 0, 1, 0),
+  F_B(HIS_STATS_r, 0, 1, 0),
+  F_B(HIS_STATS_t, 0, 1, 0),
+  F_B(HIS_STATS_T, 0, 1, 0),
+  F_B(HIS_STATS_u, 0, 0, 0),
+  F_B(HIS_STATS_U, 0, 1, 0),
+  F_B(HIS_STATS_v, 0, 1, 0),
+  F_B(HIS_STATS_w, 0, 0, 0),
+  F_B(HIS_STATS_x, 0, 1, 0),
+  F_B(HIS_STATS_y, 0, 1, 0),
+  F_B(HIS_STATS_z, 0, 1, 0),
+  F_B(HIS_STATS_IAUTH, 0, 1, 0),
+  F_B(HIS_WHOIS_SERVERNAME, 0, 1, 0),
+  F_B(HIS_WHOIS_IDLETIME, 0, 1, 0),
+  F_B(HIS_WHOIS_LOCALCHAN, 0, 1, 0),
+  F_B(HIS_WHO_SERVERNAME, 0, 1, 0),
+  F_B(HIS_WHO_HOPCOUNT, 0, 1, 0),
+  F_B(HIS_MODEWHO, 0, 1, 0),
+  F_B(HIS_BANWHO, 0, 1, 0),
+  F_B(HIS_KILLWHO, 0, 1, 0),
+  F_B(HIS_REWRITE, 0, 1, 0),
+  F_I(HIS_REMOTE, 0, 1, 0),
+  F_B(HIS_NETSPLIT, 0, 1, 0),
+  F_S(HIS_SERVERNAME, 0, "*.undernet.org", feature_notify_servername),
+  F_S(HIS_SERVERINFO, 0, "The Undernet Underworld", feature_notify_serverinfo),
+  F_S(HIS_URLSERVERS, 0, "http://www.undernet.org/servers.php", 0),
+
+  /* Misc. random stuff */
+  F_S(NETWORK, 0, "UnderNet", 0),
+  F_S(URL_CLIENTS, 0, "ftp://ftp.undernet.org/pub/irc/clients", 0),
+  F_S(URLREG, 0, "http://cservice.undernet.org/live/", 0),
+
+  F_B(UNKNOWN_CMD_ENABLE, 0, 0, 0),
+  F_S(UNKNOWN_CMD_TARGET, FEAT_NULL, 0, 0),
+  F_B(CHMODE_A_ENABLE, 0, 0, 0),
+  F_S(CHMODE_A_TARGET, FEAT_NULL, 0, 0),
+  F_B(CHMODE_F_ENABLE, 0, 0, 0),
+  
+#undef F_S
+#undef F_B
+#undef F_I
+#undef F_N
+  { FEAT_LAST_F, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
+};
+
+/** Given a feature's identifier, look up the feature descriptor.
+ * @param[in] from Client looking up feature, or NULL.
+ * @param[in] feature Feature name to find.
+ * @return Pointer to a FeatureDesc, or NULL if none was found.
+ */
+static struct FeatureDesc *
+feature_desc(struct Client* from, const char *feature)
+{
+  int i;
+
+  assert(0 != feature);
+
+  for (i = 0; features[i].type; i++) /* find appropriate descriptor */
+    if (!strcmp(feature, features[i].type))
+      return &features[i];
+
+  Debug((DEBUG_ERROR, "Unknown feature \"%s\"", feature));
+  if (from) /* report an error */
+    send_reply(from, ERR_NOFEATURE, feature);
+  else
+    log_write(LS_CONFIG, L_ERROR, 0, "Unknown feature \"%s\"", feature);
+
+  return 0; /* not found */
+}
+
+/** Given a feature vector string, set the value of a feature.
+ * @param[in] from Client trying to set the feature, or NULL.
+ * @param[in] fields Parameters to set, starting with feature name.
+ * @param[in] count Number of fields in \a fields.
+ * @return Zero (or, theoretically, CPTR_KILLED).
+ */
+int
+feature_set(struct Client* from, const char* const* fields, int count)
+{
+  int i, change = 0, tmp;
+  const char *t_str;
+  struct FeatureDesc *feat;
+
+  if (from && !HasPriv(from, PRIV_SET))
+    return send_reply(from, ERR_NOPRIVILEGES);
+
+  if (count < 1) {
+    if (from) /* report an error in the number of arguments */
+      need_more_params(from, "SET");
+    else
+      log_write(LS_CONFIG, L_ERROR, 0, "Not enough fields in F line");
+  } else if ((feat = feature_desc(from, fields[0]))) { /* find feature */
+    if (from && feat->flags & FEAT_READ)
+      return send_reply(from, ERR_NOFEATURE, fields[0]);
+
+    switch (feat->flags & FEAT_MASK) {
+    case FEAT_NONE:
+      if (feat->set && (i = (*feat->set)(from, fields + 1, count - 1))) {
+       change++; /* feature handler wants a change recorded */
+
+       if (i > 0) /* call the set callback and do marking */
+         feat->flags |= FEAT_MARK;
+       else /* i < 0 */
+         feat->flags &= ~FEAT_MARK;
+       break;
+      }
+
+    case FEAT_INT: /* an integer value */
+      tmp = feat->v_int; /* detect changes... */
+
+      if (count < 2) { /* reset value */
+       feat->v_int = feat->def_int;
+       feat->flags &= ~FEAT_MARK;
+      } else { /* ok, figure out the value and whether to mark it */
+       feat->v_int = strtoul(fields[1], 0, 0);
+       if (feat->v_int == feat->def_int)
+         feat->flags &= ~FEAT_MARK;
+       else
+         feat->flags |= FEAT_MARK;
+      }
+
+      if (feat->v_int != tmp) /* check for change */
+       change++;
+      break;
+
+    case FEAT_BOOL: /* it's a boolean value--true or false */
+      tmp = feat->v_int; /* detect changes... */
+
+      if (count < 2) { /* reset value */
+       feat->v_int = feat->def_int;
+       feat->flags &= ~FEAT_MARK;
+      } else { /* figure out the value and whether to mark it */
+       if (!ircd_strncmp(fields[1], "TRUE", strlen(fields[1])) ||
+           !ircd_strncmp(fields[1], "YES", strlen(fields[1])) ||
+           (strlen(fields[1]) >= 2 &&
+            !ircd_strncmp(fields[1], "ON", strlen(fields[1]))))
+         feat->v_int = 1;
+       else if (!ircd_strncmp(fields[1], "FALSE", strlen(fields[1])) ||
+                !ircd_strncmp(fields[1], "NO", strlen(fields[1])) ||
+                (strlen(fields[1]) >= 2 &&
+                 !ircd_strncmp(fields[1], "OFF", strlen(fields[1]))))
+         feat->v_int = 0;
+       else if (from) /* report an error... */
+         return send_reply(from, ERR_BADFEATVALUE, fields[1], feat->type);
+       else {
+         log_write(LS_CONFIG, L_ERROR, 0, "Bad value \"%s\" for feature %s",
+                   fields[1], feat->type);
+         return 0;
+       }
+
+       if (feat->v_int == feat->def_int) /* figure out whether to mark it */
+         feat->flags &= ~FEAT_MARK;
+       else
+         feat->flags |= FEAT_MARK;
+      }
+
+      if (feat->v_int != tmp) /* check for change */
+       change++;
+      break;
+
+    case FEAT_STR: /* it's a string value */
+      if (count < 2)
+       t_str = feat->def_str; /* changing to default */
+      else
+       t_str = *fields[1] ? fields[1] : 0;
+
+      if (!t_str && !(feat->flags & FEAT_NULL)) { /* NULL value permitted? */
+       if (from)
+         return send_reply(from, ERR_BADFEATVALUE, "NULL", feat->type);
+       else {
+         log_write(LS_CONFIG, L_ERROR, 0, "Bad value \"NULL\" for feature %s",
+                   feat->type);
+         return 0;
+       }
+      }
+
+      if (t_str == feat->def_str ||
+         (t_str && feat->def_str &&
+          !(feat->flags & FEAT_CASE ? strcmp(t_str, feat->def_str) :
+            ircd_strcmp(t_str, feat->def_str)))) { /* resetting to default */
+       if (feat->v_str != feat->def_str) {
+         change++; /* change from previous value */
+
+         if (feat->v_str)
+           MyFree(feat->v_str); /* free old value */
+       }
+
+       feat->v_str = feat->def_str; /* very special... */
+
+       feat->flags &= ~FEAT_MARK;
+      } else if (!t_str) {
+       if (feat->v_str) {
+         change++; /* change from previous value */
+
+         if (feat->v_str != feat->def_str)
+           MyFree(feat->v_str); /* free old value */
+       }
+
+       feat->v_str = 0; /* set it to NULL */
+
+       feat->flags |= FEAT_MARK;
+      } else if (!feat->v_str ||
+                (feat->flags & FEAT_CASE ? strcmp(t_str, feat->v_str) :
+                 ircd_strcmp(t_str, feat->v_str))) { /* new value */
+       change++; /* change from previous value */
+
+       if (feat->v_str && feat->v_str != feat->def_str)
+         MyFree(feat->v_str); /* free old value */
+       DupString(feat->v_str, t_str); /* store new value */
+
+       feat->flags |= FEAT_MARK;
+      } else /* they match, but don't match the default */
+       feat->flags |= FEAT_MARK;
+      break;
+    }
+
+    if (change && feat->notify) /* call change notify function */
+      (*feat->notify)();
+
+    if (from)
+      return feature_get(from, fields, count);
+  }
+
+  return 0;
+}
+
+/** Reset a feature to its default values.
+ * @param[in] from Client trying to reset the feature, or NULL.
+ * @param[in] fields Parameters to set, starting with feature name.
+ * @param[in] count Number of fields in \a fields.
+ * @return Zero (or, theoretically, CPTR_KILLED).
+ */
+int
+feature_reset(struct Client* from, const char* const* fields, int count)
+{
+  int i, change = 0;
+  struct FeatureDesc *feat;
+
+  assert(0 != from);
+
+  if (!HasPriv(from, PRIV_SET))
+    return send_reply(from, ERR_NOPRIVILEGES);
+
+  if (count < 1) /* check arguments */
+    need_more_params(from, "RESET");
+  else if ((feat = feature_desc(from, fields[0]))) { /* get descriptor */
+    if (from && feat->flags & FEAT_READ)
+      return send_reply(from, ERR_NOFEATURE, fields[0]);
+
+    switch (feat->flags & FEAT_MASK) {
+    case FEAT_NONE: /* None... */
+      if (feat->reset && (i = (*feat->reset)(from, fields + 1, count - 1))) {
+       change++; /* feature handler wants a change recorded */
+
+       if (i > 0) /* call reset callback and parse mark return */
+         feat->flags |= FEAT_MARK;
+       else /* i < 0 */
+         feat->flags &= ~FEAT_MARK;
+      }
+      break;
+
+    case FEAT_INT:  /* Integer... */
+    case FEAT_BOOL: /* Boolean... */
+      if (feat->v_int != feat->def_int)
+       change++; /* change will be made */
+
+      feat->v_int = feat->def_int; /* set the default */
+      feat->flags &= ~FEAT_MARK; /* unmark it */
+      break;
+
+    case FEAT_STR: /* string! */
+      if (feat->v_str != feat->def_str) {
+       change++; /* change has been made */
+       if (feat->v_str)
+         MyFree(feat->v_str); /* free old value */
+      }
+
+      feat->v_str = feat->def_str; /* set it to default */
+      feat->flags &= ~FEAT_MARK; /* unmark it */
+      break;
+    }
+
+    if (change && feat->notify) /* call change notify function */
+      (*feat->notify)();
+
+    if (from)
+      return feature_get(from, fields, count);
+  }
+
+  return 0;
+}
+
+/** Gets the value of a specific feature and reports it to the user.
+ * @param[in] from Client trying to get the feature.
+ * @param[in] fields Parameters to set, starting with feature name.
+ * @param[in] count Number of fields in \a fields.
+ * @return Zero (or, theoretically, CPTR_KILLED).
+ */
+int
+feature_get(struct Client* from, const char* const* fields, int count)
+{
+  struct FeatureDesc *feat;
+
+  assert(0 != from);
+
+  if (count < 1) /* check parameters */
+    need_more_params(from, "GET");
+  else if ((feat = feature_desc(from, fields[0]))) {
+    if ((feat->flags & FEAT_NODISP) ||
+       (feat->flags & FEAT_MYOPER && !MyOper(from)) ||
+       (feat->flags & FEAT_OPER && !IsAnOper(from))) /* check privs */
+      return send_reply(from, ERR_NOPRIVILEGES);
+
+    switch (feat->flags & FEAT_MASK) {
+    case FEAT_NONE: /* none, call the callback... */
+      if (feat->get) /* if there's a callback, use it */
+       (*feat->get)(from, fields + 1, count - 1);
+      break;
+
+    case FEAT_INT: /* integer, report integer value */
+      send_reply(from, SND_EXPLICIT | RPL_FEATURE,
+                ":Integer value of %s: %d", feat->type, feat->v_int);
+      break;
+
+    case FEAT_BOOL: /* boolean, report boolean value */
+      send_reply(from, SND_EXPLICIT | RPL_FEATURE,
+                ":Boolean value of %s: %s", feat->type,
+                feat->v_int ? "TRUE" : "FALSE");
+      break;
+
+    case FEAT_STR: /* string, report string value */
+      if (feat->v_str) /* deal with null case */
+       send_reply(from, SND_EXPLICIT | RPL_FEATURE,
+                  ":String value of %s: %s", feat->type, feat->v_str);
+      else
+       send_reply(from, SND_EXPLICIT | RPL_FEATURE,
+                  ":String value for %s not set", feat->type);
+      break;
+    }
+  }
+
+  return 0;
+}
+
+/** Called before reading the .conf to clear all dirty marks. */
+void
+feature_unmark(void)
+{
+  int i;
+
+  for (i = 0; features[i].type; i++) {
+    features[i].flags &= ~FEAT_MARK; /* clear the marks... */
+    if (features[i].unmark) /* call the unmark callback if necessary */
+      (*features[i].unmark)();
+  }
+}
+
+/** Called after reading the .conf to reset unmodified values to defaults. */
+void
+feature_mark(void)
+{
+  int i, change;
+
+  for (i = 0; features[i].type; i++) {
+    change = 0;
+
+    switch (features[i].flags & FEAT_MASK) {
+    case FEAT_NONE:
+      if (features[i].mark &&
+         (*features[i].mark)(features[i].flags & FEAT_MARK ? 1 : 0))
+       change++; /* feature handler wants a change recorded */
+      break;
+
+    case FEAT_INT:  /* Integers or Booleans... */
+    case FEAT_BOOL:
+      if (!(features[i].flags & FEAT_MARK)) { /* not changed? */
+       if (features[i].v_int != features[i].def_int)
+         change++; /* we're making a change */
+       features[i].v_int = features[i].def_int;
+      }
+      break;
+
+    case FEAT_STR: /* strings... */
+      if (!(features[i].flags & FEAT_MARK)) { /* not changed? */
+       if (features[i].v_str != features[i].def_str) {
+         change++; /* we're making a change */
+         if (features[i].v_str)
+           MyFree(features[i].v_str); /* free old value */
+       }
+       features[i].v_str = features[i].def_str;
+      }
+      break;
+    }
+
+    if (change && features[i].notify)
+      (*features[i].notify)(); /* call change notify function */
+  }
+}
+
+/** Initialize the features subsystem. */
+void
+feature_init(void)
+{
+  int i;
+
+  for (i = 0; features[i].type; i++) {
+    switch (features[i].flags & FEAT_MASK) {
+    case FEAT_NONE: /* you're on your own */
+      break;
+
+    case FEAT_INT:  /* Integers or Booleans... */
+    case FEAT_BOOL:
+      features[i].v_int = features[i].def_int;
+      break;
+
+    case FEAT_STR:  /* Strings */
+      features[i].v_str = features[i].def_str;
+      assert(features[i].def_str || (features[i].flags & FEAT_NULL));
+      break;
+    }
+  }
+
+  cli_magic(&his) = CLIENT_MAGIC;
+  cli_status(&his) = STAT_SERVER;
+  feature_notify_servername();
+  feature_notify_serverinfo();
+}
+
+/** Report all F-lines to a user.
+ * @param[in] to Client requesting statistics.
+ * @param[in] sd Stats descriptor for request (ignored).
+ * @param[in] param Extra parameter from user (ignored).
+ */
+void
+feature_report(struct Client* to, const struct StatDesc* sd, char* param)
+{
+  int i;
+
+  for (i = 0; features[i].type; i++) {
+    if ((features[i].flags & FEAT_NODISP) ||
+       (features[i].flags & FEAT_MYOPER && !MyOper(to)) ||
+       (features[i].flags & FEAT_OPER && !IsAnOper(to)))
+      continue; /* skip this one */
+
+    switch (features[i].flags & FEAT_MASK) {
+    case FEAT_NONE:
+      if (features[i].report) /* let the callback handle this */
+       (*features[i].report)(to, features[i].flags & FEAT_MARK ? 1 : 0);
+      break;
+
+
+    case FEAT_INT: /* Report an F-line with integer values */
+      if (features[i].flags & FEAT_MARK) /* it's been changed */
+       send_reply(to, SND_EXPLICIT | RPL_STATSFLINE, "F %s %d",
+                  features[i].type, features[i].v_int);
+      break;
+
+    case FEAT_BOOL: /* Report an F-line with boolean values */
+      if (features[i].flags & FEAT_MARK) /* it's been changed */
+       send_reply(to, SND_EXPLICIT | RPL_STATSFLINE, "F %s %s",
+                  features[i].type, features[i].v_int ? "TRUE" : "FALSE");
+      break;
+
+    case FEAT_STR: /* Report an F-line with string values */
+      if (features[i].flags & FEAT_MARK) { /* it's been changed */
+       if (features[i].v_str)
+         send_reply(to, SND_EXPLICIT | RPL_STATSFLINE, "F %s %s",
+                    features[i].type, features[i].v_str);
+       else /* Actually, F:<type> would reset it; you want F:<type>: */
+         send_reply(to, SND_EXPLICIT | RPL_STATSFLINE, "F %s",
+                    features[i].type);
+      }
+      break;
+    }
+  }
+}
+
+/** Return a feature's integer value.
+ * @param[in] feat &Feature identifier.
+ * @return Integer value of feature.
+ */
+int
+feature_int(enum Feature feat)
+{
+  assert(features[feat].feat == feat);
+  assert((features[feat].flags & FEAT_MASK) == FEAT_INT);
+
+  return features[feat].v_int;
+}
+
+/** Return a feature's boolean value.
+ * @param[in] feat &Feature identifier.
+ * @return Boolean value of feature.
+ */
+int
+feature_bool(enum Feature feat)
+{
+  assert(feat <= FEAT_LAST_F);
+  if (FEAT_LAST_F < feat)
+    return 0;
+  assert(features[feat].feat == feat);
+  assert((features[feat].flags & FEAT_MASK) == FEAT_BOOL);
+
+  return features[feat].v_int;
+}
+
+/** Return a feature's string value.
+ * @param[in] feat &Feature identifier.
+ * @return String value of feature.
+ */
+const char *
+feature_str(enum Feature feat)
+{
+  assert(features[feat].feat == feat);
+  assert((features[feat].flags & FEAT_MASK) == FEAT_STR);
+
+  return features[feat].v_str;
+}
diff --git a/ircd/ircd_lexer.l b/ircd/ircd_lexer.l
new file mode 100644 (file)
index 0000000..859249e
--- /dev/null
@@ -0,0 +1,275 @@
+/*
+ * ircd_lexer.l: A lexical scanner for ircd config files.
+ * This is part of ircu, an Internet Relay Chat server.
+ * The contents of this file are Copyright(C) 2001 by Andrew Miller, the
+ * ircd-hybrid team and the ircu team.
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ *  USA.
+ * $Id: ircd_lexer.l 1851 2007-11-30 22:10:04Z klmitch $
+ */
+
+%{
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "config.h"
+#include "fileio.h"
+#include "ircd.h"
+#include "ircd_alloc.h"
+#include "ircd_string.h"
+#include "s_debug.h"
+#include "y.tab.h"
+
+extern int lineno;
+
+static struct lexer_token {
+  const char *string;
+  int value;
+} tokens[] = {
+#define TOKEN(NAME) { #NAME, NAME }
+  TOKEN(ADMIN),
+  TOKEN(GENERAL),
+  TOKEN(LOCATION),
+  TOKEN(CONTACT),
+  TOKEN(CLASS),
+  TOKEN(PINGFREQ),
+  TOKEN(CONNECT),
+  TOKEN(CONNECTFREQ),
+  TOKEN(MAXLINKS),
+  TOKEN(MAXHOPS),
+  TOKEN(SENDQ),
+  TOKEN(NAME),
+  TOKEN(HOST),
+  TOKEN(IP),
+  TOKEN(USERNAME),
+  TOKEN(PASS),
+  TOKEN(SECONDS),
+  TOKEN(MINUTES),
+  TOKEN(HOURS),
+  TOKEN(DAYS),
+  TOKEN(WEEKS),
+  TOKEN(MONTHS),
+  TOKEN(YEARS),
+  TOKEN(DECADES),
+  TOKEN(BYTES),
+  TOKEN(KBYTES),
+  TOKEN(MBYTES),
+  TOKEN(GBYTES),
+  TOKEN(TBYTES),
+  TOKEN(PORT),
+  TOKEN(SERVER),
+  TOKEN(YES),
+  TOKEN(NO),
+  TOKEN(HUB),
+  TOKEN(LEAF),
+  TOKEN(UWORLD),
+  TOKEN(OPER),
+  TOKEN(LOCAL),
+  TOKEN(VHOST),
+  TOKEN(MASK),
+  TOKEN(HIDDEN),
+  TOKEN(MOTD),
+  TOKEN(NUMERIC),
+  TOKEN(NICK),
+  TOKEN(JUPE),
+  TOKEN(DESCRIPTION),
+  TOKEN(CLIENT),
+  TOKEN(REAL),
+  TOKEN(REASON),
+  TOKEN(RULE),
+  TOKEN(ALL),
+  TOKEN(CRULE),
+  TOKEN(KILL),
+  TOKEN(QUARANTINE),
+  TOKEN(IAUTH),
+  TOKEN(TIMEOUT),
+  TOKEN(FEATURES),
+  TOKEN(CHANNEL),
+  TOKEN(PSEUDO),
+  TOKEN(PREPEND),
+  TOKEN(USERMODE),
+  TOKEN(FAST),
+  TOKEN(AUTOCONNECT),
+  TOKEN(PROGRAM),
+  TOKEN(DNS),
+  TOKEN(FORWARDS),
+  TOKEN(SECURE),
+  TOKEN(WEBIRC),
+  TOKEN(SPOOF),
+  TOKEN(REQUIRED),
+  TOKEN(SSL),
+  TOKEN(CERT),
+  TOKEN(CACERT),
+#undef TOKEN
+  { "administrator", ADMIN },
+  { "apass_opmode", TPRIV_APASS_OPMODE },
+  { "auto", AUTOCONNECT },
+  { "b", BYTES },
+  { "badchan", TPRIV_BADCHAN },
+  { "chan_limit", TPRIV_CHAN_LIMIT },
+  { "deop_lchan", TPRIV_DEOP_LCHAN },
+  { "die", TPRIV_DIE },
+  { "display", TPRIV_DISPLAY },
+  { "file", TFILE },
+  { "force_local_opmode", TPRIV_FORCE_LOCAL_OPMODE },
+  { "force_opmode", TPRIV_FORCE_OPMODE },
+  { "gb", GBYTES },
+  { "gigabytes", GBYTES },
+  { "gline", TPRIV_GLINE },
+#ifdef OLD_OGN_IRCU_COMPAT
+  { "hide_channels", TPRIV_UMODE_NOCHAN },
+  { "hide_idletime", TPRIV_UMODE_NOIDLE },
+#endif
+  { "umode_nochan", TPRIV_UMODE_NOCHAN },
+  { "umode_noidle", TPRIV_UMODE_NOIDLE },
+  { "extra_hide_idletime", TPRIV_HIDE_IDLETIME },
+#ifndef OLD_OGN_IRCU_COMPAT
+  { "hide_idletime", TPRIV_HIDE_IDLETIME },
+#endif
+  { "ipv4", TOK_IPV4 },
+  { "ipv6", TOK_IPV6 },
+  { "kb", KBYTES },
+  { "kilobytes", KBYTES },
+  { "list_chan", TPRIV_LIST_CHAN },
+  { "local_badchan", TPRIV_LOCAL_BADCHAN },
+  { "local_gline", TPRIV_LOCAL_GLINE },
+  { "local_jupe", TPRIV_LOCAL_JUPE },
+  { "local_kill", TPRIV_LOCAL_KILL },
+  { "local_opmode", TPRIV_LOCAL_OPMODE },
+  { "maxchans", MAXCHANS },
+  { "mb", MBYTES },
+  { "megabytes", MBYTES },
+  { "mode_lchan", TPRIV_MODE_LCHAN },
+  { "more_flood", TPRIV_HALFFLOOD },
+  { "noamsg_override", TPRIV_NOAMSG_OVERRIDE },
+  { "operator", OPER },
+  { "opmode", TPRIV_OPMODE },
+  { "password", PASS },
+  { "propagate", TPRIV_PROPAGATE },
+  { "realname", REAL },
+  { "rehash", TPRIV_REHASH },
+  { "restart", TPRIV_RESTART },
+  { "see_chan", TPRIV_SEE_CHAN },
+  { "see_idletime", TPRIV_SEE_IDLETIME },
+  { "see_opers", TPRIV_SEE_OPERS },
+  { "set", TPRIV_SET },
+  { "show_all_invis", TPRIV_SHOW_ALL_INVIS },
+  { "show_invis", TPRIV_SHOW_INVIS },
+#ifdef OLD_OGN_IRCU_COMPAT
+  { "targetchange", TPRIV_UNLIMITED_TARGET },
+#endif
+  { "unlimited_targets", TPRIV_UNLIMITED_TARGET },
+  { "tb", TBYTES },
+  { "terabytes", TBYTES },
+  { "umode_chserv", TPRIV_UMODE_CHSERV },
+  { "umode_xtraop", TPRIV_UMODE_XTRAOP },
+  { "umode_netserv", TPRIV_UMODE_NETSERV },
+  { "umode_overridecc", TPRIV_UMODE_OVERRIDECC },
+  { "unlimit_query", TPRIV_UNLIMIT_QUERY },
+  { "unlimited_flood", TPRIV_FLOOD },
+  { "walk_lchan", TPRIV_WALK_LCHAN },
+  { "wide_gline", TPRIV_WIDE_GLINE },
+  { "whox", TPRIV_WHOX },
+  { NULL, 0 }
+};
+static int ntokens;
+
+static int
+token_compare(const void *pa, const void *pb)
+{
+  const struct lexer_token *ta = pa;
+  const struct lexer_token *tb = pb;
+  unsigned int ii = 0;
+  int res;
+  while (ta->string[ii] && (ToLower(ta->string[ii]) == ToLower(tb->string[ii])))
+    ii++;
+  res = ToLower(tb->string[ii]) - ToLower(ta->string[ii]);
+  return res;
+}
+
+static void
+init_ntokens(void)
+{
+  for (ntokens = 0; tokens[ntokens].string; ++ntokens) ;
+  qsort(tokens, ntokens, sizeof(tokens[0]), token_compare);
+}
+
+static int
+find_token(char *token)
+{
+  struct lexer_token *tok;
+  if (!ntokens)
+    init_ntokens();
+  tok = bsearch(&token, tokens, ntokens, sizeof(tokens[0]), token_compare);
+  return tok ? tok->value : 0;
+}
+
+static FBFILE *lexer_input;
+
+#undef YY_INPUT
+#define YY_INPUT(buf, res, size) res = (fbgets(buf, size, lexer_input) ? strlen(buf) : 0)
+
+int
+init_lexer(void)
+{
+  lexer_input = fbopen(configfile, "r");
+  if (lexer_input == NULL)
+  {
+#ifdef YY_FATAL_ERROR
+    YY_FATAL_ERROR("Could not open the configuration file.");
+#else
+    fprintf(stderr, "Could not open the configuration file.");
+#endif
+    return 0;
+  }
+#ifdef YY_NEW_FILE
+  YY_NEW_FILE;
+#endif
+  lineno = 1;
+  return 1;
+}
+
+void deinit_lexer(void)
+{
+  if (lexer_input != NULL)
+  {
+    fbclose(lexer_input);
+    lexer_input = NULL;
+  }
+}
+
+int
+yywrap(void)
+{
+  return 1;
+}
+
+%}
+
+WHITE [ \t\r]+
+SHCOMMENT #[^\n]*
+NUMBER [0-9]+
+QSTRING \"[^"\n]+[\"\n]
+%%
+
+{QSTRING} {yytext[yyleng-1] = 0; DupString(yylval.text, yytext+1); return QSTRING;}
+{NUMBER} {yylval.num = strtoul(yytext, NULL, 10); return NUMBER;}
+{WHITE} ;
+{SHCOMMENT} ;
+
+[a-zA-Z_][a-zA-Z_0-9]* { int res = find_token(yytext); if (res) return res; else REJECT; }
+\n lineno++;
+. return yytext[0];
diff --git a/ircd/ircd_log.c b/ircd/ircd_log.c
new file mode 100644 (file)
index 0000000..8042b13
--- /dev/null
@@ -0,0 +1,990 @@
+/************************************************************************
+ *   IRC - Internet Relay Chat, src/ircd_log.c
+ *   Copyright (C) 1999 Thomas Helvey (BleepSoft)
+ *   Copyright (C) 2000 Kevin L. Mitchell <klmitch@mit.edu>
+ *
+ *   See file AUTHORS in IRC package for additional names of
+ *   the programmers.
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 1, or (at your option)
+ *   any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+/** @file
+ * @brief IRC logging implementation.
+ * @version $Id: ircd_log.c 1620 2006-02-16 03:49:55Z entrope $
+ */
+#include "config.h"
+
+#include "ircd_log.h"
+#include "client.h"
+#include "ircd_alloc.h"
+#include "ircd_reply.h"
+#include "ircd_snprintf.h"
+#include "ircd_string.h"
+#include "ircd.h"
+#include "numeric.h"
+#include "s_debug.h"
+#include "send.h"
+#include "struct.h"
+
+/* #include <assert.h> -- Now using assert in ircd_log.h */
+#include <errno.h>
+#include <fcntl.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/uio.h>
+#include <syslog.h>
+#include <time.h>
+#include <unistd.h>
+
+int log_inassert = 0;
+
+#define LOG_BUFSIZE 2048 /**< Maximum length for a log message. */
+
+/** Select default log level cutoff. */
+#ifdef DEBUGMODE
+# define L_DEFAULT     L_DEBUG
+#else
+# define L_DEFAULT     L_INFO
+#endif
+
+#define LOG_DOSYSLOG   0x10 /**< Try to use syslog. */
+#define LOG_DOFILELOG  0x20 /**< Try to log to a file. */
+#define LOG_DOSNOTICE  0x40 /**< Try to notify operators via notice. */
+/** Bitmask of valid delivery mechanisms. */
+#define LOG_DOMASK     (LOG_DOSYSLOG | LOG_DOFILELOG | LOG_DOSNOTICE)
+
+/** Map severity levels to strings and syslog levels */
+static struct LevelData {
+  enum LogLevel level;   /**< Log level being described. */
+  char        *string;  /**< Textual name of level. */
+  int          syslog;  /**< Syslog priority for log level. */
+  unsigned int snomask; /**< Server notice mask; 0 means use default in LogDesc. */
+} levelData[] = {
+#define L(level, syslog, mask) { L_ ## level, #level, (syslog), (mask) }
+  L(CRIT, LOG_CRIT, SNO_OLDSNO),
+  L(ERROR, LOG_ERR, 0),
+  L(WARNING, LOG_WARNING, 0),
+  L(NOTICE, LOG_NOTICE, 0),
+  L(TRACE, LOG_INFO, 0),
+  L(INFO, LOG_INFO, 0),
+  L(DEBUG, LOG_INFO, SNO_DEBUG),
+#undef L
+  { L_LAST_LEVEL, 0, 0, 0 }
+};
+
+/* Just in case some implementation of syslog has them... */
+#undef LOG_NONE
+#undef LOG_DEFAULT
+#undef LOG_NOTFOUND
+
+#define LOG_NONE     -1 /**< don't syslog */
+#define LOG_DEFAULT   0 /**< syslog to logInfo.facility */
+#define LOG_NOTFOUND -2 /**< didn't find a facility corresponding to name */
+
+/** Map names to syslog facilities. */
+static struct {
+  char *name;   /**< Textual name of facility. */
+  int facility; /**< Facility value for syslog(). */
+} facilities[] = {
+#define F(fac) { #fac, LOG_ ## fac }
+  F(NONE),    F(DEFAULT), F(AUTH),
+#ifdef LOG_AUTHPRIV
+  F(AUTHPRIV),
+#endif
+  F(CRON),    F(DAEMON),  F(LOCAL0),  F(LOCAL1),  F(LOCAL2),  F(LOCAL3),
+  F(LOCAL4),  F(LOCAL5),  F(LOCAL6),  F(LOCAL7),  F(LPR),     F(MAIL),
+  F(NEWS),    F(USER),    F(UUCP),
+#undef F
+  { 0, 0 }
+};
+
+#define SNO_NONE     0x00000000 /**< don't send server notices */
+#define SNO_NOTFOUND 0xffffffff /**< didn't find a SNO_MASK value for name */
+
+/** Map names to snomask values. */
+static struct {
+  char *name;           /**< Name of server notice bit. */
+  unsigned int snomask; /**< Bitmask corresponding to name. */
+} masks[] = {
+#define M(mask) { #mask, SNO_ ## mask }
+  M(NONE),       M(OLDSNO),     M(SERVKILL),   M(OPERKILL),   M(HACK2),
+  M(HACK3),      M(UNAUTH),     M(TCPCOMMON),  M(TOOMANY),    M(HACK4),
+  M(GLINE),      M(NETWORK),    M(IPMISMATCH), M(THROTTLE),   M(OLDREALOP),
+  M(CONNEXIT),   M(DEBUG),      M(AUTH),
+#undef M
+  { 0, 0 }
+};
+
+#define LOG_MARK_FILE          0x0001  /**< file has been changed */
+#define LOG_MARK_FACILITY      0x0002  /**< facility has been changed */
+#define LOG_MARK_SNOMASK       0x0004  /**< snomask has been changed */
+#define LOG_MARK_LEVEL         0x0008  /**< level has been changed */
+
+/** Descriptions of all logging subsystems. */
+static struct LogDesc {
+  enum LogSys    subsys;   /**< number for subsystem */
+  char          *name;     /**< subsystem name */
+  struct LogFile *file;            /**< file descriptor for subsystem */
+  unsigned int   mark;     /**< subsystem has been changed */
+  int            def_fac;  /**< default facility */
+  unsigned int   def_sno;  /**< default snomask */
+  int            facility; /**< -1 means don't use syslog */
+  unsigned int   snomask;  /**< 0 means no server message */
+  enum LogLevel          level;    /**< logging level */
+} logDesc[] = {
+#define S(sys, p, sn) { LS_##sys, #sys, 0, 0, (p), (sn), (p), (sn), L_DEFAULT }
+  S(SYSTEM, -1, 0),
+  S(CONFIG, 0, SNO_OLDSNO),
+  S(OPERMODE, -1, SNO_HACK4),
+  S(GLINE, -1, SNO_GLINE),
+  S(JUPE, -1, SNO_NETWORK),
+  S(WHO, -1, 0),
+  S(NETWORK, -1, SNO_NETWORK),
+  S(OPERKILL, -1, 0),
+  S(SERVKILL, -1, 0),
+  S(USER, -1, 0),
+  S(OPER, -1, SNO_OLDREALOP),
+  S(RESOLVER, -1, 0),
+  S(SOCKET, -1, 0),
+  S(IAUTH, -1, SNO_NETWORK),
+  S(DEBUG, -1, SNO_DEBUG),
+#undef S
+  { LS_LAST_SYSTEM, 0, 0, -1, 0, -1, 0 }
+};
+
+/** Describes a log file. */
+struct LogFile {
+  struct LogFile  *next;   /**< next log file descriptor */
+  struct LogFile **prev_p; /**< what points to us */
+  int             fd;     /**< file's descriptor-- -1 if not open */
+  int             ref;    /**< how many things refer to us? */
+  char           *file;   /**< file name */
+};
+
+/** Modifiable static information. */
+static struct {
+  struct LogFile *filelist; /**< list of log files */
+  struct LogFile *freelist; /**< list of free'd log files */
+  int            facility; /**< default facility */
+  const char    *procname; /**< process's name */
+  struct LogFile *dbfile;   /**< debug file */
+} logInfo = { 0, 0, LOG_USER, "ircd", 0 };
+
+/** Helper routine to open a log file if needed.
+ * If the log file is already open, do nothing.
+ * @param[in,out] lf Log file to open.
+ */
+static void
+log_open(struct LogFile *lf)
+{
+  /* only open the file if we haven't already */
+  if (lf && lf->fd < 0) {
+    lf->fd = open(lf->file, O_WRONLY | O_CREAT | O_APPEND,
+                 S_IRUSR | S_IWUSR);
+  }
+}
+
+#ifdef DEBUGMODE
+
+/** Reopen debug log file. */
+static void
+log_debug_reopen(void)
+{
+  if (!logInfo.dbfile) /* no open debugging file */
+    return;
+
+  if (!logInfo.dbfile->file) { /* using terminal output */
+    logInfo.dbfile->fd = 2;
+    return;
+  }
+
+  /* Ok, it's a real file; close it if necessary and use log_open to open it */
+  if (logInfo.dbfile->fd >= 0) {
+    close(logInfo.dbfile->fd);
+    logInfo.dbfile->fd = -1; /* mark that it's closed for log_open */
+  }
+
+  log_open(logInfo.dbfile);
+
+  if (logInfo.dbfile->fd < 0) { /* try again with /dev/null */
+    if ((logInfo.dbfile->fd = open("/dev/null", O_WRONLY)) < 0)
+      exit(-1);
+  }
+
+  /* massage the file descriptor to be stderr */
+  if (logInfo.dbfile->fd != 2) {
+    int fd;
+    fd = dup2(logInfo.dbfile->fd, 2);
+    close(logInfo.dbfile->fd);
+    logInfo.dbfile->fd = fd;
+  }
+}
+
+/** initialize debugging log file.
+ * @param[in] usetty If non-zero, log to terminal instead of file.
+ */
+void
+log_debug_init(int usetty)
+{
+  logInfo.dbfile = (struct LogFile*) MyMalloc(sizeof(struct LogFile));
+
+  logInfo.dbfile->next = 0; /* initialize debugging filename */
+  logInfo.dbfile->prev_p = 0;
+  logInfo.dbfile->fd = -1;
+  logInfo.dbfile->ref = 1;
+
+  if (usetty) /* store pathname to use */
+    logInfo.dbfile->file = 0;
+  else
+    DupString(logInfo.dbfile->file, LOGFILE);
+
+  log_debug_reopen(); /* open the debug log */
+
+  logDesc[LS_DEBUG].file = logInfo.dbfile; /* remember where it went */
+}
+
+#endif /* DEBUGMODE */
+
+/** Set the debug log file name.
+ * @param[in] file File name, or NULL to select the default.
+ * @return Zero if the file was reopened; non-zero if not debugging to file.
+ */
+static int
+log_debug_file(const char *file)
+{
+#ifdef DEBUGMODE
+  if (!file)
+    file = LOGFILE;
+
+  /* If we weren't started with debugging enabled, or if we're using
+   * the terminal, don't do anything at all.
+   */
+  if (!logInfo.dbfile || !logInfo.dbfile->file)
+    return 1;
+
+  MyFree(logInfo.dbfile->file); /* free old pathname */
+  DupString(logInfo.dbfile->file, file); /* store new pathname */
+
+  log_debug_reopen(); /* reopen the debug log */
+#endif /* DEBUGMODE */
+  return 0;
+}
+
+/** Initialize logging subsystem.
+ * @param[in] process_name Process name to interactions with syslog.
+ */
+void
+log_init(const char *process_name)
+{
+  /* store the process name; probably belongs in ircd.c, but oh well... */
+  if (!EmptyString(process_name))
+    logInfo.procname = process_name;
+
+  /* ok, open syslog; default facility: LOG_USER */
+  openlog(logInfo.procname, LOG_PID | LOG_NDELAY, logInfo.facility);
+}
+
+/** Reopen log files (so admins can do things like rotate log files). */
+void
+log_reopen(void)
+{
+  log_close(); /* close everything...we reopen on demand */
+
+#ifdef DEBUGMODE
+  log_debug_reopen(); /* reopen debugging log if necessary */
+#endif /* DEBUGMODE */
+
+  /* reopen syslog, if needed; default facility: LOG_USER */
+  openlog(logInfo.procname, LOG_PID | LOG_NDELAY, logInfo.facility);
+}
+
+/** Close all log files. */
+void
+log_close(void)
+{
+  struct LogFile *ptr;
+
+  closelog(); /* close syslog */
+
+  for (ptr = logInfo.filelist; ptr; ptr = ptr->next) {
+    if (ptr->fd >= 0)
+      close(ptr->fd); /* close all the files... */
+
+    ptr->fd = -1;
+  }
+
+  if (logInfo.dbfile && logInfo.dbfile->file) {
+    if (logInfo.dbfile->fd >= 0)
+      close(logInfo.dbfile->fd); /* close the debug log file */
+
+    logInfo.dbfile->fd = -1;
+  }
+}
+
+/** Write a logging entry.
+ * @param[in] subsys Target subsystem.
+ * @param[in] severity Severity of message.
+ * @param[in] flags Combination of zero or more of LOG_NOSYSLOG, LOG_NOFILELOG, LOG_NOSNOTICE to suppress certain output.
+ * @param[in] fmt Format string for message.
+ */
+void
+log_write(enum LogSys subsys, enum LogLevel severity, unsigned int flags,
+         const char *fmt, ...)
+{
+  va_list vl;
+
+  va_start(vl, fmt);
+  log_vwrite(subsys, severity, flags, fmt, vl);
+  va_end(vl);
+}
+
+/** Write a logging entry using a va_list.
+ * @param[in] subsys Target subsystem.
+ * @param[in] severity Severity of message.
+ * @param[in] flags Combination of zero or more of LOG_NOSYSLOG, LOG_NOFILELOG, LOG_NOSNOTICE to suppress certain output.
+ * @param[in] fmt Format string for message.
+ * @param[in] vl Variable-length argument list for message.
+ */
+void
+log_vwrite(enum LogSys subsys, enum LogLevel severity, unsigned int flags,
+          const char *fmt, va_list vl)
+{
+  struct VarData vd;
+  struct LogDesc *desc;
+  struct LevelData *ldata;
+  struct tm *tstamp;
+  struct iovec vector[3];
+  time_t curtime;
+  char buf[LOG_BUFSIZE];
+  /* 1234567890123456789012 3 */
+  /* [2000-11-28 16:11:20] \0 */
+  char timebuf[23];
+
+  /* check basic assumptions */
+  assert(-1 < (int)subsys);
+  assert((int)subsys < LS_LAST_SYSTEM);
+  assert(-1 < (int)severity);
+  assert((int)severity < L_LAST_LEVEL);
+  assert(0 == (flags & ~LOG_NOMASK));
+  assert(0 != fmt);
+
+  /* find the log data and the severity data */
+  desc = &logDesc[subsys];
+  ldata = &levelData[severity];
+
+  /* check the set of ordering assumptions */
+  assert(desc->subsys == subsys);
+  assert(ldata->level == severity);
+
+  /* check severity... */
+  if (severity > desc->level)
+    return;
+
+  /* figure out where all we need to log */
+  if (!(flags & LOG_NOFILELOG) && desc->file) {
+    log_open(desc->file);
+    if (desc->file->fd >= 0) /* don't log to file if we can't open the file */
+      flags |= LOG_DOFILELOG;
+  }
+
+  if (!(flags & LOG_NOSYSLOG) && desc->facility >= 0)
+    flags |= LOG_DOSYSLOG; /* will syslog */
+
+  if (!(flags & LOG_NOSNOTICE) && (desc->snomask != 0 || ldata->snomask != 0))
+    flags |= LOG_DOSNOTICE; /* will send a server notice */
+
+  /* short-circuit if there's nothing to do... */
+  if (!(flags & LOG_DOMASK))
+    return;
+
+  /* Build the basic log string */
+  vd.vd_format = fmt;
+  va_copy(vd.vd_args, vl);
+
+  /* save the length for writev */
+  /* Log format: "SYSTEM [SEVERITY]: log message" */
+  vector[1].iov_len =
+    ircd_snprintf(0, buf, sizeof(buf), "%s [%s]: %v", desc->name,
+                 ldata->string, &vd);
+
+  /* if we have something to write to... */
+  if (flags & LOG_DOFILELOG) {
+    curtime = TStime();
+    tstamp = localtime(&curtime); /* build the timestamp */
+
+    vector[0].iov_len =
+      ircd_snprintf(0, timebuf, sizeof(timebuf), "[%d-%d-%d %d:%02d:%02d] ",
+                   tstamp->tm_year + 1900, tstamp->tm_mon + 1,
+                   tstamp->tm_mday, tstamp->tm_hour, tstamp->tm_min,
+                   tstamp->tm_sec);
+
+    /* set up the remaining parts of the writev vector... */
+    vector[0].iov_base = timebuf;
+    vector[1].iov_base = buf;
+
+    vector[2].iov_base = (void*) "\n"; /* terminate lines with a \n */
+    vector[2].iov_len = 1;
+
+    /* write it out to the log file */
+    writev(desc->file->fd, vector, 3);
+  }
+
+  /* oh yeah, syslog it too... */
+  if (flags & LOG_DOSYSLOG)
+    syslog(ldata->syslog | desc->facility, "%s", buf);
+
+  /* can't forget server notices... */
+  if (flags & LOG_DOSNOTICE)
+    sendto_opmask_butone(0, ldata->snomask ? ldata->snomask : desc->snomask,
+                        "%s", buf);
+}
+
+/** Log an appropriate message for kills.
+ * @param[in] victim %Client being killed.
+ * @param[in] killer %User or server doing the killing.
+ * @param[in] inpath Peer that sent us the KILL message.
+ * @param[in] path Kill path that sent to us by \a inpath.
+ * @param[in] msg Kill reason.
+ */
+void
+log_write_kill(const struct Client *victim, const struct Client *killer,
+              const char *inpath, const char *path, const char *msg)
+{
+  if (MyUser(victim))
+    log_write(IsServer(killer) ? LS_SERVKILL : LS_OPERKILL, L_TRACE, 0,
+             "A local client %#C KILLED by %#C Path: %s!%s %s",
+             victim, killer, inpath, path, msg);
+  else
+    log_write(IsServer(killer) ? LS_SERVKILL : LS_OPERKILL, L_TRACE, 0,
+             "KILL from %C For %C Path: %s!%s %s", killer, victim, inpath,
+             path, msg);
+}
+
+/** Find a reference-counted LogFile by file name.
+ * @param[in] file Name of file.
+ * @return A log file descriptor with LogFile::ref at least 1.
+ */
+static struct LogFile *
+log_file_create(const char *file)
+{
+  struct LogFile *tmp;
+
+  assert(0 != file);
+
+  /* if one already exists for that file, return it */
+  for (tmp = logInfo.filelist; tmp; tmp = tmp->next)
+    if (!strcmp(tmp->file, file)) {
+      tmp->ref++;
+      return tmp;
+    }
+
+  if (logInfo.freelist) { /* pop one off the free list */
+    tmp = logInfo.freelist;
+    logInfo.freelist = tmp->next;
+  } else /* allocate a new one */
+    tmp = (struct LogFile*) MyMalloc(sizeof(struct LogFile));
+
+  tmp->fd = -1; /* initialize the structure */
+  tmp->ref = 1;
+  DupString(tmp->file, file);
+
+  tmp->next = logInfo.filelist; /* link it into the list... */
+  tmp->prev_p = &logInfo.filelist;
+  if (logInfo.filelist)
+    logInfo.filelist->prev_p = &tmp->next;
+  logInfo.filelist = tmp;
+
+  return tmp;
+}
+
+/** Dereference a log file.
+ * If the reference count is exactly one on entry to this function,
+ * the file is closed and its structure is freed.
+ * @param[in] lf Log file to dereference.
+ */
+static void
+log_file_destroy(struct LogFile *lf)
+{
+  assert(0 != lf);
+
+  if (--lf->ref == 0) {
+    if (lf->next) /* clip it out of the list */
+      lf->next->prev_p = lf->prev_p;
+    *lf->prev_p = lf->next;
+
+    lf->prev_p = 0; /* we won't use it for the free list */
+    if (lf->fd >= 0)
+      close(lf->fd);
+    lf->fd = -1;
+    MyFree(lf->file); /* free the file name */
+
+    lf->next = logInfo.freelist; /* stack it onto the free list */
+    logInfo.freelist = lf;
+  }
+}
+
+/** Look up a log subsystem by name.
+ * @param[in] subsys Subsystem name.
+ * @return Pointer to the subsystem's LogDesc, or NULL if none exists.
+ */
+static struct LogDesc *
+log_find(const char *subsys)
+{
+  int i;
+
+  assert(0 != subsys);
+
+  /* find the named subsystem */
+  for (i = 0; i < LS_LAST_SYSTEM; i++)
+    if (!ircd_strcmp(subsys, logDesc[i].name))
+      return &logDesc[i];
+
+  return 0; /* not found */
+}
+
+/** Return canonical version of log subsystem name.
+ * @param[in] subsys Subsystem name.
+ * @return A constant string containing the canonical name.
+ */
+char *
+log_canon(const char *subsys)
+{
+  struct LogDesc *desc;
+
+  if (!(desc = log_find(subsys)))
+    return 0;
+
+  return desc->name;
+}
+
+/** Look up a log level by name.
+ * @param[in] level Log level name.
+ * @return LogLevel enumeration, or L_LAST_LEVEL if none exists.
+ */
+static enum LogLevel
+log_lev_find(const char *level)
+{
+  int i;
+
+  assert(0 != level);
+
+  /* find the named level */
+  for (i = 0; levelData[i].string; i++)
+    if (!ircd_strcmp(level, levelData[i].string))
+      return levelData[i].level;
+
+  return L_LAST_LEVEL; /* not found */
+}
+
+/** Look up the canonical name for a log level.
+ * @param[in] lev
+ * @return A constant string containing the level's canonical name.
+ */
+static char *
+log_lev_name(enum LogLevel lev)
+{
+  assert(-1 < (int)lev);
+  assert((int)lev < L_LAST_LEVEL);
+  assert(lev == levelData[lev].level);
+
+  return levelData[lev].string;
+}
+
+/** Look up a syslog facility by name.
+ * @param[in] facility Facility name.
+ * @return Syslog facility value, or LOG_NOTFOUND if none exists.
+ */
+static int
+log_fac_find(const char *facility)
+{
+  int i;
+
+  assert(0 != facility);
+
+  /* find the named facility */
+  for (i = 0; facilities[i].name; i++)
+    if (!ircd_strcmp(facility, facilities[i].name))
+      return facilities[i].facility;
+
+  return LOG_NOTFOUND; /* not found */
+}
+
+/** Look up the name for a syslog facility.
+ * @param[in] fac Facility value.
+ * @return Canonical name for facility, or NULL if none exists.
+ */
+static char *
+log_fac_name(int fac)
+{
+  int i;
+
+  /* find the facility */
+  for (i = 0; facilities[i].name; i++)
+    if (facilities[i].facility == fac)
+      return facilities[i].name;
+
+  return 0; /* not found; should never happen */
+}
+
+/** Look up a server notice mask by name.
+ * @param[in] maskname Name of server notice mask.
+ * @return Bitmask for server notices, or 0 if none exists.
+ */
+static unsigned int
+log_sno_find(const char *maskname)
+{
+  int i;
+
+  assert(0 != maskname);
+
+  /* find the named snomask */
+  for (i = 0; masks[i].name; i++)
+    if (!ircd_strcmp(maskname, masks[i].name))
+      return masks[i].snomask;
+
+  return SNO_NOTFOUND; /* not found */
+}
+
+/** Look up the canonical name for a server notice mask.
+ * @param[in] sno Server notice mask.
+ * @return Canonical name for the mask, or NULL if none exists.
+ */
+static char *
+log_sno_name(unsigned int sno)
+{
+  int i;
+
+  /* find the snomask */
+  for (i = 0; masks[i].name; i++)
+    if (masks[i].snomask == sno)
+      return masks[i].name;
+
+  return 0; /* not found; should never happen */
+}
+
+/** Set a log file for a particular subsystem.
+ * @param[in] subsys Subsystem name.
+ * @param[in] filename Log file to write to.
+ * @return Zero on success; non-zero on error.
+ */
+int
+log_set_file(const char *subsys, const char *filename)
+{
+  struct LogDesc *desc;
+
+  /* find subsystem */
+  if (!(desc = log_find(subsys)))
+    return 2;
+
+  if (filename)
+    desc->mark |= LOG_MARK_FILE; /* mark that file has been changed */
+  else
+    desc->mark &= ~LOG_MARK_FILE; /* file has been reset to defaults */
+
+  /* no change, don't go to the trouble of destroying and recreating */
+  if (desc->file && desc->file->file && filename &&
+      !strcmp(desc->file->file, filename))
+    return 0;
+
+  /* debug log is special, since it has to be opened on fd 2 */
+  if (desc->subsys == LS_DEBUG)
+    return log_debug_file(filename);
+
+  if (desc->file) /* destroy previous entry... */
+    log_file_destroy(desc->file);
+
+  /* set the file to use */
+  desc->file = filename ? log_file_create(filename) : 0;
+
+  return 0;
+}
+
+/** Find the log file name for a subsystem.
+ * @param[in] subsys Subsystem name.
+ * @return Log file for the subsystem, or NULL if not being logged to a file.
+ */
+char *
+log_get_file(const char *subsys)
+{
+  struct LogDesc *desc;
+
+  /* find subsystem */
+  if (!(desc = log_find(subsys)))
+    return 0;
+
+  return desc->file ? desc->file->file : 0;
+}
+
+/** Set the syslog facility for a particular subsystem.
+ * @param[in] subsys Subsystem name.
+ * @param[in] facility Facility name to log to.
+ * @return Zero on success; non-zero on error.
+ */
+int
+log_set_facility(const char *subsys, const char *facility)
+{
+  struct LogDesc *desc;
+  int fac;
+
+  /* find subsystem */
+  if (!(desc = log_find(subsys)))
+    return 2;
+
+  /* set syslog facility */
+  if (EmptyString(facility)) {
+    desc->facility = desc->def_fac;
+    desc->mark &= ~LOG_MARK_FACILITY;
+  } else if ((fac = log_fac_find(facility)) != LOG_NOTFOUND) {
+    desc->facility = fac;
+    if (fac == desc->def_fac)
+      desc->mark &= ~LOG_MARK_FACILITY;
+    else
+      desc->mark |= LOG_MARK_FACILITY;
+  } else
+    return 1;
+
+  return 0;
+}
+
+/** Find the facility name for a subsystem.
+ * @param[in] subsys Subsystem name.
+ * @return Facility name being used, or NULL if not being logged to syslog.
+ */
+char *
+log_get_facility(const char *subsys)
+{
+  struct LogDesc *desc;
+
+  /* find subsystem */
+  if (!(desc = log_find(subsys)))
+    return 0;
+
+  /* find the facility's name */
+  return log_fac_name(desc->facility);
+}
+
+/** Set the server notice mask for a subsystem.
+ * @param[in] subsys Subsystem name.
+ * @param[in] snomask Server notice mask name.
+ * @return Zero on success; non-zero on error.
+ */
+int
+log_set_snomask(const char *subsys, const char *snomask)
+{
+  struct LogDesc *desc;
+  unsigned int sno = SNO_DEFAULT;
+
+  /* find subsystem */
+  if (!(desc = log_find(subsys)))
+    return 2;
+
+  /* set snomask value */
+  if (EmptyString(snomask)) {
+    desc->snomask = desc->def_sno;
+    desc->mark &= ~LOG_MARK_SNOMASK;
+  } else if ((sno = log_sno_find(snomask)) != SNO_NOTFOUND) {
+    desc->snomask = sno;
+    if (sno == desc->def_sno)
+      desc->mark &= ~LOG_MARK_SNOMASK;
+    else
+      desc->mark |= LOG_MARK_SNOMASK;
+  } else
+    return 1;
+
+  return 0;
+}
+
+/** Find the server notice mask name for a subsystem.
+ * @param[in] subsys Subsystem name.
+ * @return Name of server notice mask being used, or NULL if none.
+ */
+char *
+log_get_snomask(const char *subsys)
+{
+  struct LogDesc *desc;
+
+  /* find subsystem */
+  if (!(desc = log_find(subsys)))
+    return 0;
+
+  /* find the snomask value's name */
+  return log_sno_name(desc->snomask);
+}
+
+/** Set the verbosity level for a subsystem.
+ * @param[in] subsys Subsystem name.
+ * @param[in] level Minimum log level.
+ * @return Zero on success; non-zero on error.
+ */
+int
+log_set_level(const char *subsys, const char *level)
+{
+  struct LogDesc *desc;
+  enum LogLevel lev;
+
+  /* find subsystem */
+  if (!(desc = log_find(subsys)))
+    return 2;
+
+  /* set logging level */
+  if (EmptyString(level)) {
+    desc->level = L_DEFAULT;
+    desc->mark &= ~LOG_MARK_LEVEL;
+  } else if ((lev = log_lev_find(level)) != L_LAST_LEVEL) {
+    desc->level = lev;
+    if (lev == L_DEFAULT)
+      desc->mark &= ~LOG_MARK_LEVEL;
+    else
+      desc->mark |= LOG_MARK_LEVEL;
+  } else
+    return 1;
+
+  return 0;
+}
+
+/** Find the verbosity level for a subsystem.
+ * @param[in] subsys Subsystem name.
+ * @return Minimum verbosity level being used, or NULL on error.
+ */
+char *
+log_get_level(const char *subsys)
+{
+  struct LogDesc *desc;
+
+  /* find subsystem */
+  if (!(desc = log_find(subsys)))
+    return 0;
+
+  /* find the level's name */
+  return log_lev_name(desc->level);
+}
+
+/** Set the default syslog facility.
+ * @param[in] facility Syslog facility name.
+ * @return Zero on success, non-zero on error.
+ */
+int
+log_set_default(const char *facility)
+{
+  int fac, oldfac;
+
+  oldfac = logInfo.facility;
+
+  if (EmptyString(facility))
+    logInfo.facility = LOG_USER;
+  else if ((fac = log_fac_find(facility)) != LOG_NOTFOUND &&
+          fac != LOG_NONE && fac != LOG_DEFAULT)
+    logInfo.facility = fac;
+  else
+    return 1;
+
+  if (logInfo.facility != oldfac) {
+    closelog(); /* reopen syslog with new facility setting */
+    openlog(logInfo.procname, LOG_PID | LOG_NDELAY, logInfo.facility);
+  }
+
+  return 0;
+}
+
+/** Find the default syslog facility name.
+ * @return Canonical name of default syslog facility, or NULL if none.
+ */
+char *
+log_get_default(void)
+{
+  /* find the facility's name */
+  return log_fac_name(logInfo.facility);
+}
+
+/** Clear all marks. */
+void
+log_feature_unmark(void)
+{
+  int i;
+
+  for (i = 0; i < LS_LAST_SYSTEM; i++)
+    logDesc[i].mark = 0;
+}
+
+/** Reset unmodified fields in all log subsystems to their defaults.
+ * @param[in] flag If non-zero, clear default syslog facility.
+ */
+int
+log_feature_mark(int flag)
+{
+  int i;
+
+  if (flag)
+    log_set_default(0);
+
+  for (i = 0; i < LS_LAST_SYSTEM; i++) {
+    if (!(logDesc[i].mark & LOG_MARK_FILE)) {
+      if (logDesc[i].subsys != LS_DEBUG) { /* debug is special */
+       if (logDesc[i].file) /* destroy previous entry... */
+         log_file_destroy(logDesc[i].file);
+       logDesc[i].file = 0;
+      }
+    }
+
+    if (!(logDesc[i].mark & LOG_MARK_FACILITY)) /* set default facility */
+      logDesc[i].facility = logDesc[i].def_fac;
+
+    if (!(logDesc[i].mark & LOG_MARK_SNOMASK)) /* set default snomask */
+      logDesc[i].snomask = logDesc[i].def_sno;
+
+    if (!(logDesc[i].mark & LOG_MARK_LEVEL)) /* set default level */
+      logDesc[i].level = L_DEFAULT;
+  }
+
+  return 0; /* we don't have a notify handler */
+}
+
+/** Feature list callback to report log settings.
+ * @param[in] to Client requesting list.
+ * @param[in] flag If non-zero, report default syslog facility.
+ */
+void
+log_feature_report(struct Client *to, int flag)
+{
+  int i;
+
+  for (i = 0; i < LS_LAST_SYSTEM; i++)
+  {
+    if (logDesc[i].mark & LOG_MARK_FILE) /* report file */
+      send_reply(to, SND_EXPLICIT | RPL_STATSFLINE, "F LOG %s FILE %s",
+                 logDesc[i].name, (logDesc[i].file && logDesc[i].file->file ?
+                                   logDesc[i].file->file : "(terminal)"));
+
+    if (logDesc[i].mark & LOG_MARK_FACILITY) /* report facility */
+      send_reply(to, SND_EXPLICIT | RPL_STATSFLINE, "F LOG %s FACILITY %s",
+                logDesc[i].name, log_fac_name(logDesc[i].facility));
+
+    if (logDesc[i].mark & LOG_MARK_SNOMASK) /* report snomask */
+      send_reply(to, SND_EXPLICIT | RPL_STATSFLINE, "F LOG %s SNOMASK %s",
+                logDesc[i].name, log_sno_name(logDesc[i].snomask));
+
+    if (logDesc[i].mark & LOG_MARK_LEVEL) /* report log level */
+      send_reply(to, SND_EXPLICIT | RPL_STATSFLINE, "F LOG %s LEVEL %s",
+                logDesc[i].name, log_lev_name(logDesc[i].level));
+  }
+
+  if (flag) /* report default facility */
+    send_reply(to, SND_EXPLICIT | RPL_STATSFLINE, "F LOG %s",
+              log_fac_name(logInfo.facility));
+}
diff --git a/ircd/ircd_md5.c b/ircd/ircd_md5.c
new file mode 100644 (file)
index 0000000..3d770ba
--- /dev/null
@@ -0,0 +1,266 @@
+/*
+ * IRC - Internet Relay Chat, ircd/ircd_md5.h
+ *
+ * This code implements the MD5 message-digest algorithm.
+ * The algorithm is due to Ron Rivest.  This code was
+ * written by Colin Plumb in 1993, no copyright is claimed.
+ * This code is in the public domain; do with it what you wish.
+ *
+ * Equivalent code is available from RSA Data Security, Inc.
+ * This code has been tested against that, and is equivalent,
+ * except that you don't need to include two pages of legalese
+ * with every copy.
+ *
+ * To compute the message digest of a chunk of bytes, declare an
+ * MD5Context structure, pass it to MD5Init, call MD5Update as
+ * needed on buffers full of bytes, and then call MD5Final, which
+ * will fill a supplied 16-byte array with the digest.
+ *
+ * ircuified 2002 by hikari
+ */
+/** @file
+ * @brief MD5 implementation for ircu.
+ * @version $Id: ircd_md5.c 1234 2004-10-05 22:51:47Z entrope $
+ */
+
+#include <string.h>
+#include "ircd_md5.h"
+
+#ifndef HIGHFIRST
+/** Bit-reverse bytes in a buffer. */
+#define byteReverse(buf, len)  /* Nothing */
+#else
+static void byteReverse(unsigned char *buf, unsigned longs);
+
+#ifndef ASM_MD5
+/*
+ * Note: this code is harmless on little-endian machines.
+ */
+static void byteReverse(unsigned char *buf, unsigned longs)
+{
+       uint32 t;
+       do {
+               t = (uint32) ((unsigned) buf[3] << 8 | buf[2]) << 16 |
+                   ((unsigned) buf[1] << 8 | buf[0]);
+               *(uint32 *) buf = t;
+               buf += 4;
+       } while (--longs);
+}
+#endif
+#endif
+
+/** Iniitalize MD5 context.
+ * @param[out] ctx MD5 context to initialize.
+ */
+void MD5Init(struct MD5Context *ctx)
+{
+       ctx->buf[0] = 0x67452301U;
+       ctx->buf[1] = 0xefcdab89U;
+       ctx->buf[2] = 0x98badcfeU;
+       ctx->buf[3] = 0x10325476U;
+
+       ctx->bits[0] = 0;
+       ctx->bits[1] = 0;
+}
+
+/** Update MD5 context with data from a buffer.
+ * @param[in,out] ctx MD5 context to operate on.
+ * @param[in] buf Input buffer.
+ * @param[in] len Number of bytes in input buffer.
+ */
+void MD5Update(struct MD5Context *ctx, unsigned const char *buf, unsigned len)
+{
+       uint32 t;
+
+       /* Update bitcount */
+
+       t = ctx->bits[0];
+       if ((ctx->bits[0] = t + ((uint32) len << 3)) < t)
+               ctx->bits[1]++; /* Carry from low to high */
+       ctx->bits[1] += len >> 29;
+
+       t = (t >> 3) & 0x3f;    /* Bytes already in shsInfo->data */
+
+       /* Handle any leading odd-sized chunks */
+
+       if (t) {
+               unsigned char *p = (unsigned char *) ctx->in + t;
+
+               t = 64 - t;
+               if (len < t) {
+                       memcpy(p, buf, len);
+                       return;
+               }
+               memcpy(p, buf, t);
+               byteReverse(ctx->in, 16);
+               MD5Transform(ctx->buf, (uint32 *) ctx->in);
+               buf += t;
+               len -= t;
+       }
+       /* Process data in 64-byte chunks */
+
+       while (len >= 64) {
+               memcpy(ctx->in, buf, 64);
+               byteReverse(ctx->in, 16);
+               MD5Transform(ctx->buf, (uint32 *) ctx->in);
+               buf += 64;
+               len -= 64;
+       }
+
+       /* Handle any remaining bytes of data. */
+
+       memcpy(ctx->in, buf, len);
+}
+
+/** Perform final steps of MD5 hash.
+ * @param[out] digest Receives output hash value.
+ * @param[in,out] ctx MD5 context to finalize.
+ */
+void MD5Final(unsigned char digest[16], struct MD5Context *ctx)
+{
+       unsigned count;
+       unsigned char *p;
+
+       /* Compute number of bytes mod 64 */
+       count = (ctx->bits[0] >> 3) & 0x3F;
+
+       /* Set the first char of padding to 0x80.  This is safe since there is
+          always at least one byte free */
+       p = ctx->in + count;
+       *p++ = 0x80;
+
+       /* Bytes of padding needed to make 64 bytes */
+       count = 64 - 1 - count;
+
+       /* Pad out to 56 mod 64 */
+       if (count < 8) {
+               /* Two lots of padding:  Pad the first block to 64 bytes */
+               memset(p, 0, count);
+               byteReverse(ctx->in, 16);
+               MD5Transform(ctx->buf, (uint32 *) ctx->in);
+
+               /* Now fill the next block with 56 bytes */
+               memset(ctx->in, 0, 56);
+       } else {
+               /* Pad block to 56 bytes */
+               memset(p, 0, count - 8);
+       }
+       byteReverse(ctx->in, 14);
+
+       /* Append length in bits and transform */
+       ((uint32 *) ctx->in)[14] = ctx->bits[0];
+       ((uint32 *) ctx->in)[15] = ctx->bits[1];
+
+       MD5Transform(ctx->buf, (uint32 *) ctx->in);
+       byteReverse((unsigned char *) ctx->buf, 4);
+       memcpy(digest, ctx->buf, 16);
+       memset(ctx, 0, sizeof(ctx));    /* In case it's sensitive */
+}
+
+#ifndef ASM_MD5
+
+/* The four core functions - F1 is optimized somewhat */
+
+/* #define F1(x, y, z) (x & y | ~x & z) */
+/** Helper function for first round of MD5. */
+#define F1(x, y, z) (z ^ (x & (y ^ z)))
+/** Helper function for second round of MD5. */
+#define F2(x, y, z) F1(z, x, y)
+/** Helper function for third round of MD5. */
+#define F3(x, y, z) (x ^ y ^ z)
+/** Helper function for fourth round of MD5. */
+#define F4(x, y, z) (y ^ (x | ~z))
+
+/** Step function for each round of MD5 */
+#define MD5STEP(f, w, x, y, z, data, s) \
+       ( w += f(x, y, z) + data,  w = w<<s | w>>(32-s),  w += x )
+
+/** Perform the core MD5 update steps to update a 128-bit hash value
+ * with 512 bits of input data.
+ * @param[in,out] buf Hash value.
+ * @param[in] in Input buffer.
+ */
+void MD5Transform(uint32 buf[4], uint32 const in[16])
+{
+       register uint32 a, b, c, d;
+
+       a = buf[0];
+       b = buf[1];
+       c = buf[2];
+       d = buf[3];
+
+       MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478U, 7);
+       MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756U, 12);
+       MD5STEP(F1, c, d, a, b, in[2] + 0x242070dbU, 17);
+       MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceeeU, 22);
+       MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0fafU, 7);
+       MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62aU, 12);
+       MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613U, 17);
+       MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501U, 22);
+       MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8U, 7);
+       MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7afU, 12);
+       MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1U, 17);
+       MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7beU, 22);
+       MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122U, 7);
+       MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193U, 12);
+       MD5STEP(F1, c, d, a, b, in[14] + 0xa679438eU, 17);
+       MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821U, 22);
+
+       MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562U, 5);
+       MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340U, 9);
+       MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51U, 14);
+       MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aaU, 20);
+       MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105dU, 5);
+       MD5STEP(F2, d, a, b, c, in[10] + 0x02441453U, 9);
+       MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681U, 14);
+       MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8U, 20);
+       MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6U, 5);
+       MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6U, 9);
+       MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87U, 14);
+       MD5STEP(F2, b, c, d, a, in[8] + 0x455a14edU, 20);
+       MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905U, 5);
+       MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8U, 9);
+       MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9U, 14);
+       MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8aU, 20);
+
+       MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942U, 4);
+       MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681U, 11);
+       MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122U, 16);
+       MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380cU, 23);
+       MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44U, 4);
+       MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9U, 11);
+       MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60U, 16);
+       MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70U, 23);
+       MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6U, 4);
+       MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127faU, 11);
+       MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085U, 16);
+       MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05U, 23);
+       MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039U, 4);
+       MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5U, 11);
+       MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8U, 16);
+       MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665U, 23);
+
+       MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244U, 6);
+       MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97U, 10);
+       MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7U, 15);
+       MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039U, 21);
+       MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3U, 6);
+       MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92U, 10);
+       MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47dU, 15);
+       MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1U, 21);
+       MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4fU, 6);
+       MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0U, 10);
+       MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314U, 15);
+       MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1U, 21);
+       MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82U, 6);
+       MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235U, 10);
+       MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bbU, 15);
+       MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391U, 21);
+
+       buf[0] += a;
+       buf[1] += b;
+       buf[2] += c;
+       buf[3] += d;
+}
+
+#endif
diff --git a/ircd/ircd_parser.y b/ircd/ircd_parser.y
new file mode 100644 (file)
index 0000000..eaf942b
--- /dev/null
@@ -0,0 +1,1303 @@
+/*
+ * ircd_parser.y: A yacc/bison parser for ircd config files.
+ * This is part of ircu, an Internet Relay Chat server.
+ * The contents of this file are Copyright 2001 Diane Bruce,
+ * Andrew Miller, the ircd-hybrid team and the ircu team.
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ *  USA.
+ * $Id: ircd_parser.y 1907 2009-02-09 04:11:04Z entrope $
+ */
+%{
+
+#include "config.h"
+#include "s_conf.h"
+#include "class.h"
+#include "client.h"
+#include "crule.h"
+#include "ircd_features.h"
+#include "fileio.h"
+#include "gline.h"
+#include "hash.h"
+#include "ircd.h"
+#include "ircd_alloc.h"
+#include "ircd_chattr.h"
+#include "ircd_log.h"
+#include "ircd_reply.h"
+#include "ircd_snprintf.h"
+#include "ircd_string.h"
+#include "list.h"
+#include "listener.h"
+#include "match.h"
+#include "motd.h"
+#include "numeric.h"
+#include "numnicks.h"
+#include "opercmds.h"
+#include "parse.h"
+#include "res.h"
+#include "s_auth.h"
+#include "s_bsd.h"
+#include "s_conf.h"
+#include "s_debug.h"
+#include "s_misc.h"
+#include "send.h"
+#include "struct.h"
+#include "sys.h"
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <arpa/inet.h>
+
+#define MAX_STRINGS 80 /* Maximum number of feature params. */
+#define USE_IPV4 (1 << 16)
+#define USE_IPV6 (1 << 17)
+
+  extern struct LocalConf   localConf;
+  extern struct DenyConf*   denyConfList;
+  extern struct CRuleConf*  cruleConfList;
+  extern struct ServerConf* serverConfList;
+  extern struct s_map*      GlobalServiceMapList;
+  extern struct qline*      GlobalQuarantineList;
+
+  int yylex(void);
+  /* Now all the globals we need :/... */
+  int tping, tconn, maxlinks, sendq, port, invert, stringno, flags, maxchans, iauth_required = 0;
+  char *name, *pass, *host, *ip, *username, *origin, *hub_limit;
+  struct SLink *hosts;
+  char *stringlist[MAX_STRINGS];
+  struct ListenerFlags listen_flags;
+  struct ConnectionClass *c_class;
+  struct DenyConf *dconf;
+  struct ServerConf *sconf;
+  struct s_map *smap;
+  struct Privs privs;
+  struct Privs privs_dirty;
+  struct webirc_block *webirc;
+
+static void parse_error(char *pattern,...) {
+  static char error_buffer[1024];
+  va_list vl;
+  va_start(vl,pattern);
+  ircd_vsnprintf(NULL, error_buffer, sizeof(error_buffer), pattern, vl);
+  va_end(vl);
+  yyerror(error_buffer);
+}
+
+static void free_slist(struct SLink **link) {
+  struct SLink *next;
+  while (*link != NULL) {
+    next = (*link)->next;
+    MyFree((*link)->value.cp);
+    free_link(*link);
+    *link = next;
+  }
+}
+
+%}
+
+%token <text> QSTRING
+%token <num> NUMBER
+
+%token GENERAL
+%token ADMIN
+%token LOCATION
+%token CONTACT
+%token CONNECT
+%token CLASS
+%token CHANNEL
+%token PINGFREQ
+%token CONNECTFREQ
+%token MAXLINKS
+%token MAXHOPS
+%token SENDQ
+%token NAME
+%token HOST
+%token IP
+%token USERNAME
+%token PASS
+%token LOCAL
+%token SECONDS
+%token MINUTES
+%token HOURS
+%token DAYS
+%token WEEKS
+%token MONTHS
+%token YEARS
+%token DECADES
+%token BYTES
+%token KBYTES
+%token MBYTES
+%token GBYTES
+%token TBYTES
+%token SERVER
+%token PORT
+%token MASK
+%token HUB
+%token LEAF
+%token UWORLD
+%token YES
+%token NO
+%token OPER
+%token VHOST
+%token HIDDEN
+%token MOTD
+%token JUPE
+%token NICK
+%token NUMERIC
+%token DESCRIPTION
+%token CLIENT
+%token KILL
+%token CRULE
+%token REAL
+%token REASON
+%token TFILE
+%token RULE
+%token ALL
+%token FEATURES
+%token QUARANTINE
+%token PSEUDO
+%token PREPEND
+%token USERMODE
+%token IAUTH
+%token TIMEOUT
+%token FAST
+%token AUTOCONNECT
+%token PROGRAM
+%token TOK_IPV4 TOK_IPV6
+%token DNS
+%token FORWARDS
+%token SECURE
+%token WEBIRC
+%token SPOOF
+%token MAXCHANS
+%token REQUIRED
+%token SSL
+%token CERT
+%token CACERT
+/* and now a lot of privileges... */
+%token TPRIV_CHAN_LIMIT TPRIV_MODE_LCHAN TPRIV_DEOP_LCHAN TPRIV_WALK_LCHAN
+%token TPRIV_LOCAL_KILL TPRIV_REHASH TPRIV_RESTART TPRIV_DIE
+%token TPRIV_GLINE TPRIV_LOCAL_GLINE TPRIV_LOCAL_JUPE TPRIV_LOCAL_BADCHAN
+%token TPRIV_LOCAL_OPMODE TPRIV_OPMODE TPRIV_SET TPRIV_WHOX TPRIV_BADCHAN
+%token TPRIV_SEE_CHAN TPRIV_SHOW_INVIS TPRIV_SHOW_ALL_INVIS TPRIV_PROPAGATE
+%token TPRIV_UNLIMIT_QUERY TPRIV_DISPLAY TPRIV_SEE_OPERS TPRIV_WIDE_GLINE
+%token TPRIV_FORCE_OPMODE TPRIV_FORCE_LOCAL_OPMODE TPRIV_APASS_OPMODE
+%token TPRIV_LIST_CHAN TPRIV_SEE_IDLETIME TPRIV_UMODE_NETSERV
+%token TPRIV_UMODE_NOCHAN TPRIV_UMODE_NOIDLE TPRIV_UMODE_CHSERV TPRIV_UMODE_XTRAOP
+%token TPRIV_FLOOD TPRIV_HALFFLOOD TPRIV_UNLIMITED_TARGET TPRIV_UMODE_OVERRIDECC
+%token TPRIV_HIDE_IDLETIME TPRIV_NOAMSG_OVERRIDE
+/* and some types... */
+%type <num> sizespec
+%type <num> timespec timefactor factoredtimes factoredtime
+%type <num> expr yesorno privtype address_family
+%left '+' '-'
+%left '*' '/'
+
+%union{
+ char *text;
+ int num;
+}
+
+%%
+/* Blocks in the config file... */
+blocks: blocks block | block;
+block: adminblock | generalblock | classblock | connectblock |
+       uworldblock | operblock | portblock | jupeblock | clientblock |
+       killblock | cruleblock | motdblock | featuresblock | quarantineblock |
+       pseudoblock | iauthblock | forwardsblock | webircblock | sslblock | error ';';
+
+/* The timespec, sizespec and expr was ripped straight from
+ * ircd-hybrid-7. */
+timespec: expr | factoredtimes;
+
+factoredtimes: factoredtimes factoredtime
+{
+  $$ = $1 + $2;
+} | factoredtime;
+
+factoredtime: expr timefactor
+{
+  $$ = $1 * $2;
+};
+
+timefactor: SECONDS { $$ = 1; }
+| MINUTES { $$ = 60; }
+| HOURS { $$ = 60 * 60; }
+| DAYS { $$ = 60 * 60 * 24; }
+| WEEKS { $$ = 60 * 60 * 24 * 7; }
+| MONTHS { $$ = 60 * 60 * 24 * 7 * 4; }
+| YEARS { $$ = 60 * 60 * 24 * 365; }
+| DECADES { $$ = 60 * 60 * 24 * 365 * 10; };
+
+
+sizespec:      expr    {
+                       $$ = $1;
+               }
+               | expr BYTES  { 
+                       $$ = $1;
+               }
+               | expr KBYTES {
+                       $$ = $1 * 1024;
+               }
+               | expr MBYTES {
+                       $$ = $1 * 1024 * 1024;
+               }
+               | expr GBYTES {
+                       $$ = $1 * 1024 * 1024 * 1024;
+               }
+               | expr TBYTES {
+                       $$ = $1 * 1024 * 1024 * 1024;
+               }
+               ;
+
+/* this is an arithmetic expression */
+expr: NUMBER
+               { 
+                       $$ = $1;
+               }
+               | expr '+' expr { 
+                       $$ = $1 + $3;
+               }
+               | expr '-' expr { 
+                       $$ = $1 - $3;
+               }
+               | expr '*' expr { 
+                       $$ = $1 * $3;
+               }
+               | expr '/' expr { 
+                       $$ = $1 / $3;
+               }
+/* leave this out until we find why it makes BSD yacc dump core -larne
+               | '-' expr  %prec NEG {
+                       $$ = -$2;
+               } */
+               | '(' expr ')' {
+                       $$ = $2;
+               }
+               ;
+
+jupeblock: JUPE '{' jupeitems '}' ';' ;
+jupeitems: jupeitem jupeitems | jupeitem;
+jupeitem: jupenick;
+jupenick: NICK '=' QSTRING ';'
+{
+  addNickJupes($3);
+  MyFree($3);
+};
+
+generalblock: GENERAL
+{
+    /* Zero out the vhost addresses, in case they were removed. */
+    memset(&VirtualHost_v4.addr, 0, sizeof(VirtualHost_v4.addr));
+    memset(&VirtualHost_v6.addr, 0, sizeof(VirtualHost_v6.addr));
+} '{' generalitems '}' ';' {
+  if (localConf.name == NULL)
+    parse_error("Your General block must contain a name.");
+  if (localConf.numeric == 0)
+    parse_error("Your General block must contain a numeric (between 1 and 4095).");
+};
+generalitems: generalitem generalitems | generalitem;
+generalitem: generalnumeric | generalname | generalvhost | generaldesc
+  | generaldnsvhost | generaldnsserver;
+
+generalnumeric: NUMERIC '=' NUMBER ';'
+{
+  if (localConf.numeric == 0)
+    localConf.numeric = $3;
+  else if (localConf.numeric != $3)
+    parse_error("Redefinition of server numeric %i (%i)", $3,
+               localConf.numeric);
+};
+
+generalname: NAME '=' QSTRING ';'
+{
+  if (localConf.name == NULL)
+    localConf.name = $3;
+  else {
+    if (strcmp(localConf.name, $3))
+      parse_error("Redefinition of server name %s (%s)", $3,
+                  localConf.name);
+    MyFree($3);
+  }
+};
+
+generaldesc: DESCRIPTION '=' QSTRING ';'
+{
+  MyFree(localConf.description);
+  localConf.description = $3;
+  ircd_strncpy(cli_info(&me), $3, REALLEN);
+};
+
+generalvhost: VHOST '=' QSTRING ';'
+{
+  struct irc_in_addr addr;
+  char *vhost = $3;
+
+  if (!strcmp(vhost, "*")) {
+    /* This traditionally meant bind to all interfaces and connect
+     * from the default. */
+  } else if (!ircd_aton(&addr, vhost))
+    parse_error("Invalid virtual host '%s'.", vhost);
+  else if (irc_in_addr_is_ipv4(&addr))
+    memcpy(&VirtualHost_v4.addr, &addr, sizeof(addr));
+  else
+    memcpy(&VirtualHost_v6.addr, &addr, sizeof(addr));
+  MyFree(vhost);
+};
+
+generaldnsvhost: DNS VHOST '=' address_family QSTRING ';'
+{
+  struct irc_in_addr addr;
+  int families = $4;
+  char *vhost = $5;
+
+  if (!strcmp(vhost, "*")) {
+    /* Let the operating system assign the default. */
+  } else if (!ircd_aton(&addr, vhost))
+    parse_error("Invalid DNS virtual host '%s'.", vhost);
+  else
+  {
+    if ((families & USE_IPV4)
+        || (!families && irc_in_addr_is_ipv4(&addr)))
+      memcpy(&VirtualHost_dns_v4.addr, &addr, sizeof(addr));
+    if ((families & USE_IPV6)
+        || (!families && !irc_in_addr_is_ipv4(&addr)))
+      memcpy(&VirtualHost_dns_v6.addr, &addr, sizeof(addr));
+  }
+  MyFree(vhost);
+};
+
+generaldnsserver: DNS SERVER '=' QSTRING ';'
+{
+  char *server = $4;
+
+  add_nameserver(server);
+  MyFree(server);
+};
+
+adminblock: ADMIN
+{
+  MyFree(localConf.location1);
+  MyFree(localConf.location2);
+  MyFree(localConf.contact);
+  localConf.location1 = localConf.location2 = localConf.contact = NULL;
+}
+'{' adminitems '}' ';'
+{
+  if (localConf.location1 == NULL)
+    DupString(localConf.location1, "");
+  if (localConf.location2 == NULL)
+    DupString(localConf.location2, "");
+  if (localConf.contact == NULL)
+    DupString(localConf.contact, "");
+};
+adminitems: adminitems adminitem | adminitem;
+adminitem: adminlocation | admincontact;
+adminlocation: LOCATION '=' QSTRING ';'
+{
+  if (localConf.location1 == NULL)
+    localConf.location1 = $3;
+  else if (localConf.location2 == NULL)
+    localConf.location2 = $3;
+  else /* Otherwise just drop it. -A1kmm */
+    MyFree($3);
+};
+admincontact: CONTACT '=' QSTRING ';'
+{
+ MyFree(localConf.contact);
+ localConf.contact = $3;
+};
+
+classblock: CLASS {
+  tping = 90;
+  maxchans = 0;
+} '{' classitems '}' ';'
+{
+  if (name != NULL)
+  {
+    struct ConnectionClass *c_class;
+    add_class(name, tping, tconn, maxlinks, sendq, maxchans);
+    c_class = find_class(name);
+    MyFree(c_class->default_umode);
+    c_class->default_umode = pass;
+    memcpy(&c_class->privs, &privs, sizeof(c_class->privs));
+    memcpy(&c_class->privs_dirty, &privs_dirty, sizeof(c_class->privs_dirty));
+  }
+  else {
+   parse_error("Missing name in class block");
+  }
+  name = NULL;
+  pass = NULL;
+  tconn = 0;
+  maxlinks = 0;
+  sendq = 0;
+  memset(&privs, 0, sizeof(privs));
+  memset(&privs_dirty, 0, sizeof(privs_dirty));
+};
+classitems: classitem classitems | classitem;
+classitem: classname | classpingfreq | classconnfreq | classmaxlinks |
+           classsendq | classusermode | priv | maxchans;
+classname: NAME '=' QSTRING ';'
+{
+  MyFree(name);
+  name = $3;
+};
+maxchans: MAXCHANS '=' expr ';'
+{
+  maxchans = $3;
+};
+classpingfreq: PINGFREQ '=' timespec ';'
+{
+  tping = $3;
+};
+classconnfreq: CONNECTFREQ '=' timespec ';'
+{
+  tconn = $3;
+};
+classmaxlinks: MAXLINKS '=' expr ';'
+{
+  maxlinks = $3;
+};
+classsendq: SENDQ '=' sizespec ';'
+{
+  sendq = $3;
+};
+classusermode: USERMODE '=' QSTRING ';'
+{
+  MyFree(pass);
+  pass = $3;
+};
+
+connectblock: CONNECT
+{
+ flags = CONF_AUTOCONNECT;
+} '{' connectitems '}' ';'
+{
+ struct ConfItem *aconf = NULL;
+ if (name == NULL)
+  parse_error("Missing name in connect block");
+ else if (pass == NULL)
+  parse_error("Missing password in connect block");
+ else if (strlen(pass) > PASSWDLEN)
+  parse_error("Password too long in connect block");
+ else if (host == NULL)
+  parse_error("Missing host in connect block");
+ else if (strchr(host, '*') || strchr(host, '?'))
+  parse_error("Invalid host '%s' in connect block", host);
+ else if (c_class == NULL)
+  parse_error("Missing or non-existent class in connect block");
+ else {
+   aconf = make_conf(CONF_SERVER);
+   aconf->name = name;
+   aconf->origin_name = origin;
+   aconf->passwd = pass;
+   aconf->conn_class = c_class;
+   aconf->address.port = port;
+   aconf->host = host;
+   /* If the user specified a hub allowance, but not maximum links,
+    * allow an effectively unlimited number of hops.
+    */
+   aconf->maximum = (hub_limit != NULL && maxlinks == 0) ? 65535 : maxlinks;
+   aconf->hub_limit = hub_limit;
+   aconf->flags = flags;
+   lookup_confhost(aconf);
+ }
+ if (!aconf) {
+   MyFree(name);
+   MyFree(pass);
+   MyFree(host);
+   MyFree(origin);
+   MyFree(hub_limit);
+ }
+ name = pass = host = origin = hub_limit = NULL;
+ c_class = NULL;
+ port = flags = maxlinks = 0;
+};
+connectitems: connectitem connectitems | connectitem;
+connectitem: connectname | connectpass | connectclass | connecthost
+              | connectport | connectvhost | connectleaf | connecthub
+              | connecthublimit | connectmaxhops | connectauto | connectsecure;
+connectname: NAME '=' QSTRING ';'
+{
+ MyFree(name);
+ name = $3;
+};
+connectpass: PASS '=' QSTRING ';'
+{
+ MyFree(pass);
+ pass = $3;
+};
+connectclass: CLASS '=' QSTRING ';'
+{
+ c_class = find_class($3);
+ if (!c_class)
+  parse_error("No such connection class '%s' for Connect block", $3);
+ MyFree($3);
+};
+connecthost: HOST '=' QSTRING ';'
+{
+ MyFree(host);
+ host = $3;
+};
+connectport: PORT '=' NUMBER ';'
+{
+ port = $3;
+};
+connectvhost: VHOST '=' QSTRING ';'
+{
+ MyFree(origin);
+ origin = $3;
+};
+connectleaf: LEAF ';'
+{
+ maxlinks = 0;
+};
+connecthub: HUB ';'
+{
+ MyFree(hub_limit);
+ DupString(hub_limit, "*");
+};
+connecthublimit: HUB '=' QSTRING ';'
+{
+ MyFree(hub_limit);
+ hub_limit = $3;
+};
+connectmaxhops: MAXHOPS '=' expr ';'
+{
+  maxlinks = $3;
+};
+connectauto: AUTOCONNECT '=' YES ';' { flags |= CONF_AUTOCONNECT; }
+ | AUTOCONNECT '=' NO ';' { flags &= ~CONF_AUTOCONNECT; };
+connectsecure: SECURE '=' YES ';' { flags |= CONF_SECURE; }
+ | SECURE '=' NO ';' { flags &= ~CONF_SECURE; };
+
+uworldblock: UWORLD '{' uworlditems '}' ';';
+uworlditems: uworlditem uworlditems | uworlditem;
+uworlditem: uworldname;
+uworldname: NAME '=' QSTRING ';'
+{
+  make_conf(CONF_UWORLD)->host = $3;
+};
+
+operblock: OPER '{' operitems '}' ';'
+{
+  struct ConfItem *aconf = NULL;
+  struct SLink *link;
+
+  if (name == NULL)
+    parse_error("Missing name in operator block");
+  else if (pass == NULL)
+    parse_error("Missing password in operator block");
+  /* Do not check password length because it may be crypted. */
+  else if (hosts == NULL)
+    parse_error("Missing host(s) in operator block");
+  else if (c_class == NULL)
+    parse_error("Invalid or missing class in operator block");
+  else if (!FlagHas(&privs_dirty, PRIV_PROPAGATE)
+           && !FlagHas(&c_class->privs_dirty, PRIV_PROPAGATE))
+    parse_error("Operator block for %s and class %s have no LOCAL setting", name, c_class->cc_name);
+  else for (link = hosts; link != NULL; link = link->next) {
+    aconf = make_conf(CONF_OPERATOR);
+    DupString(aconf->name, name);
+    DupString(aconf->passwd, pass);
+    conf_parse_userhost(aconf, link->value.cp);
+    aconf->conn_class = c_class;
+    memcpy(&aconf->privs, &privs, sizeof(aconf->privs));
+    memcpy(&aconf->privs_dirty, &privs_dirty, sizeof(aconf->privs_dirty));
+  }
+  MyFree(name);
+  MyFree(pass);
+  free_slist(&hosts);
+  name = pass = NULL;
+  c_class = NULL;
+  memset(&privs, 0, sizeof(privs));
+  memset(&privs_dirty, 0, sizeof(privs_dirty));
+};
+operitems: operitem | operitems operitem;
+operitem: opername | operpass | operhost | operclass | priv;
+opername: NAME '=' QSTRING ';'
+{
+  MyFree(name);
+  name = $3;
+};
+operpass: PASS '=' QSTRING ';'
+{
+  MyFree(pass);
+  pass = $3;
+};
+operhost: HOST '=' QSTRING ';'
+{
+ struct SLink *link;
+ link = make_link();
+ if (!strchr($3, '@'))
+ {
+   int uh_len;
+   link->value.cp = (char*) MyMalloc((uh_len = strlen($3)+3));
+   ircd_snprintf(0, link->value.cp, uh_len, "*@%s", $3);
+ }
+ else
+   DupString(link->value.cp, $3);
+ MyFree($3);
+ link->next = hosts;
+ hosts = link;
+};
+operclass: CLASS '=' QSTRING ';'
+{
+ c_class = find_class($3);
+ if (!c_class)
+  parse_error("No such connection class '%s' for Operator block", $3);
+ MyFree($3);
+};
+
+priv: privtype '=' yesorno ';'
+{
+  FlagSet(&privs_dirty, $1);
+  if (($3 == 1) ^ invert)
+    FlagSet(&privs, $1);
+  else
+    FlagClr(&privs, $1);
+  invert = 0;
+};
+
+privtype: TPRIV_CHAN_LIMIT { $$ = PRIV_CHAN_LIMIT; } |
+          TPRIV_MODE_LCHAN { $$ = PRIV_MODE_LCHAN; } |
+          TPRIV_DEOP_LCHAN { $$ = PRIV_DEOP_LCHAN; } |
+          TPRIV_WALK_LCHAN { $$ = PRIV_WALK_LCHAN; } |
+          TPRIV_SEE_IDLETIME { $$ = PRIV_SEE_IDLETIME; } |
+          TPRIV_HIDE_IDLETIME { $$ = PRIV_HIDE_IDLETIME; } |
+          TPRIV_UMODE_NOCHAN { $$ = PRIV_UMODE_NOCHAN; } |
+          TPRIV_UMODE_NOIDLE { $$ = PRIV_UMODE_NOIDLE; } |
+          TPRIV_UMODE_CHSERV { $$ = PRIV_UMODE_CHSERV; } |
+          TPRIV_UMODE_XTRAOP { $$ = PRIV_UMODE_XTRAOP; } |
+          TPRIV_UMODE_NETSERV { $$ = PRIV_UMODE_NETSERV; } |
+          TPRIV_FLOOD { $$ = PRIV_FLOOD; } |
+          TPRIV_HALFFLOOD { $$ = PRIV_HALFFLOOD; } |
+          TPRIV_UNLIMITED_TARGET { $$ = PRIV_UNLIMITED_TARGET; } |
+          TPRIV_UMODE_OVERRIDECC { $$ = PRIV_UMODE_OVERRIDECC; } |
+          KILL { $$ = PRIV_KILL; } |
+          TPRIV_LOCAL_KILL { $$ = PRIV_LOCAL_KILL; } |
+          TPRIV_REHASH { $$ = PRIV_REHASH; } |
+          TPRIV_RESTART { $$ = PRIV_RESTART; } |
+          TPRIV_DIE { $$ = PRIV_DIE; } |
+          TPRIV_GLINE { $$ = PRIV_GLINE; } |
+          TPRIV_LOCAL_GLINE { $$ = PRIV_LOCAL_GLINE; } |
+          JUPE { $$ = PRIV_JUPE; } |
+          TPRIV_LOCAL_JUPE { $$ = PRIV_LOCAL_JUPE; } |
+          TPRIV_LOCAL_OPMODE { $$ = PRIV_LOCAL_OPMODE; } |
+          TPRIV_OPMODE { $$ = PRIV_OPMODE; }|
+          TPRIV_SET { $$ = PRIV_SET; } |
+          TPRIV_WHOX { $$ = PRIV_WHOX; } |
+          TPRIV_BADCHAN { $$ = PRIV_BADCHAN; } |
+          TPRIV_LOCAL_BADCHAN { $$ = PRIV_LOCAL_BADCHAN; } |
+          TPRIV_SEE_CHAN { $$ = PRIV_SEE_CHAN; } |
+          TPRIV_SHOW_INVIS { $$ = PRIV_SHOW_INVIS; } |
+          TPRIV_SHOW_ALL_INVIS { $$ = PRIV_SHOW_ALL_INVIS; } |
+          TPRIV_PROPAGATE { $$ = PRIV_PROPAGATE; } |
+          TPRIV_UNLIMIT_QUERY { $$ = PRIV_UNLIMIT_QUERY; } |
+          TPRIV_DISPLAY { $$ = PRIV_DISPLAY; } |
+          TPRIV_SEE_OPERS { $$ = PRIV_SEE_OPERS; } |
+          TPRIV_WIDE_GLINE { $$ = PRIV_WIDE_GLINE; } |
+          TPRIV_LIST_CHAN { $$ = PRIV_LIST_CHAN; } |
+          LOCAL { $$ = PRIV_PROPAGATE; invert = 1; } |
+          TPRIV_FORCE_OPMODE { $$ = PRIV_FORCE_OPMODE; } |
+          TPRIV_FORCE_LOCAL_OPMODE { $$ = PRIV_FORCE_LOCAL_OPMODE; } |
+          TPRIV_NOAMSG_OVERRIDE { $$ = PRIV_NOAMSG_OVERRIDE; } |
+          TPRIV_APASS_OPMODE { $$ = PRIV_APASS_OPMODE; } ;
+
+yesorno: YES { $$ = 1; } | NO { $$ = 0; };
+
+/* not a recursive definition because some pedant will just come along
+ * and whine that the parser accepts "ipv4 ipv4 ipv4 ipv4"
+ */
+address_family:
+               { $$ = 0; }
+    | TOK_IPV4 { $$ = USE_IPV4; }
+    | TOK_IPV6 { $$ = USE_IPV6; }
+    | TOK_IPV4 TOK_IPV6 { $$ = USE_IPV4 | USE_IPV6; }
+    | TOK_IPV6 TOK_IPV4 { $$ = USE_IPV6 | USE_IPV4; }
+    ;
+
+/* The port block... */
+portblock: PORT '{' portitems '}' ';' {
+  struct ListenerFlags flags_here;
+  struct SLink *link;
+  if (hosts == NULL) {
+    struct SLink *link;
+    link = make_link();
+    DupString(link->value.cp, "*");
+    link->flags = 0;
+    link->next = hosts;
+    hosts = link;
+  }
+  for (link = hosts; link != NULL; link = link->next) {
+    memcpy(&flags_here, &listen_flags, sizeof(&flags_here));
+    switch (link->flags & (USE_IPV4 | USE_IPV6)) {
+    case USE_IPV4:
+      FlagSet(&flags_here, LISTEN_IPV4);
+      break;
+    case USE_IPV6:
+      FlagSet(&flags_here, LISTEN_IPV6);
+      break;
+    default: /* 0 or USE_IPV4|USE_IPV6 */
+      FlagSet(&flags_here, LISTEN_IPV4);
+      FlagSet(&flags_here, LISTEN_IPV6);
+      break;
+    }
+    if (link->flags & 65535)
+      port = link->flags & 65535;
+    add_listener(port, link->value.cp, pass, &flags_here);
+  }
+  free_slist(&hosts);
+  MyFree(pass);
+  memset(&listen_flags, 0, sizeof(listen_flags));
+  pass = NULL;
+  port = 0;
+};
+portitems: portitem portitems | portitem;
+portitem: portnumber | portvhost | portvhostnumber | portmask | portserver | porthidden | portsecure;
+portnumber: PORT '=' address_family NUMBER ';'
+{
+  if ($4 < 1 || $4 > 65535) {
+    parse_error("Port %d is out of range", port);
+  } else {
+    port = $3 | $4;
+    if (hosts && (0 == (hosts->flags & 65535)))
+      hosts->flags = (hosts->flags & ~65535) | port;
+  }
+};
+
+portvhost: VHOST '=' address_family QSTRING ';'
+{
+  struct SLink *link;
+  link = make_link();
+  link->value.cp = $4;
+  link->flags = $3 | port;
+  link->next = hosts;
+  hosts = link;
+};
+
+portvhostnumber: VHOST '=' address_family QSTRING NUMBER ';'
+{
+  if ($5 < 1 || $5 > 65535) {
+    parse_error("Port %d is out of range", port);
+  } else {
+    struct SLink *link;
+    link = make_link();
+    link->value.cp = $4;
+    link->flags = $3 | $5;
+    link->next = hosts;
+    hosts = link;
+  }
+};
+
+portmask: MASK '=' QSTRING ';'
+{
+  MyFree(pass);
+  pass = $3;
+};
+
+portserver: SERVER '=' YES ';'
+{
+  FlagSet(&listen_flags, LISTEN_SERVER);
+} | SERVER '=' NO ';'
+{
+  FlagClr(&listen_flags, LISTEN_SERVER);
+};
+
+porthidden: HIDDEN '=' YES ';'
+{
+  FlagSet(&listen_flags, LISTEN_HIDDEN);
+} | HIDDEN '=' NO ';'
+{
+  FlagClr(&listen_flags, LISTEN_HIDDEN);
+};
+
+portsecure: SECURE '=' YES ';'
+{
+  FlagSet(&listen_flags, LISTEN_SSL);
+} | SECURE '=' NO ';'
+{
+  FlagClr(&listen_flags, LISTEN_SSL);
+};
+
+clientblock: CLIENT
+{
+  maxlinks = 65535;
+  port = 0;
+}
+'{' clientitems '}' ';'
+{
+  struct ConfItem *aconf = 0;
+  struct irc_in_addr addr;
+  unsigned char addrbits = 0;
+
+  if (!c_class)
+    parse_error("Invalid or missing class in Client block");
+  else if (pass && strlen(pass) > PASSWDLEN)
+    parse_error("Password too long in connect block");
+  else if (ip && !ipmask_parse(ip, &addr, &addrbits))
+    parse_error("Invalid IP address %s in Client block", ip);
+  else {
+    aconf = make_conf(CONF_CLIENT);
+    aconf->username = username;
+    aconf->host = host;
+    if (ip)
+      memcpy(&aconf->address.addr, &addr, sizeof(aconf->address.addr));
+    else
+      memset(&aconf->address.addr, 0, sizeof(aconf->address.addr));
+    aconf->address.port = port;
+    aconf->addrbits = addrbits;
+    aconf->name = ip;
+    aconf->conn_class = c_class;
+    aconf->maximum = maxlinks;
+    aconf->passwd = pass;
+  }
+  if (!aconf) {
+    MyFree(username);
+    MyFree(host);
+    MyFree(ip);
+    MyFree(pass);
+  }
+  host = NULL;
+  username = NULL;
+  c_class = NULL;
+  maxlinks = 0;
+  ip = NULL;
+  pass = NULL;
+  port = 0;
+};
+clientitems: clientitem clientitems | clientitem;
+clientitem: clienthost | clientip | clientusername | clientclass | clientpass | clientmaxlinks | clientport;
+clienthost: HOST '=' QSTRING ';'
+{
+  char *sep = strchr($3, '@');
+  MyFree(host);
+  if (sep) {
+    *sep++ = '\0';
+    MyFree(username);
+    DupString(host, sep);
+    username = $3;
+  } else {
+    host = $3;
+  }
+};
+clientip: IP '=' QSTRING ';'
+{
+  char *sep;
+  sep = strchr($3, '@');
+  MyFree(ip);
+  if (sep) {
+    *sep++ = '\0';
+    MyFree(username);
+    DupString(ip, sep);
+    username = $3;
+  } else {
+    ip = $3;
+  }
+};
+clientusername: USERNAME '=' QSTRING ';'
+{
+  MyFree(username);
+  username = $3;
+};
+clientclass: CLASS '=' QSTRING ';'
+{
+  c_class = find_class($3);
+  if (!c_class)
+    parse_error("No such connection class '%s' for Client block", $3);
+  MyFree($3);
+};
+clientpass: PASS '=' QSTRING ';'
+{
+  MyFree(pass);
+  pass = $3;
+};
+clientmaxlinks: MAXLINKS '=' expr ';'
+{
+  maxlinks = $3;
+};
+clientport: PORT '=' expr ';'
+{
+  port = $3;
+};
+
+killblock: KILL
+{
+  dconf = (struct DenyConf*) MyCalloc(1, sizeof(*dconf));
+} '{' killitems '}' ';'
+{
+  if (dconf->usermask || dconf->hostmask ||dconf->realmask) {
+    dconf->next = denyConfList;
+    denyConfList = dconf;
+  }
+  else
+  {
+    MyFree(dconf->usermask);
+    MyFree(dconf->hostmask);
+    MyFree(dconf->realmask);
+    MyFree(dconf->message);
+    MyFree(dconf);
+    parse_error("Kill block must match on at least one of username, host or realname");
+  }
+  dconf = NULL;
+};
+killitems: killitem killitems | killitem;
+killitem: killuhost | killreal | killusername | killreasonfile | killreason;
+killuhost: HOST '=' QSTRING ';'
+{
+  char *h;
+  MyFree(dconf->hostmask);
+  MyFree(dconf->usermask);
+  if ((h = strchr($3, '@')) == NULL)
+  {
+    DupString(dconf->usermask, "*");
+    dconf->hostmask = $3;
+  }
+  else
+  {
+    *h++ = '\0';
+    DupString(dconf->hostmask, h);
+    dconf->usermask = $3;
+  }
+  ipmask_parse(dconf->hostmask, &dconf->address, &dconf->bits);
+};
+
+killusername: USERNAME '=' QSTRING ';'
+{
+  MyFree(dconf->usermask);
+  dconf->usermask = $3;
+};
+
+killreal: REAL '=' QSTRING ';'
+{
+ MyFree(dconf->realmask);
+ dconf->realmask = $3;
+};
+
+killreason: REASON '=' QSTRING ';'
+{
+ dconf->flags &= ~DENY_FLAGS_FILE;
+ MyFree(dconf->message);
+ dconf->message = $3;
+};
+
+killreasonfile: TFILE '=' QSTRING ';'
+{
+ dconf->flags |= DENY_FLAGS_FILE;
+ MyFree(dconf->message);
+ dconf->message = $3;
+};
+
+cruleblock: CRULE
+{
+  tconn = CRULE_AUTO;
+} '{' cruleitems '}' ';'
+{
+  struct CRuleNode *node = NULL;
+  struct SLink *link;
+
+  if (hosts == NULL)
+    parse_error("Missing server(s) in crule block");
+  else if (pass == NULL)
+    parse_error("Missing rule in crule block");
+  else if ((node = crule_parse(pass)) == NULL)
+    parse_error("Invalid rule '%s' in crule block", pass);
+  else for (link = hosts; link != NULL; link = link->next)
+  {
+    struct CRuleConf *p = (struct CRuleConf*) MyMalloc(sizeof(*p));
+    if (node == NULL)
+      node = crule_parse(pass);
+    DupString(p->hostmask, link->value.cp);
+    DupString(p->rule, pass);
+    p->type = tconn;
+    p->node = node;
+    node = NULL;
+    p->next = cruleConfList;
+    cruleConfList = p;
+  }
+  free_slist(&hosts);
+  MyFree(pass);
+  pass = NULL;
+  tconn = 0;
+};
+
+cruleitems: cruleitem cruleitems | cruleitem;
+cruleitem: cruleserver | crulerule | cruleall;
+
+cruleserver: SERVER '=' QSTRING ';'
+{
+  struct SLink *link;
+  link = make_link();
+  link->value.cp = $3;
+  link->next = hosts;
+  hosts = link;
+};
+
+crulerule: RULE '=' QSTRING ';'
+{
+ MyFree(pass);
+ pass = $3;
+};
+
+cruleall: ALL '=' YES ';'
+{
+ tconn = CRULE_ALL;
+} | ALL '=' NO ';'
+{
+ tconn = CRULE_AUTO;
+};
+
+motdblock: MOTD '{' motditems '}' ';'
+{
+  struct SLink *link;
+  if (pass != NULL)
+    for (link = hosts; link != NULL; link = link->next)
+      motd_add(link->value.cp, pass);
+  free_slist(&hosts);
+  MyFree(pass);
+  pass = NULL;
+};
+
+motditems: motditem motditems | motditem;
+motditem: motdhost | motdfile;
+motdhost: HOST '=' QSTRING ';'
+{
+  struct SLink *link;
+  link = make_link();
+  link->value.cp = $3;
+  link->next = hosts;
+  hosts = link;
+};
+
+motdfile: TFILE '=' QSTRING ';'
+{
+  MyFree(pass);
+  pass = $3;
+};
+
+featuresblock: FEATURES '{' featureitems '}' ';';
+featureitems: featureitems featureitem | featureitem;
+
+featureitem: QSTRING
+{
+  stringlist[0] = $1;
+  stringno = 1;
+} '=' stringlist ';' {
+  unsigned int ii;
+  feature_set(NULL, (const char * const *)stringlist, stringno);
+  for (ii = 0; ii < stringno; ++ii)
+    MyFree(stringlist[ii]);
+};
+
+stringlist: stringlist extrastring | extrastring;
+extrastring: QSTRING
+{
+  if (stringno < MAX_STRINGS)
+    stringlist[stringno++] = $1;
+  else
+    MyFree($1);
+};
+
+quarantineblock: QUARANTINE '{' quarantineitems '}' ';';
+quarantineitems: quarantineitems quarantineitem | quarantineitem;
+quarantineitem: QSTRING '=' QSTRING ';'
+{
+  struct qline *qconf = MyCalloc(1, sizeof(*qconf));
+  qconf->chname = $1;
+  qconf->reason = $3;
+  qconf->next = GlobalQuarantineList;
+  GlobalQuarantineList = qconf;
+};
+
+pseudoblock: PSEUDO QSTRING '{'
+{
+  smap = MyCalloc(1, sizeof(struct s_map));
+  smap->command = $2;
+}
+pseudoitems '}' ';'
+{
+  int valid = 0;
+
+  if (!smap->name)
+    parse_error("Missing name in pseudo %s block", smap->command);
+  else if (!smap->services)
+    parse_error("Missing nick in pseudo %s block", smap->command);
+  else if (!strIsAlpha(smap->command))
+    parse_error("Pseudo command %s invalid: must all be letters", smap->command);
+  else
+    valid = 1;
+  if (valid && register_mapping(smap))
+  {
+    smap->next = GlobalServiceMapList;
+    GlobalServiceMapList = smap;
+  }
+  else
+  {
+    free_mapping(smap);
+  }
+  smap = NULL;
+};
+
+pseudoitems: pseudoitem pseudoitems | pseudoitem;
+pseudoitem: pseudoname | pseudoprepend | pseudonick | pseudoflags;
+pseudoname: NAME '=' QSTRING ';'
+{
+  MyFree(smap->name);
+  smap->name = $3;
+};
+pseudoprepend: PREPEND '=' QSTRING ';'
+{
+  MyFree(smap->prepend);
+  smap->prepend = $3;
+};
+pseudonick: NICK '=' QSTRING ';'
+{
+  char *sep = strchr($3, '@');
+
+  if (sep != NULL) {
+    size_t slen = strlen($3);
+    struct nick_host *nh = MyMalloc(sizeof(*nh) + slen);
+    memcpy(nh->nick, $3, slen + 1);
+    nh->nicklen = sep - $3;
+    nh->next = smap->services;
+    smap->services = nh;
+  }
+  MyFree($3);
+};
+pseudoflags: FAST ';'
+{
+  smap->flags |= SMAP_FAST;
+};
+
+iauthblock: IAUTH '{' iauthitems '}' ';'
+{
+  auth_spawn(stringno, stringlist, iauth_required);
+  while (stringno > 0)
+  {
+    --stringno;
+    MyFree(stringlist[stringno]);
+  }
+  iauth_required = 0;
+};
+
+iauthitems: iauthitem iauthitems | iauthitem;
+iauthitem: iauthprogram | iauthrequired;
+iauthprogram: PROGRAM '='
+{
+  while (stringno > 0)
+  {
+    --stringno;
+    MyFree(stringlist[stringno]);
+  }
+} stringlist ';';
+
+iauthrequired: REQUIRED '=' yesorno ';'
+{
+  iauth_required = $3;
+}
+
+forwardsblock: FORWARDS {
+  unsigned int ii;
+  for(ii = 0; ii < 256; ++ii) {
+    MyFree(GlobalForwards[ii]);
+  }
+} '{' forwarditems '}' ';';
+forwarditems: forwarditems forwarditem | forwarditem;
+forwarditem: QSTRING '=' QSTRING ';'
+{
+  unsigned char ch = $1[0];
+  MyFree(GlobalForwards[ch]);
+  GlobalForwards[ch] = $3;
+  MyFree($1);
+};
+
+webircblock: WEBIRC {
+    /* If we read a new webirc block, we create a new block. */
+    webirc = webirc_block();
+} '{' webircitems '}' ';' {
+    /* check for integrity */
+    if(!webirc->name[0]) {
+        parse_error("Every WebIRC block needs at least a name entry.");
+        webirc_list_clear(webirc);
+        MyFree(webirc);
+        webirc = NULL;
+    }
+    else {
+        webirc_establish(webirc);
+        webirc = NULL;
+    }
+};
+webircitems: webircitems webircitem | webircitem;
+webircitem: webircpass | webirchost | webircnhost | webircspoof | webircnspoof | webircname;
+webircpass: PASS '=' QSTRING ';' {
+    unsigned int len;
+    if((len = strlen($3)) > 0)
+        webirc_set(webirc, WEBIRC_PASS, $3, len, 0);
+    MyFree($3);
+};
+webirchost: HOST '=' QSTRING ';' {
+    unsigned int len;
+    if((len = strlen($3)) > 0)
+        webirc_set(webirc, WEBIRC_HOST, $3, len, 0);
+    MyFree($3);
+};
+webircnhost: HOST '!' '=' QSTRING ';' {
+    unsigned int len;
+    if((len = strlen($4)) > 0)
+        webirc_set(webirc, WEBIRC_HOST, $4, len, 1);
+    MyFree($4);
+};
+webircspoof: SPOOF '=' QSTRING ';' {
+    unsigned int len;
+    if((len = strlen($3)) > 0)
+        webirc_set(webirc, WEBIRC_SPOOF, $3, len, 0);
+    MyFree($3);
+};
+webircnspoof: SPOOF '!' '=' QSTRING ';' {
+    unsigned int len;
+    if((len = strlen($4)) > 0)
+        webirc_set(webirc, WEBIRC_SPOOF, $4, len, 1);
+    MyFree($4);
+};
+webircname: NAME '=' QSTRING ';' {
+    unsigned int len;
+    if(webirc->name[0]) {
+        MyFree($3);
+        parse_error("Only one name entry per WebIRC is allowed.");
+    }
+    else if((len = strlen($3)) > NICKLEN) {
+        MyFree($3);
+        parse_error("WebIRC block name length is limited to NICKLEN.");
+    }
+    else {
+        if((len = strlen($3)) > 0) {
+            strcpy(webirc->name, $3);
+            webirc->name[len] = '\0';
+        }
+        MyFree($3);
+    }
+};
+
+sslblock: SSL '{' sslitems '}' ';' ;
+sslitems: sslitems sslitem | sslitem;
+sslitem: sslcert | sslcacert;
+sslcert: CERT '=' QSTRING ';' {
+    ssl_setcert($3);
+    MyFree($3);
+};
+sslcacert: CACERT '=' QSTRING ';' {
+    ssl_addtrust($3);
+    MyFree($3);
+};
+
diff --git a/ircd/ircd_relay.c b/ircd/ircd_relay.c
new file mode 100644 (file)
index 0000000..701c639
--- /dev/null
@@ -0,0 +1,711 @@
+/*
+ * IRC - Internet Relay Chat, ircd/ircd_relay.c
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ *                    University of Oulu, Computing Center
+ *
+ * See file AUTHORS in IRC package for additional names of
+ * the programmers.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+/** @file
+ * @brief Helper functions to relay various types of messages.
+ * @version $Id: ircd_relay.c 1271 2004-12-11 05:14:07Z klmitch $
+ *
+ * There are four basic types of messages, each with four subtypes.
+ *
+ * The basic types are: channel, directed, masked, and private.
+ * Channel messages are (perhaps obviously) sent directly to a
+ * channel.  Directed messages are sent to "NICK[%host]@server", but
+ * only allowed if the server is a services server (to avoid
+ * information leaks for normal clients).  Masked messages are sent to
+ * either *@*host.mask or *.server.mask.  Private messages are sent to
+ * NICK.
+ *
+ * The subtypes for each type are: client message, client notice,
+ * server message, and server notice.  Client subtypes are sent by a
+ * local user, and server subtypes are given to us by a server.
+ * Notice subtypes correspond to the NOTICE command, and message
+ * subtypes correspond to the PRIVMSG command.
+ *
+ * As a special note, directed messages do not have server subtypes,
+ * since there is no difference in handling them based on origin.
+ */
+#include "config.h"
+
+#include "ircd_relay.h"
+#include "channel.h"
+#include "client.h"
+#include "hash.h"
+#include "ircd.h"
+#include "ircd_chattr.h"
+#include "ircd_features.h"
+#include "ircd_log.h"
+#include "ircd_reply.h"
+#include "ircd_string.h"
+#include "match.h"
+#include "msg.h"
+#include "numeric.h"
+#include "numnicks.h"
+#include "s_debug.h"
+#include "s_misc.h"
+#include "s_user.h"
+#include "send.h"
+
+/* #include <assert.h> -- Now using assert in ircd_log.h */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+/*
+ * This file contains message relaying functions for client and server
+ * private messages and notices
+ * TODO: This file contains a lot of cut and paste code, and needs
+ * to be cleaned up a bit. The idea is to factor out the common checks
+ * but not introduce any IsOper/IsUser/MyUser/IsServer etc. stuff.
+ */
+
+/** Relay a local user's message to a channel.
+ * Generates an error if the client cannot send to the channel.
+ * @param[in] sptr Client that originated the message.
+ * @param[in] name Name of target channel.
+ * @param[in] text %Message to relay.
+ * @param[in] ccount Count of channels we're sending the message to.
+ */
+void relay_channel_message(struct Client* sptr, const char* name, const char* text, const int ccount)
+{
+  struct Channel* chptr;
+  const char *c;
+  assert(0 != sptr);
+  assert(0 != name);
+  assert(0 != text);
+
+  if (0 == (chptr = FindChannel(name))) {
+    send_reply(sptr, ERR_NOSUCHCHANNEL, name);
+    return;
+  }
+
+  /* First thing we do is passing the message to the extended NOAMSG mode.
+   * It even can use the input when the message is dropped later on.
+   */
+  if(!IsXtraOp(sptr) && !HasPriv(sptr, PRIV_NOAMSG_OVERRIDE) && ext_amsg_block(sptr, chptr, text)) {
+    send_reply(sptr, ERR_CANNOTSENDTOCHAN, chptr->chname);
+    return;
+  }
+
+  /*
+   * This first: Almost never a server/service
+   */
+  if (!client_can_send_to_channel(sptr, chptr, 0)) {
+    send_reply(sptr, ERR_CANNOTSENDTOCHAN, chptr->chname);
+    return;
+  }
+  if ((chptr->mode.mode & MODE_NOPRIVMSGS) &&
+      check_target_limit(sptr, chptr, chptr->chname, 0))
+    return;
+
+  /* multi target message check */
+  if(!IsXtraOp(sptr) && !HasPriv(sptr, PRIV_NOAMSG_OVERRIDE) && (chptr->mode.mode & MODE_NOAMSGS) && (ccount > 1)) {
+    send_reply(sptr, ERR_CANNOTSENDTOCHAN, chptr->chname);
+    return;
+  }
+
+    /* Check for color/ctcp. */
+    if((chptr->mode.mode & MODE_NOCOLOUR) && !IsOverrideCC(sptr)) {
+        for(c = text; *c; c++) {
+            if(*c == 3 || *c == 27) {
+                send_reply(sptr, ERR_CANNOTSENDTOCHAN, chptr->chname);
+                return;
+            }
+        }
+    }
+    /* Still allow /me to function. */
+    if((chptr->mode.mode & MODE_NOCTCP) && !IsOverrideCC(sptr) && ircd_strncmp(text, "\001ACTION ", 8)) {
+        for(c = text; *c; ++c) {
+            if(*c == 1) {
+                send_reply(sptr, ERR_CANNOTSENDTOCHAN, chptr->chname);
+                return;
+            }
+        }
+    }
+
+  RevealDelayedJoinIfNeeded(sptr, chptr);
+  sendcmdto_channel_butone(sptr, CMD_PRIVATE, chptr, cli_from(sptr),
+                          SKIP_DEAF | SKIP_BURST, text[0], "%H :%s", chptr, text);
+}
+
+/** Relay a local user's notice to a channel.
+ * Silently exits if the client cannot send to the channel.
+ * @param[in] sptr Client that originated the message.
+ * @param[in] name Name of target channel.
+ * @param[in] text %Message to relay.
+ * @param[in] ccount Count of channels we're sending the message to.
+ */
+void relay_channel_notice(struct Client* sptr, const char* name, const char* text, const int ccount)
+{
+  struct Channel* chptr;
+  const char *c;
+  assert(0 != sptr);
+  assert(0 != name);
+  assert(0 != text);
+
+  if (0 == (chptr = FindChannel(name)))
+    return;
+
+  /* First thing we do is passing the message to the extended NOAMSG mode.
+   * It even can use the input when the message is dropped later on.
+   */
+  if(!IsXtraOp(sptr) && !HasPriv(sptr, PRIV_NOAMSG_OVERRIDE) && ext_amsg_block(sptr, chptr, text))
+    return;
+       
+  /* Now we check if the channel has the NONOTICE mode
+   * If NONOTICE is set only XtraOPS or ColorOverride users can send notices!
+   */
+  if((chptr->mode.mode & MODE_NONOTICE) && !IsOverrideCC(sptr) && !IsXtraOp(sptr)) {
+    send_reply(sptr, ERR_CANNOTSENDTOCHAN, chptr->chname);
+    return;
+  }
+
+  /*
+   * This first: Almost never a server/service
+   */
+  if (!client_can_send_to_channel(sptr, chptr, 0))
+    return;
+
+  if ((chptr->mode.mode & MODE_NOPRIVMSGS) &&
+      check_target_limit(sptr, chptr, chptr->chname, 0))
+    return;
+
+  /* multi target message check */
+  if(!IsXtraOp(sptr) && !HasPriv(sptr, PRIV_NOAMSG_OVERRIDE) && (chptr->mode.mode & MODE_NOAMSGS) && (ccount > 1))
+    return;
+
+    /* Check for color/ctcp. */
+    if((chptr->mode.mode & MODE_NOCOLOUR) && !IsOverrideCC(sptr)) {
+        for(c = text; *c; c++) {
+            if(*c == 3 || *c == 27) {
+                return;
+            }
+        }
+    }
+    /* Still allow /me to function. */
+    if((chptr->mode.mode & MODE_NOCTCP) && !IsOverrideCC(sptr) && ircd_strncmp(text, "\001ACTION ", 8)) {
+        for(c = text; *c; ++c) {
+            if(*c == 1) {
+                return;
+            }
+        }
+    }
+
+  RevealDelayedJoinIfNeeded(sptr, chptr);
+  sendcmdto_channel_butone(sptr, CMD_NOTICE, chptr, cli_from(sptr),
+                          SKIP_DEAF | SKIP_BURST, '\0', "%H :%s", chptr, text);
+}
+
+/** Relay a message to a channel.
+ * Generates an error if the client cannot send to the channel,
+ * or if the channel is a local channel
+ * @param[in] sptr Client that originated the message.
+ * @param[in] name Name of target channel.
+ * @param[in] text %Message to relay.
+ */
+void server_relay_channel_message(struct Client* sptr, const char* name, const char* text)
+{
+  struct Channel* chptr;
+  assert(0 != sptr);
+  assert(0 != name);
+  assert(0 != text);
+
+  if (IsLocalChannel(name) || 0 == (chptr = FindChannel(name))) {
+    send_reply(sptr, ERR_NOSUCHCHANNEL, name);
+    return;
+  }
+  /*
+   * This first: Almost never a server/service
+   * Servers may have channel services, need to check for it here
+   */
+  if (client_can_send_to_channel(sptr, chptr, 1) || IsChannelService(sptr)) {
+    sendcmdto_channel_butone(sptr, CMD_PRIVATE, chptr, cli_from(sptr),
+                            SKIP_DEAF | SKIP_BURST, text[0], "%H :%s", chptr, text);
+  }
+  else
+    send_reply(sptr, ERR_CANNOTSENDTOCHAN, chptr->chname);
+}
+
+/** Relay a notice to a channel.
+ * Generates an error if the client cannot send to the channel,
+ * or if the channel is a local channel
+ * @param[in] sptr Client that originated the message.
+ * @param[in] name Name of target channel.
+ * @param[in] text %Message to relay.
+ */
+void server_relay_channel_notice(struct Client* sptr, const char* name, const char* text)
+{
+  struct Channel* chptr;
+  assert(0 != sptr);
+  assert(0 != name);
+  assert(0 != text);
+
+  if (IsLocalChannel(name) || 0 == (chptr = FindChannel(name)))
+    return;
+  /*
+   * This first: Almost never a server/service
+   * Servers may have channel services, need to check for it here
+   */
+  if (client_can_send_to_channel(sptr, chptr, 1) || IsChannelService(sptr)) {
+    sendcmdto_channel_butone(sptr, CMD_NOTICE, chptr, cli_from(sptr),
+                            SKIP_DEAF | SKIP_BURST, '\0', "%H :%s", chptr, text);
+  }
+}
+
+/** Relay a directed message.
+ * Same as "relay_directed_message" but has some other privilege checks.
+ * Checks that the target user is on an ulined server.
+ * If this check fails, it takes \a server as an account
+ * name and checks whether \a name has the account set.
+ * If both checks fail, it prints a message to the user and returns.
+ * @param[in] sptr Client that originated the message.
+ * @param[in] name Target nickname.
+ * @param[in] server Name of target server.
+ * @param[in] text %Message to relay.
+ */
+int relay_directed_account_server_message(struct Client* sptr, char* name, char* server, const char* text)
+{
+  struct Client* acptr, *dest;
+  char*          host;
+  char*          serv;
+
+  assert(0 != sptr);
+  assert(0 != name);
+  assert(0 != text);
+  assert(0 != server);
+
+  serv = server + 1;
+  *server = '\0';
+  if ((host = strchr(name, '%')))
+    *host++ = '\0';
+
+  if (!(acptr = FindUser(name)) || (!EmptyString(host) && 0 != match(host, cli_user(acptr)->host)))
+  {
+    return 0;
+  }
+
+  if((dest = FindServer(serv)) == NULL || dest != cli_user(acptr)->server || !IsService(dest)) {
+    if(!IsNetServ(acptr) || !IsAccount(acptr) || 0 != ircd_strcmp(cli_user(acptr)->account, serv)) {
+      return 0;
+    }
+  }
+
+  if(dest) {
+    *server = '@';
+    if(host)
+      *--host = '%';
+    sendcmdto_one(sptr, CMD_PRIVATE, acptr, "%s :%s", name, text);
+    return 1;
+  }
+
+  if(!MyUser(acptr))
+  {
+    sendcmdto_one(sptr, CMD_PRIVATE, acptr, "%C :%s", acptr, text);
+  }
+  else
+  {
+    if (!(is_silenced(sptr, acptr)))
+      sendcmdto_one(sptr, CMD_PRIVATE, acptr, "%C :%s", acptr, text);
+  }
+
+  *server = '@';
+  if (host)
+    *--host = '%';
+
+  return 1;
+}
+
+/** Relay a directed message.
+ * Generates an error if the named server does not exist, if it is not
+ * a services server, or if \a name names a local user and a hostmask
+ * is specified but does not match.
+ * @param[in] sptr Client that originated the message.
+ * @param[in] name Target nickname, with optional "%hostname" suffix.
+ * @param[in] server Name of target server.
+ * @param[in] text %Message to relay.
+ */
+void relay_directed_message(struct Client* sptr, char* name, char* server, const char* text)
+{
+  struct Client* acptr;
+  char*          host;
+
+  assert(0 != sptr);
+  assert(0 != name);
+  assert(0 != text);
+  assert(0 != server);
+
+  if ((acptr = FindServer(server + 1)) == NULL || !IsService(acptr))
+  {
+    send_reply(sptr, ERR_NOSUCHNICK, name);
+    return;
+  }
+  /*
+   * NICK[%host]@server addressed? See if <server> is me first
+   */
+  if (!IsMe(acptr))
+  {
+    sendcmdto_one(sptr, CMD_PRIVATE, acptr, "%s :%s", name, text);
+    return;
+  }
+  /*
+   * Look for an user whose NICK is equal to <name> and then
+   * check if it's hostname matches <host> and if it's a local
+   * user.
+   */
+  *server = '\0';
+  if ((host = strchr(name, '%')))
+    *host++ = '\0';
+
+  /* As reported by Vampire-, it's possible to brute force finding users
+   * by sending a message to each server and see which one succeeded.
+   * This means we have to remove error reporting.  Sigh.  Better than
+   * removing the ability to send directed messages to client servers 
+   * Thanks for the suggestion Vampire=.  -- Isomer 2001-08-28
+   * Argh, /ping nick@server, disallow messages to non +k clients :/  I hate
+   * this. -- Isomer 2001-09-16
+   */
+  if (!(acptr = FindUser(name)) || !MyUser(acptr) ||
+      (!EmptyString(host) && 0 != match(host, cli_user(acptr)->host)) ||
+      !IsChannelService(acptr))
+  {
+    /*
+     * By this stage we might as well not bother because they will
+     * know that this server is currently linked because of the
+     * increased lag.
+     */
+    send_reply(sptr, ERR_NOSUCHNICK, name);
+    return;
+  }
+
+  *server = '@';
+  if (host)
+    *--host = '%';
+
+  if (!(is_silenced(sptr, acptr)))
+    sendcmdto_one(sptr, CMD_PRIVATE, acptr, "%s :%s", name, text);
+}
+
+/** Relay a directed notice.
+ * Generates an error if the named server does not exist, if it is not
+ * a services server, or if \a name names a local user and a hostmask
+ * is specified but does not match.
+ * @param[in] sptr Client that originated the message.
+ * @param[in] name Target nickname, with optional "%hostname" suffix.
+ * @param[in] server Name of target server.
+ * @param[in] text %Message to relay.
+ */
+void relay_directed_notice(struct Client* sptr, char* name, char* server, const char* text)
+{
+  struct Client* acptr;
+  char*          host;
+
+  assert(0 != sptr);
+  assert(0 != name);
+  assert(0 != text);
+  assert(0 != server);
+
+  if (0 == (acptr = FindServer(server + 1)))
+    return;
+  /*
+   * NICK[%host]@server addressed? See if <server> is me first
+   */
+  if (!IsMe(acptr)) {
+    sendcmdto_one(sptr, CMD_NOTICE, acptr, "%s :%s", name, text);
+    return;
+  }
+  /*
+   * Look for an user whose NICK is equal to <name> and then
+   * check if it's hostname matches <host> and if it's a local
+   * user.
+   */
+  *server = '\0';
+  if ((host = strchr(name, '%')))
+    *host++ = '\0';
+
+  if (!(acptr = FindUser(name)) || !MyUser(acptr) ||
+      (!EmptyString(host) && 0 != match(host, cli_user(acptr)->host)))
+    return;
+
+  *server = '@';
+  if (host)
+    *--host = '%';
+
+  if (!(is_silenced(sptr, acptr)))
+    sendcmdto_one(sptr, CMD_NOTICE, acptr, "%s :%s", name, text);
+}
+
+/** Relay a private message from a local user.
+ * Returns an error if the user does not exist or sending to him would
+ * exceed the source's free targets.  Sends an AWAY status message if
+ * the target is marked as away.
+ * @param[in] sptr Client that originated the message.
+ * @param[in] name Nickname of target user.
+ * @param[in] text %Message to relay.
+ */
+void relay_private_message(struct Client* sptr, const char* name, const char* text)
+{
+  struct Client* acptr;
+
+  assert(0 != sptr);
+  assert(0 != name);
+  assert(0 != text);
+
+  if (0 == (acptr = FindUser(name))) {
+    send_reply(sptr, ERR_NOSUCHNICK, name);
+    return;
+  }
+  if ((!IsChannelService(acptr) &&
+       check_target_limit(sptr, acptr, cli_name(acptr), 0)) ||
+      is_silenced(sptr, acptr))
+    return;
+
+  /*
+   * send away message if user away
+   */
+  if (cli_user(acptr) && cli_user(acptr)->away)
+    send_reply(sptr, RPL_AWAY, cli_name(acptr), cli_user(acptr)->away);
+  /*
+   * deliver the message
+   */
+  if (MyUser(acptr))
+    add_target(acptr, sptr);
+
+  sendcmdto_one(sptr, CMD_PRIVATE, acptr, "%C :%s", acptr, text);
+}
+
+/** Relay a private notice from a local user.
+ * Returns an error if the user does not exist or sending to him would
+ * exceed the source's free targets.  Sends an AWAY status message if
+ * the target is marked as away.
+ * @param[in] sptr Client that originated the message.
+ * @param[in] name Nickname of target user.
+ * @param[in] text %Message to relay.
+ */
+void relay_private_notice(struct Client* sptr, const char* name, const char* text)
+{
+  struct Client* acptr;
+  assert(0 != sptr);
+  assert(0 != name);
+  assert(0 != text);
+
+  if (0 == (acptr = FindUser(name)))
+    return;
+  if ((!IsChannelService(acptr) && 
+       check_target_limit(sptr, acptr, cli_name(acptr), 0)) ||
+      is_silenced(sptr, acptr))
+    return;
+  /*
+   * deliver the message
+   */
+  if (MyUser(acptr))
+    add_target(acptr, sptr);
+
+  sendcmdto_one(sptr, CMD_NOTICE, acptr, "%C :%s", acptr, text);
+}
+
+/** Relay a private message that arrived from a server.
+ * Returns an error if the user does not exist.
+ * @param[in] sptr Client that originated the message.
+ * @param[in] name Nickname of target user.
+ * @param[in] text %Message to relay.
+ */
+void server_relay_private_message(struct Client* sptr, const char* name, const char* text)
+{
+  struct Client* acptr;
+  assert(0 != sptr);
+  assert(0 != name);
+  assert(0 != text);
+  /*
+   * nickname addressed?
+   */
+  if (0 == (acptr = findNUser(name)) || !IsUser(acptr)) {
+    send_reply(sptr, SND_EXPLICIT | ERR_NOSUCHNICK, "* :Target left %s. "
+              "Failed to deliver: [%.20s]", feature_str(FEAT_NETWORK),
+               text);
+    return;
+  }
+  if (is_silenced(sptr, acptr))
+    return;
+
+  if (MyUser(acptr))
+    add_target(acptr, sptr);
+
+  sendcmdto_one(sptr, CMD_PRIVATE, acptr, "%C :%s", acptr, text);
+}
+
+
+/** Relay a private notice that arrived from a server.
+ * Returns an error if the user does not exist.
+ * @param[in] sptr Client that originated the message.
+ * @param[in] name Nickname of target user.
+ * @param[in] text %Message to relay.
+ */
+void server_relay_private_notice(struct Client* sptr, const char* name, const char* text)
+{
+  struct Client* acptr;
+  assert(0 != sptr);
+  assert(0 != name);
+  assert(0 != text);
+  /*
+   * nickname addressed?
+   */
+  if (0 == (acptr = findNUser(name)) || !IsUser(acptr))
+    return;
+
+  if (is_silenced(sptr, acptr))
+    return;
+
+  if (MyUser(acptr))
+    add_target(acptr, sptr);
+
+  sendcmdto_one(sptr, CMD_NOTICE, acptr, "%C :%s", acptr, text);
+}
+
+/** Relay a masked message from a local user.
+ * Sends an error response if there is no top-level domain label in \a
+ * mask, or if that TLD contains a wildcard.
+ * @param[in] sptr Client that originated the message.
+ * @param[in] mask Target mask for the message.
+ * @param[in] text %Message to relay.
+ */
+void relay_masked_message(struct Client* sptr, const char* mask, const char* text)
+{
+  const char* s;
+  int   host_mask = 0;
+
+  assert(0 != sptr);
+  assert(0 != mask);
+  assert(0 != text);
+  /*
+   * look for the last '.' in mask and scan forward
+   */
+  if (0 == (s = strrchr(mask, '.'))) {
+    send_reply(sptr, ERR_NOTOPLEVEL, mask);
+    return;
+  }
+  while (*++s) {
+    if (*s == '.' || *s == '*' || *s == '?')
+       break;
+  }
+  if (*s == '*' || *s == '?') {
+    send_reply(sptr, ERR_WILDTOPLEVEL, mask);
+    return;
+  }
+  s = mask;
+  if ('@' == *++s) {
+    host_mask = 1;
+    ++s;
+  }
+
+  sendcmdto_match_butone(sptr, CMD_PRIVATE, s,
+                        IsServer(cli_from(sptr)) ? cli_from(sptr) : 0,
+                        host_mask ? MATCH_HOST : MATCH_SERVER,
+                        "%s :%s", mask, text);
+}
+
+/** Relay a masked notice from a local user.
+ * Sends an error response if there is no top-level domain label in \a
+ * mask, or if that TLD contains a wildcard.
+ * @param[in] sptr Client that originated the message.
+ * @param[in] mask Target mask for the message.
+ * @param[in] text %Message to relay.
+ */
+void relay_masked_notice(struct Client* sptr, const char* mask, const char* text)
+{
+  const char* s;
+  int   host_mask = 0;
+
+  assert(0 != sptr);
+  assert(0 != mask);
+  assert(0 != text);
+  /*
+   * look for the last '.' in mask and scan forward
+   */
+  if (0 == (s = strrchr(mask, '.'))) {
+    send_reply(sptr, ERR_NOTOPLEVEL, mask);
+    return;
+  }
+  while (*++s) {
+    if (*s == '.' || *s == '*' || *s == '?')
+       break;
+  }
+  if (*s == '*' || *s == '?') {
+    send_reply(sptr, ERR_WILDTOPLEVEL, mask);
+    return;
+  }
+  s = mask;
+  if ('@' == *++s) {
+    host_mask = 1;
+    ++s;
+  }
+
+  sendcmdto_match_butone(sptr, CMD_NOTICE, s,
+                        IsServer(cli_from(sptr)) ? cli_from(sptr) : 0,
+                        host_mask ? MATCH_HOST : MATCH_SERVER,
+                        "%s :%s", mask, text);
+}
+
+/** Relay a masked message that arrived from a server.
+ * @param[in] sptr Client that originated the message.
+ * @param[in] mask Target mask for the message.
+ * @param[in] text %Message to relay.
+ */
+void server_relay_masked_message(struct Client* sptr, const char* mask, const char* text)
+{
+  const char* s = mask;
+  int         host_mask = 0;
+  assert(0 != sptr);
+  assert(0 != mask);
+  assert(0 != text);
+
+  if ('@' == *++s) {
+    host_mask = 1;
+    ++s;
+  }
+  sendcmdto_match_butone(sptr, CMD_PRIVATE, s,
+                        IsServer(cli_from(sptr)) ? cli_from(sptr) : 0,
+                        host_mask ? MATCH_HOST : MATCH_SERVER,
+                        "%s :%s", mask, text);
+}
+
+/** Relay a masked notice that arrived from a server.
+ * @param[in] sptr Client that originated the message.
+ * @param[in] mask Target mask for the message.
+ * @param[in] text %Message to relay.
+ */
+void server_relay_masked_notice(struct Client* sptr, const char* mask, const char* text)
+{
+  const char* s = mask;
+  int         host_mask = 0;
+  assert(0 != sptr);
+  assert(0 != mask);
+  assert(0 != text);
+
+  if ('@' == *++s) {
+    host_mask = 1;
+    ++s;
+  }
+  sendcmdto_match_butone(sptr, CMD_NOTICE, s,
+                        IsServer(cli_from(sptr)) ? cli_from(sptr) : 0,
+                        host_mask ? MATCH_HOST : MATCH_SERVER,
+                        "%s :%s", mask, text);
+}
+
diff --git a/ircd/ircd_reply.c b/ircd/ircd_reply.c
new file mode 100644 (file)
index 0000000..796fa1d
--- /dev/null
@@ -0,0 +1,118 @@
+/*
+ * IRC - Internet Relay Chat, ircd/m_proto.c
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ *                    University of Oulu, Computing Center
+ *
+ * See file AUTHORS in IRC package for additional names of
+ * the programmers.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+/** @file
+ * @brief Implementation of functions to send common replies to users.
+ * @version $Id: ircd_reply.c 1762 2007-02-04 04:18:31Z entrope $
+ */
+#include "config.h"
+
+#include "ircd_reply.h"
+#include "client.h"
+#include "ircd.h"
+#include "ircd_log.h"
+#include "ircd_snprintf.h"
+#include "msg.h"
+#include "msgq.h"
+#include "numeric.h"
+#include "s_conf.h"
+#include "s_debug.h"
+#include "send.h"
+
+/* #include <assert.h> -- Now using assert in ircd_log.h */
+#include <string.h>
+
+/** Report a protocol violation warning to anyone listening.  This can
+ * be easily used to clean up the last couple of parts of the code.
+ * @param[in] cptr Client that violated the protocol.
+ * @param[in] pattern Description of how the protocol was violated.
+ * @return Zero.
+ */
+int protocol_violation(struct Client* cptr, const char* pattern, ...)
+{
+  struct VarData vd;
+  char message[BUFSIZE];
+
+  assert(pattern);
+  assert(cptr);
+
+  vd.vd_format = pattern;
+  va_start(vd.vd_args, pattern);
+  ircd_snprintf(NULL, message, sizeof(message),
+                "Protocol Violation from %s: %v", cli_name(cptr), &vd);
+  va_end(vd.vd_args);
+
+  sendwallto_group_butone(&me, WALL_DESYNCH, NULL, "%s", message);
+  return 0;
+}
+
+/** Inform a client that they need to provide more parameters.
+ * @param[in] cptr Taciturn client.
+ * @param[in] cmd Command name.
+ * @return Zero.
+ */
+int need_more_params(struct Client* cptr, const char* cmd)
+{
+  send_reply(cptr, ERR_NEEDMOREPARAMS, cmd);
+  return 0;
+}
+
+/** Send a generic reply to a user.
+ * @param[in] to Client that wants a reply.
+ * @param[in] reply Numeric of message to send.
+ * @return Zero.
+ */
+int send_reply(struct Client *to, int reply, ...)
+{
+  struct VarData vd;
+  struct MsgBuf *mb;
+  const struct Numeric *num;
+
+  assert(0 != to);
+  assert(0 != reply);
+
+  num = get_error_numeric(reply & ~SND_EXPLICIT); /* get reply... */
+
+  va_start(vd.vd_args, reply);
+
+  if (reply & SND_EXPLICIT) /* get right pattern */
+    vd.vd_format = (const char *) va_arg(vd.vd_args, char *);
+  else
+    vd.vd_format = num->format;
+
+  assert(0 != vd.vd_format);
+
+  /* build buffer */
+  mb = msgq_make(cli_from(to), "%:#C %s %C %v", &me, num->str, to, &vd);
+
+  va_end(vd.vd_args);
+
+  /* send it to the user */
+  send_buffer(to, mb, 0);
+
+  msgq_clean(mb);
+
+  return 0; /* convenience return */
+}
+
+
+
diff --git a/ircd/ircd_res.c b/ircd/ircd_res.c
new file mode 100644 (file)
index 0000000..266596f
--- /dev/null
@@ -0,0 +1,952 @@
+/*
+ * A rewrite of Darren Reed's original res.c As there is nothing
+ * left of Darren's original code, this is now licensed by the hybrid group.
+ * (Well, some of the function names are the same, and bits of the structs..)
+ * You can use it where it is useful, free even. Buy us a beer and stuff.
+ *
+ * The authors takes no responsibility for any damage or loss
+ * of property which results from the use of this software.
+ *
+ * July 1999 - Rewrote a bunch of stuff here. Change hostent builder code,
+ *     added callbacks and reference counting of returned hostents.
+ *     --Bleep (Thomas Helvey <tomh@inxpress.net>)
+ *
+ * This was all needlessly complicated for irc. Simplified. No more hostent
+ * All we really care about is the IP -> hostname mappings. Thats all.
+ *
+ * Apr 28, 2003 --cryogen and Dianora
+ */
+/** @file
+ * @brief IRC resolver functions.
+ * @version $Id: ircd_res.c 1764 2007-02-25 15:41:49Z entrope $
+ */
+
+#include "client.h"
+#include "ircd_alloc.h"
+#include "ircd_log.h"
+#include "ircd_osdep.h"
+#include "ircd_reply.h"
+#include "ircd_string.h"
+#include "ircd_snprintf.h"
+#include "ircd.h"
+#include "numeric.h"
+#include "fileio.h" /* for fbopen / fbclose / fbputs */
+#include "random.h"
+#include "s_bsd.h"
+#include "s_debug.h"
+#include "s_stats.h"
+#include "send.h"
+#include "sys.h"
+#include "res.h"
+#include "ircd_reslib.h"
+
+/* #include <assert.h> -- Now using assert in ircd_log.h */
+#include <string.h>
+#include <sys/time.h>
+#include <sys/socket.h>
+#include <time.h>
+
+#if (CHAR_BIT != 8)
+#error this code needs to be able to address individual octets 
+#endif
+
+/** IPv4 resolver UDP socket. */
+static struct Socket res_socket_v4;
+/** IPv6 resolver UDP socket. */
+static struct Socket res_socket_v6;
+/** Next DNS lookup timeout. */
+static struct Timer res_timeout;
+/** Local address for IPv4 DNS lookups. */
+struct irc_sockaddr VirtualHost_dns_v4;
+/** Local address for IPv6 DNS lookups. */
+struct irc_sockaddr VirtualHost_dns_v6;
+/** Check for whether the resolver has been initialized yet. */
+#define resolver_started() (request_list.next != NULL)
+
+/** Maximum DNS packet length.
+ * RFC says 512, but we add extra for expanded names.
+ */
+#define MAXPACKET      1024
+#define AR_TTL         600   /**< TTL in seconds for dns cache entries */
+
+/* RFC 1104/1105 wasn't very helpful about what these fields
+ * should be named, so for now, we'll just name them this way.
+ * we probably should look at what named calls them or something.
+ */
+/** Size of TYPE field of a DNS RR header. */
+#define TYPE_SIZE         (size_t)2
+/** Size of CLASS field of a DNS RR header. */
+#define CLASS_SIZE        (size_t)2
+/** Size of TTL field of a DNS RR header. */
+#define TTL_SIZE          (size_t)4
+/** Size of RDLENGTH field of a DNS RR header. */
+#define RDLENGTH_SIZE     (size_t)2
+/** Size of fixed-format part of a DNS RR header. */
+#define ANSWER_FIXED_SIZE (TYPE_SIZE + CLASS_SIZE + TTL_SIZE + RDLENGTH_SIZE)
+
+/** Current request state. */
+typedef enum
+{
+  REQ_IDLE,  /**< We're doing not much at all. */
+  REQ_PTR,   /**< Looking up a PTR. */
+  REQ_A,     /**< Looking up an A, possibly because AAAA failed. */
+  REQ_AAAA,  /**< Looking up an AAAA. */
+  REQ_CNAME, /**< We got a CNAME in response, we better get a real answer next. */
+  REQ_INT    /**< ip6.arpa failed, falling back to ip6.int. */
+} request_state;
+
+/** Doubly linked list node. */
+struct dlink
+{
+    struct dlink *prev; /**< Previous element in list. */
+    struct dlink *next; /**< Next element in list. */
+};
+
+/** A single resolver request.
+ * (Do not be fooled by the "list" in the name.)
+ */
+struct reslist
+{
+  struct dlink node;       /**< Doubly linked list node. */
+  int id;                  /**< Request ID (from request header). */
+  int sent;                /**< Number of requests sent. */
+  request_state state;     /**< State the resolver machine is in. */
+  char type;               /**< Current request type. */
+  char retries;            /**< Retry counter. */
+  char sends;              /**< Number of sends (>1 means resent). */
+  char resend;             /**< Send flag; 0 == don't resend. */
+  time_t sentat;           /**< Timestamp we last sent this request. */
+  time_t timeout;          /**< When this request times out. */
+  struct irc_in_addr addr; /**< Address for this request. */
+  char *name;              /**< Hostname for this request. */
+  dns_callback_f callback; /**< Callback function on completion. */
+  void *callback_ctx;      /**< Context pointer for callback. */
+};
+
+/** Base of request list. */
+static struct dlink request_list;
+
+static void rem_request(struct reslist *request);
+static struct reslist *make_request(dns_callback_f callback, void *ctx);
+static void do_query_name(dns_callback_f callback, void *ctx,
+                          const char* name, struct reslist *request, int);
+static void do_query_number(dns_callback_f callback, void *ctx,
+                            const struct irc_in_addr *,
+                            struct reslist *request);
+static void query_name(const char *name, int query_class, int query_type,
+                       struct reslist *request);
+static int send_res_msg(const char *buf, int len, int count);
+static void resend_query(struct reslist *request);
+static int proc_answer(struct reslist *request, HEADER *header, char *, char *);
+static struct reslist *find_id(int id);
+static void res_readreply(struct Event *ev);
+static void timeout_resolver(struct Event *notused);
+
+extern struct irc_sockaddr irc_nsaddr_list[IRCD_MAXNS];
+extern int irc_nscount;
+extern char irc_domain[HOSTLEN];
+
+/** Prepare the resolver library to (optionally) accept a list of
+ * DNS servers through add_dns_server().
+ */
+void clear_nameservers(void)
+{
+  irc_nscount = 0;
+  memset(&VirtualHost_dns_v4, 0, sizeof(VirtualHost_dns_v4));
+  memset(&VirtualHost_dns_v6, 0, sizeof(VirtualHost_dns_v6));
+}
+
+/** Check whether \a inp is a nameserver we use.
+ * @param[in] inp Nameserver address.
+ * @return Non-zero if we trust \a inp; zero if not.
+ */
+static int
+res_ourserver(const struct irc_sockaddr *inp)
+{
+  int ns;
+
+  for (ns = 0;  ns < irc_nscount;  ns++)
+    if (!irc_in_addr_cmp(&inp->addr, &irc_nsaddr_list[ns].addr)
+        && inp->port == irc_nsaddr_list[ns].port)
+      return 1;
+
+  return(0);
+}
+
+/** Start (or re-start) resolver.
+ * This means read resolv.conf, initialize the list of pending
+ * requests, open the resolver socket and initialize its timeout.
+ */
+void
+restart_resolver(void)
+{
+  int need_v4;
+  int need_v6;
+  int ns;
+
+  irc_res_init();
+
+  if (!request_list.next)
+    request_list.next = request_list.prev = &request_list;
+
+  /* Check which address family (or families) our nameservers use. */
+  for (need_v4 = need_v6 = ns = 0; ns < irc_nscount; ns++)
+  {
+    if (irc_in_addr_is_ipv4(&irc_nsaddr_list[ns].addr))
+      need_v4 = 1;
+    else
+      need_v6 = 1;
+  }
+
+  /* If we need an IPv4 socket, and don't have one, open it. */
+  if (need_v4 && !s_active(&res_socket_v4))
+  {
+    int fd = os_socket(&VirtualHost_dns_v4, SOCK_DGRAM, "Resolver UDPv4 socket", AF_INET);
+    if (fd >= 0)
+      socket_add(&res_socket_v4, res_readreply, NULL,
+                 SS_DATAGRAM, SOCK_EVENT_READABLE, fd);
+  }
+
+#ifdef AF_INET6
+  /* If we need an IPv6 socket, and don't have one, open it. */
+  if (need_v6 && !s_active(&res_socket_v6))
+  {
+    int fd = os_socket(&VirtualHost_dns_v6, SOCK_DGRAM, "Resolver UDPv6 socket", AF_INET6);
+    if (fd >= 0)
+      socket_add(&res_socket_v6, res_readreply, NULL,
+                 SS_DATAGRAM, SOCK_EVENT_READABLE, fd);
+  }
+#endif
+
+  if (s_active(&res_socket_v4) || s_active(&res_socket_v6))
+    timer_init(&res_timeout);
+}
+
+/** Append local domain to hostname if needed.
+ * If \a hname does not contain any '.'s, append #irc_domain to it.
+ * @param[in,out] hname Hostname to check.
+ * @param[in] size Length of \a hname buffer.
+ */
+void
+add_local_domain(char* hname, size_t size)
+{
+  /* try to fix up unqualified names 
+   */
+  if (strchr(hname, '.') == NULL)
+  {
+    if (irc_domain[0])
+    {
+      size_t len = strlen(hname);
+
+      if ((strlen(irc_domain) + len + 2) < size)
+      {
+        hname[len++] = '.';
+        strcpy(hname + len, irc_domain);
+      }
+    }
+  }
+}
+
+/** Add a node to a doubly linked list.
+ * @param[in,out] node Node to add to list.
+ * @param[in,out] next Add \a node before this one.
+ */
+static void
+add_dlink(struct dlink *node, struct dlink *next)
+{
+    node->prev = next->prev;
+    node->next = next;
+    node->prev->next = node;
+    node->next->prev = node;
+}
+
+/** Remove a request from the list and free it.
+ * @param[in] request Node to free.
+ */
+static void
+rem_request(struct reslist *request)
+{
+  /* remove from dlist */
+  request->node.prev->next = request->node.next;
+  request->node.next->prev = request->node.prev;
+  /* free memory */
+  MyFree(request->name);
+  MyFree(request);
+}
+
+/** Create a DNS request record for the server.
+ * @param[in] query Callback information for caller.
+ * @return Newly allocated and linked-in reslist.
+ */
+static struct reslist *
+make_request(dns_callback_f callback, void *ctx)
+{
+  struct reslist *request;
+
+  if (!resolver_started())
+    restart_resolver();
+
+  request = (struct reslist *)MyMalloc(sizeof(struct reslist));
+  memset(request, 0, sizeof(struct reslist));
+
+  request->state   = REQ_IDLE;
+  request->sentat  = CurrentTime;
+  request->retries = feature_int(FEAT_IRCD_RES_RETRIES);
+  request->resend  = 1;
+  request->timeout = feature_int(FEAT_IRCD_RES_TIMEOUT);
+  memset(&request->addr, 0, sizeof(request->addr));
+  request->callback = callback;
+  request->callback_ctx = ctx;
+
+  add_dlink(&request->node, &request_list);
+  return(request);
+}
+
+/** Make sure that a timeout event will happen by the given time.
+ * @param[in] when Latest time for timeout to run.
+ */
+static void
+check_resolver_timeout(time_t when)
+{
+  if (when > CurrentTime + AR_TTL)
+    when = CurrentTime + AR_TTL;
+  /* TODO after 2.10.12: Rewrite the timer API because there should be
+   * no need for clients to know this kind of implementation detail. */
+  if (when > t_expire(&res_timeout))
+    /* do nothing */;
+  else if (t_onqueue(&res_timeout) && !(res_timeout.t_header.gh_flags & GEN_MARKED))
+    timer_chg(&res_timeout, TT_ABSOLUTE, when);
+  else
+    timer_add(&res_timeout, timeout_resolver, NULL, TT_ABSOLUTE, when);
+}
+
+/** Drop pending DNS lookups which have timed out.
+ * @param[in] ev Timer event data (ignored).
+ */
+static void
+timeout_resolver(struct Event *ev)
+{
+  struct dlink *ptr, *next_ptr;
+  struct reslist *request;
+  time_t next_time = 0;
+  time_t timeout   = 0;
+
+  if (ev_type(ev) != ET_EXPIRE)
+    return;
+
+  for (ptr = request_list.next; ptr != &request_list; ptr = next_ptr)
+  {
+    next_ptr = ptr->next;
+    request = (struct reslist*)ptr;
+    timeout = request->sentat + request->timeout;
+
+    if (CurrentTime >= timeout)
+    {
+      if (--request->retries <= 0)
+      {
+        Debug((DEBUG_DNS, "Request %p out of retries; destroying", request));
+        (*request->callback)(request->callback_ctx, NULL, NULL);
+        rem_request(request);
+        continue;
+      }
+      else
+      {
+        request->sentat = CurrentTime;
+        request->timeout += request->timeout;
+        resend_query(request);
+      }
+    }
+
+    if ((next_time == 0) || timeout < next_time)
+    {
+      next_time = timeout;
+    }
+  }
+
+  if (next_time <= CurrentTime)
+    next_time = CurrentTime + AR_TTL;
+  check_resolver_timeout(next_time);
+}
+
+/** Drop queries that are associated with a particular pointer.
+ * This is used to clean up lookups for clients or conf blocks
+ * that went away.
+ * @param[in] vptr User callback pointer to search for.
+ */
+void
+delete_resolver_queries(const void *vptr)
+{
+  struct dlink *ptr, *next_ptr;
+  struct reslist *request;
+
+  if (request_list.next) {
+    for (ptr = request_list.next; ptr != &request_list; ptr = next_ptr)
+    {
+      next_ptr = ptr->next;
+      request = (struct reslist*)ptr;
+      if (vptr == request->callback_ctx) {
+        Debug((DEBUG_DNS, "Removing request %p with vptr %p", request, vptr));
+        rem_request(request);
+      }
+    }
+  }
+}
+
+/** Send a message to all of our nameservers.
+ * @param[in] msg Message to send.
+ * @param[in] len Length of message.
+ * @param[in] rcount Maximum number of servers to ask.
+ * @return Number of servers that were successfully asked.
+ */
+static int
+send_res_msg(const char *msg, int len, int rcount)
+{
+  int i;
+  int sent = 0;
+  int max_queries = IRCD_MIN(irc_nscount, rcount);
+
+  /* RES_PRIMARY option is not implemented
+   * if (res.options & RES_PRIMARY || 0 == max_queries)
+   */
+  if (max_queries == 0)
+    max_queries = 1;
+
+  for (i = 0; i < max_queries; i++) {
+    int fd = irc_in_addr_is_ipv4(&irc_nsaddr_list[i].addr) ? s_fd(&res_socket_v4) : s_fd(&res_socket_v6);
+    if (os_sendto_nonb(fd, msg, len, NULL, 0, &irc_nsaddr_list[i]) == IO_SUCCESS)
+      ++sent;
+  }
+
+  return(sent);
+}
+
+/** Find a DNS request by ID.
+ * @param[in] id Identifier to find.
+ * @return Matching DNS request, or NULL if none are found.
+ */
+static struct reslist *
+find_id(int id)
+{
+  struct dlink *ptr;
+  struct reslist *request;
+
+  for (ptr = request_list.next; ptr != &request_list; ptr = ptr->next)
+  {
+    request = (struct reslist*)ptr;
+
+    if (request->id == id) {
+      Debug((DEBUG_DNS, "find_id(%d) -> %p", id, request));
+      return(request);
+    }
+  }
+
+  Debug((DEBUG_DNS, "find_id(%d) -> NULL", id));
+  return(NULL);
+}
+
+/** Try to look up address for a hostname, trying IPv6 (T_AAAA) first.
+ * @param[in] name Hostname to look up.
+ * @param[in] query Callback information.
+ */
+void
+gethost_byname(const char *name, dns_callback_f callback, void *ctx)
+{
+  do_query_name(callback, ctx, name, NULL, T_AAAA);
+}
+
+/** Try to look up hostname for an address.
+ * @param[in] addr Address to look up.
+ * @param[in] query Callback information.
+ */
+void
+gethost_byaddr(const struct irc_in_addr *addr, dns_callback_f callback, void *ctx)
+{
+  do_query_number(callback, ctx, addr, NULL);
+}
+
+/** Send a query to look up the address for a name.
+ * @param[in] query Callback information.
+ * @param[in] name Hostname to look up.
+ * @param[in] request DNS lookup structure (may be NULL).
+ * @param[in] type Preferred request type.
+ */
+static void
+do_query_name(dns_callback_f callback, void *ctx, const char *name,
+              struct reslist *request, int type)
+{
+  char host_name[HOSTLEN + 1];
+
+  ircd_strncpy(host_name, name, HOSTLEN);
+  add_local_domain(host_name, HOSTLEN);
+
+  if (request == NULL)
+  {
+    request       = make_request(callback, ctx);
+    DupString(request->name, host_name);
+#ifdef IPV6
+    if (type != T_A)
+      request->state = REQ_AAAA;
+    else
+#endif
+    request->state = REQ_A;
+  }
+
+  request->type = type;
+  Debug((DEBUG_DNS, "Requesting DNS %s %s as %p", (request->state == REQ_AAAA ? "AAAA" : "A"), host_name, request));
+  query_name(host_name, C_IN, type, request);
+}
+
+/** Send a query to look up the name for an address.
+ * @param[in] query Callback information.
+ * @param[in] addr Address to look up.
+ * @param[in] request DNS lookup structure (may be NULL).
+ */
+static void
+do_query_number(dns_callback_f callback, void *ctx, const struct irc_in_addr *addr,
+                struct reslist *request)
+{
+  char ipbuf[128];
+  const unsigned char *cp;
+
+  if (irc_in_addr_is_ipv4(addr))
+  {
+    cp = (const unsigned char*)&addr->in6_16[6];
+    ircd_snprintf(NULL, ipbuf, sizeof(ipbuf), "%u.%u.%u.%u.in-addr.arpa.",
+                  (unsigned int)(cp[3]), (unsigned int)(cp[2]),
+                  (unsigned int)(cp[1]), (unsigned int)(cp[0]));
+  }
+  else
+  {
+    const char *intarpa;
+
+    if (request != NULL && request->state == REQ_INT)
+      intarpa = "int";
+    else
+      intarpa = "arpa";
+
+    cp = (const unsigned char *)&addr->in6_16[0];
+    ircd_snprintf(NULL, ipbuf, sizeof(ipbuf),
+                  "%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x."
+                  "%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.ip6.%s.",
+                  (unsigned int)(cp[15]&0xf), (unsigned int)(cp[15]>>4),
+                  (unsigned int)(cp[14]&0xf), (unsigned int)(cp[14]>>4),
+                  (unsigned int)(cp[13]&0xf), (unsigned int)(cp[13]>>4),
+                  (unsigned int)(cp[12]&0xf), (unsigned int)(cp[12]>>4),
+                  (unsigned int)(cp[11]&0xf), (unsigned int)(cp[11]>>4),
+                  (unsigned int)(cp[10]&0xf), (unsigned int)(cp[10]>>4),
+                  (unsigned int)(cp[9]&0xf), (unsigned int)(cp[9]>>4),
+                  (unsigned int)(cp[8]&0xf), (unsigned int)(cp[8]>>4),
+                  (unsigned int)(cp[7]&0xf), (unsigned int)(cp[7]>>4),
+                  (unsigned int)(cp[6]&0xf), (unsigned int)(cp[6]>>4),
+                  (unsigned int)(cp[5]&0xf), (unsigned int)(cp[5]>>4),
+                  (unsigned int)(cp[4]&0xf), (unsigned int)(cp[4]>>4),
+                  (unsigned int)(cp[3]&0xf), (unsigned int)(cp[3]>>4),
+                  (unsigned int)(cp[2]&0xf), (unsigned int)(cp[2]>>4),
+                  (unsigned int)(cp[1]&0xf), (unsigned int)(cp[1]>>4),
+                  (unsigned int)(cp[0]&0xf), (unsigned int)(cp[0]>>4), intarpa);
+  }
+  if (request == NULL)
+  {
+    request       = make_request(callback, ctx);
+    request->state= REQ_PTR;
+    request->type = T_PTR;
+    memcpy(&request->addr, addr, sizeof(request->addr));
+    request->name = (char *)MyMalloc(HOSTLEN + 1);
+  }
+  Debug((DEBUG_DNS, "Requesting DNS PTR %s as %p", ipbuf, request));
+  query_name(ipbuf, C_IN, T_PTR, request);
+}
+
+/** Generate a query based on class, type and name.
+ * @param[in] name Domain name to look up.
+ * @param[in] query_class Query class (see RFC 1035).
+ * @param[in] type Query type (see RFC 1035).
+ * @param[in] request DNS request structure.
+ */
+static void
+query_name(const char *name, int query_class, int type,
+           struct reslist *request)
+{
+  char buf[MAXPACKET];
+  int request_len = 0;
+
+  memset(buf, 0, sizeof(buf));
+
+  if ((request_len = irc_res_mkquery(name, query_class, type,
+      (unsigned char *)buf, sizeof(buf))) > 0)
+  {
+    HEADER *header = (HEADER *)buf;
+
+    /*
+     * generate an unique id
+     * NOTE: we don't have to worry about converting this to and from
+     * network byte order, the nameserver does not interpret this value
+     * and returns it unchanged
+     */
+    do
+    {
+      header->id = (header->id + ircrandom()) & 0xffff;
+    } while (find_id(header->id));
+    request->id = header->id;
+    ++request->sends;
+
+    request->sent += send_res_msg(buf, request_len, request->sends);
+    check_resolver_timeout(request->sentat + request->timeout);
+  }
+}
+
+/** Send a failed DNS lookup request again.
+ * @param[in] request Request to resend.
+ */
+static void
+resend_query(struct reslist *request)
+{
+  if (request->resend == 0)
+    return;
+
+  switch(request->type)
+  {
+    case T_PTR:
+      do_query_number(NULL, NULL, &request->addr, request);
+      break;
+    case T_A:
+      do_query_name(NULL, NULL, request->name, request, request->type);
+      break;
+    case T_AAAA:
+      /* didn't work, try A */
+      if (request->state == REQ_AAAA)
+        do_query_name(NULL, NULL, request->name, request, T_A);
+    default:
+      break;
+  }
+}
+
+/** Process the answer for a lookup request.
+ * @param[in] request DNS request that got an answer.
+ * @param[in] header Header of DNS response.
+ * @param[in] buf DNS response body.
+ * @param[in] eob Pointer to end of DNS response.
+ * @return Number of answers read from \a buf.
+ */
+static int
+proc_answer(struct reslist *request, HEADER* header, char* buf, char* eob)
+{
+  char hostbuf[HOSTLEN + 100]; /* working buffer */
+  unsigned char *current;      /* current position in buf */
+  int query_class;             /* answer class */
+  int type;                    /* answer type */
+  int n;                       /* temp count */
+  int rd_length;
+
+  current = (unsigned char *)buf + sizeof(HEADER);
+
+  for (; header->qdcount > 0; --header->qdcount)
+  {
+    if ((n = irc_dn_skipname(current, (unsigned char *)eob)) < 0)
+      break;
+
+    current += (size_t) n + QFIXEDSZ;
+  }
+
+  /*
+   * process each answer sent to us blech.
+   */
+  while (header->ancount > 0 && (char *)current < eob)
+  {
+    header->ancount--;
+
+    n = irc_dn_expand((unsigned char *)buf, (unsigned char *)eob, current,
+        hostbuf, sizeof(hostbuf));
+
+    if (n < 0)
+    {
+      /*
+       * broken message
+       */
+      return(0);
+    }
+    else if (n == 0)
+    {
+      /*
+       * no more answers left
+       */
+      return(0);
+    }
+
+    hostbuf[HOSTLEN] = '\0';
+
+    /* With Address arithmetic you have to be very anal
+     * this code was not working on alpha due to that
+     * (spotted by rodder/jailbird/dianora)
+     */
+    current += (size_t) n;
+
+    if (!(((char *)current + ANSWER_FIXED_SIZE) < eob))
+      break;
+
+    type = irc_ns_get16(current);
+    current += TYPE_SIZE;
+
+    query_class = irc_ns_get16(current);
+    current += CLASS_SIZE;
+
+    current += TTL_SIZE;
+
+    rd_length = irc_ns_get16(current);
+    current += RDLENGTH_SIZE;
+
+    /*
+     * Wait to set request->type until we verify this structure
+     */
+    switch (type)
+    {
+      case T_A:
+        if (request->type != T_A)
+          return(0);
+
+        /*
+         * check for invalid rd_length or too many addresses
+         */
+        if (rd_length != sizeof(struct in_addr))
+          return(0);
+        memset(&request->addr, 0, sizeof(request->addr));
+        memcpy(&request->addr.in6_16[6], current, sizeof(struct in_addr));
+        return(1);
+        break;
+      case T_AAAA:
+        if (request->type != T_AAAA)
+          return(0);
+        if (rd_length != sizeof(struct irc_in_addr))
+          return(0);
+        memcpy(&request->addr, current, sizeof(struct irc_in_addr));
+        return(1);
+        break;
+      case T_PTR:
+        if (request->type != T_PTR)
+          return(0);
+        n = irc_dn_expand((unsigned char *)buf, (unsigned char *)eob,
+            current, hostbuf, sizeof(hostbuf));
+        if (n < 0)
+          return(0); /* broken message */
+        else if (n == 0)
+          return(0); /* no more answers left */
+
+        ircd_strncpy(request->name, hostbuf, HOSTLEN);
+
+        return(1);
+        break;
+      case T_CNAME: /* first check we already haven't started looking
+                       into a cname */
+        if (request->state == REQ_CNAME)
+        {
+          n = irc_dn_expand((unsigned char *)buf, (unsigned char *)eob,
+                            current, hostbuf, sizeof(hostbuf));
+
+          if (n < 0)
+            return(0);
+          return(1);
+        }
+
+        request->state = REQ_CNAME;
+        current += rd_length;
+        break;
+
+      default:
+        /* XXX I'd rather just throw away the entire bogus thing
+         * but its possible its just a broken nameserver with still
+         * valid answers. But lets do some rudimentary logging for now...
+         */
+        log_write(LS_RESOLVER, L_ERROR, 0, "irc_res.c bogus type %d", type);
+
+        if ((char*)current + rd_length >= (char*)current)
+          current += rd_length;
+        else
+          return(0);
+
+        break;
+    }
+  }
+
+  return(1);
+}
+
+/** Read a DNS reply from the nameserver and process it.
+ * @param[in] ev I/O activity event for resolver socket.
+ */
+static void
+res_readreply(struct Event *ev)
+{
+  struct irc_sockaddr lsin;
+  struct Socket *sock;
+  char buf[sizeof(HEADER) + MAXPACKET];
+  HEADER *header;
+  struct reslist *request = NULL;
+  unsigned int rc;
+  int answer_count;
+
+  assert((ev_socket(ev) == &res_socket_v4) || (ev_socket(ev) == &res_socket_v6));
+  sock = ev_socket(ev);
+
+  if (IO_SUCCESS != os_recvfrom_nonb(s_fd(sock), buf, sizeof(buf), &rc, &lsin)
+      || (rc <= sizeof(HEADER)))
+    return;
+
+  /*
+   * check against possibly fake replies
+   */
+  if (!res_ourserver(&lsin))
+    return;
+
+  /*
+   * convert DNS reply reader from Network byte order to CPU byte order.
+   */
+  header = (HEADER *)buf;
+  header->ancount = ntohs(header->ancount);
+  header->qdcount = ntohs(header->qdcount);
+  header->nscount = ntohs(header->nscount);
+  header->arcount = ntohs(header->arcount);
+
+  /*
+   * response for an id which we have already received an answer for
+   * just ignore this response.
+   */
+  if (0 == (request = find_id(header->id)))
+    return;
+
+  if ((header->rcode != NO_ERRORS) || (header->ancount == 0))
+  {
+    if (SERVFAIL == header->rcode || NXDOMAIN == header->rcode)
+    {
+        /*
+         * If a bad error was returned, we stop here and don't send
+         * send any more (no retries granted).
+         */
+        Debug((DEBUG_DNS, "Request %p has bad response (state %d type %d rcode %d)", request, request->state, request->type, header->rcode));
+        (*request->callback)(request->callback_ctx, NULL, NULL);
+       rem_request(request);
+    }
+    else
+    {
+      /*
+       * If we haven't already tried this, and we're looking up AAAA, try A
+       * now
+       */
+
+      if (request->state == REQ_AAAA && request->type == T_AAAA)
+      {
+        request->timeout += feature_int(FEAT_IRCD_RES_TIMEOUT);
+        resend_query(request);
+      }
+      else if (request->type == T_PTR && request->state != REQ_INT &&
+               !irc_in_addr_is_ipv4(&request->addr))
+      {
+        request->state = REQ_INT;
+        request->timeout += feature_int(FEAT_IRCD_RES_TIMEOUT);
+        resend_query(request);
+      }
+    }
+
+    return;
+  }
+  /*
+   * If this fails there was an error decoding the received packet,
+   * try it again and hope it works the next time.
+   */
+  answer_count = proc_answer(request, header, buf, buf + rc);
+
+  if (answer_count)
+  {
+    if (request->type == T_PTR)
+    {
+      if (request->name == NULL)
+      {
+        /*
+         * got a PTR response with no name, something bogus is happening
+         * don't bother trying again, the client address doesn't resolve
+         */
+        Debug((DEBUG_DNS, "Request %p PTR had empty name", request));
+        (*request->callback)(request->callback_ctx, NULL, NULL);
+        rem_request(request);
+        return;
+      }
+
+      /*
+       * Lookup the 'authoritative' name that we were given for the
+       * ip#.
+       */
+#ifdef IPV6
+      if (!irc_in_addr_is_ipv4(&request->addr))
+        do_query_name(request->callback, request->callback_ctx, request->name, NULL, T_AAAA);
+      else
+#endif
+      do_query_name(request->callback, request->callback_ctx, request->name, NULL, T_A);
+      Debug((DEBUG_DNS, "Request %p switching to forward resolution", request));
+      rem_request(request);
+    }
+    else
+    {
+      /*
+       * got a name and address response, client resolved
+       */
+      (*request->callback)(request->callback_ctx, &request->addr, request->name);
+      Debug((DEBUG_DNS, "Request %p got forward resolution", request));
+      rem_request(request);
+    }
+  }
+  else if (!request->sent)
+  {
+    /* XXX - we got a response for a query we didn't send with a valid id?
+     * this should never happen, bail here and leave the client unresolved
+     */
+    assert(0);
+
+    /* XXX don't leak it */
+    Debug((DEBUG_DNS, "Request %p was unexpected(!)", request));
+    rem_request(request);
+  }
+}
+
+/** Statistics callback to list DNS servers.
+ * @param[in] source_p Client requesting statistics.
+ * @param[in] sd Stats descriptor for request (ignored).
+ * @param[in] param Extra parameter from user (ignored).
+ */
+void
+report_dns_servers(struct Client *source_p, const struct StatDesc *sd, char *param)
+{
+  int i;
+  char ipaddr[128];
+
+  for (i = 0; i < irc_nscount; i++)
+  {
+    ircd_ntoa_r(ipaddr, &irc_nsaddr_list[i].addr);
+    send_reply(source_p, RPL_STATSALINE, ipaddr);
+  }
+}
+
+/** Report memory usage to a client.
+ * @param[in] sptr Client requesting information.
+ * @return Total memory used by pending requests.
+ */
+size_t
+cres_mem(struct Client* sptr)
+{
+  struct dlink *dlink;
+  struct reslist *request;
+  size_t request_mem   = 0;
+  int    request_count = 0;
+
+  if (request_list.next) {
+    for (dlink = request_list.next; dlink != &request_list; dlink = dlink->next) {
+      request = (struct reslist*)dlink;
+      request_mem += sizeof(*request);
+      if (request->name)
+        request_mem += strlen(request->name) + 1;
+      ++request_count;
+    }
+  }
+
+  send_reply(sptr, SND_EXPLICIT | RPL_STATSDEBUG,
+            ":Resolver: requests %d(%d)", request_count, request_mem);
+  return request_mem;
+}
diff --git a/ircd/ircd_reslib.c b/ircd/ircd_reslib.c
new file mode 100644 (file)
index 0000000..871f5f6
--- /dev/null
@@ -0,0 +1,1204 @@
+/*
+ * Copyright (c) 1985, 1993
+ *    The 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. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. 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.
+ */
+
+/*
+ * Portions Copyright (c) 1993 by Digital Equipment Corporation.
+ * 
+ * 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, and that
+ * the name of Digital Equipment Corporation not be used in advertising or
+ * publicity pertaining to distribution of the document or software without
+ * specific, written prior permission.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS.   IN NO EVENT SHALL DIGITAL EQUIPMENT
+ * CORPORATION 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.
+ */
+
+/*
+ * Portions Copyright (c) 1996-1999 by Internet Software Consortium.
+ *
+ * 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 INTERNET SOFTWARE CONSORTIUM DISCLAIMS
+ * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
+ * CONSORTIUM 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.
+ */
+
+/* Original copyright ISC as above. 
+ * Code modified specifically for ircd use from the following original files
+ * in bind ...
+ *
+ * res_comp.c
+ * ns_name.c
+ * ns_netint.c
+ * res_init.c
+ * 
+ * - Dianora
+ */
+
+#include "ircd.h"
+#include "res.h"
+#include "ircd_reslib.h"
+#include "ircd_defs.h"
+#include "fileio.h"
+#include "ircd_string.h"
+
+#include <ctype.h>
+#include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#define NS_TYPE_ELT             0x40 /**< EDNS0 extended label type */
+#define DNS_LABELTYPE_BITSTRING 0x41 /**< Bitstring label */
+#define MAXLINE 128 /**< Maximum line length for resolv.conf */
+
+/** @file
+ * @brief DNS resolver library functions.
+ * @version $Id: ircd_reslib.c 1764 2007-02-25 15:41:49Z entrope $
+ */
+
+/** Array of nameserver addresses. */
+struct irc_sockaddr irc_nsaddr_list[IRCD_MAXNS];
+/** Number of nameservers in #irc_nsaddr_list. */
+int irc_nscount;
+/** Local domain to use as a search suffix. */
+char irc_domain[HOSTLEN + 1];
+
+/** Maps hex digits to their values, or -1 for other characters. */
+static const char digitvalue[256] = {
+  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*16*/
+  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*32*/
+  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*48*/
+   0,  1,  2,  3,  4,  5,  6,  7,  8,  9, -1, -1, -1, -1, -1, -1, /*64*/
+  -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*80*/
+  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*96*/
+  -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*112*/
+  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*128*/
+  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*256*/
+};
+
+static int parse_resvconf(void);
+
+/** Array of decimal digits, indexed by value. */
+static const char digits[] = "0123456789";
+static int labellen(const unsigned char *lp);
+static int special(int ch);
+static int printable(int ch);
+static int irc_decode_bitstring(const char **cpp, char *dn, const char *eom);
+static int irc_ns_name_compress(const char *src, unsigned char *dst, size_t dstsiz,
+    const unsigned char **dnptrs, const unsigned char **lastdnptr);
+static int irc_dn_find(const unsigned char *, const unsigned char *, const unsigned char * const *,
+                       const unsigned char * const *);
+static int irc_encode_bitsring(const char **, const char *, unsigned char **, unsigned char **,
+                               const char *);
+static int mklower(int ch);
+
+/** Initialize the resolver library.
+ * @return Zero on success, non-zero on failure.
+ */
+int
+irc_res_init(void)
+{
+  return (irc_nscount == 0) ? parse_resvconf() : 0;
+}
+
+/** Read resolver configuration file for domain and nameserver lines.
+ * The "domain" line is used to overwrite #irc_domain.
+ * Addresses in "nameserver" lines are appended to #irc_nsaddr_list.
+ * @return Zero on success, non-zero on failure.
+ */
+static int
+parse_resvconf(void)
+{
+  char *p;
+  char *opt;
+  char *arg;
+  char input[MAXLINE];
+  FBFILE *file;
+
+  /* XXX "/etc/resolv.conf" should be from a define in setup.h perhaps
+   * for cygwin support etc. this hardcodes it to unix for now -db
+   */
+  if ((file = fbopen("/etc/resolv.conf", "r")) == NULL)
+    return(-1);
+
+  while (fbgets(input, MAXLINE, file) != NULL)
+  {
+    /* blow away any newline */
+    if ((p = strpbrk(input, "\r\n")) != NULL)
+      *p = '\0';
+
+    /* Ignore comment lines immediately */
+    if (*input == '#')
+      continue;
+
+    p = input;
+    /* skip until something that's not a space is seen */
+    while (IsSpace(*p))
+      p++;
+    /* if at this point, have a '\0' then continue */
+    if (*p == '\0')
+      continue;
+
+    /* skip until a space is found */
+    opt = input;
+    while (!IsSpace(*p))
+      if (*p++ == '\0')
+        continue;  /* no arguments?.. ignore this line */
+    /* blow away the space character */
+    *p++ = '\0';
+
+    /* skip these spaces that are before the argument */
+    while (IsSpace(*p))
+      p++;
+    /* Now arg should be right where p is pointing */
+    arg = p;
+    if ((p = strpbrk(arg, " \t")) != NULL)
+      *p = '\0';  /* take the first word */
+
+    if (strcasecmp(opt, "domain") == 0)
+      ircd_strncpy(irc_domain, arg, HOSTLEN);
+    else if (strcasecmp(opt, "nameserver") == 0)
+      add_nameserver(arg);
+  }
+
+  fbclose(file);
+  return(0);
+}
+
+/** Add a resolver to #irc_nsaddr_list.
+ * @param[in] arg Dotted quad or IPv6 text form of nameserver address.
+ */
+void
+add_nameserver(const char *arg)
+{
+  struct irc_sockaddr res;
+
+  /* Done max number of nameservers? */
+  if (irc_nscount >= IRCD_MAXNS)
+    return;
+
+  /* Failure converting from numeric string? */
+  if (!ircd_aton(&res.addr, arg))
+      return;
+  res.port = 53;
+  memcpy(&irc_nsaddr_list[irc_nscount], &res, sizeof(irc_nsaddr_list[irc_nscount]));
+  irc_nscount++;
+}
+
+/**
+ * Expand compressed domain name to full domain name.
+ * Like irc_ns_name_uncompress(), but checks for a well-formed result.
+ * @param[in] msg Pointer to the beginning of the message.
+ * @param[in] eom First location after the message.
+ * @param[in] src Pointer to where to starting decoding.
+ * @param[out] dst Output buffer.
+ * @param[in] dstsiz Number of bytes that can be written to \a dst.
+ * @return Number of bytes written to \a dst.
+ */
+int
+irc_dn_expand(const unsigned char *msg, const unsigned char *eom,
+              const unsigned char *src, char *dst, int dstsiz)
+{
+  int n = irc_ns_name_uncompress(msg, eom, src, dst, (size_t)dstsiz);
+
+  if (n > 0 && dst[0] == '.')
+    dst[0] = '\0';
+  return(n);
+}
+
+/**
+ * Expand compressed domain name to full domain name.
+ * @param[in] msg Pointer to the beginning of the message.
+ * @param[in] eom First location after the message.
+ * @param[in] src Pointer to where to starting decoding.
+ * @param[out] dst Output buffer.
+ * @param[in] dstsiz Number of bytes that can be written to \a dst.
+ * @return Number of bytes written to \a dst.
+ */
+int
+irc_ns_name_uncompress(const unsigned char *msg, const unsigned char *eom,
+                       const unsigned char *src, char *dst, size_t dstsiz)
+{
+  unsigned char tmp[NS_MAXCDNAME];
+  int n;
+
+  if ((n = irc_ns_name_unpack(msg, eom, src, tmp, sizeof tmp)) == -1)
+    return(-1);
+  if (irc_ns_name_ntop((char*)tmp, (char*)dst, dstsiz) == -1)
+    return(-1);
+  return(n);
+}
+
+/**
+ * Unpack compressed domain name to uncompressed form.
+ * @param[in] msg Pointer to the beginning of the message.
+ * @param[in] eom First location after the message.
+ * @param[in] src Pointer to where to starting decoding.
+ * @param[out] dst Output buffer.
+ * @param[in] dstsiz Number of bytes that can be written to \a dst.
+ * @return Number of bytes written to \a dst.
+ */
+int
+irc_ns_name_unpack(const unsigned char *msg, const unsigned char *eom,
+                   const unsigned char *src, unsigned char *dst,
+                   size_t dstsiz)
+{
+       const unsigned char *srcp, *dstlim;
+       unsigned char *dstp;
+       int n, len, checked, l;
+
+       len = -1;
+       checked = 0;
+       dstp = dst;
+       srcp = src;
+       dstlim = dst + dstsiz;
+       if (srcp < msg || srcp >= eom) {
+               errno = EMSGSIZE;
+               return (-1);
+       }
+       /* Fetch next label in domain name. */
+       while ((n = *srcp++) != 0) {
+               /* Check for indirection. */
+               switch (n & NS_CMPRSFLGS) {
+               case 0:
+               case NS_TYPE_ELT:
+                       /* Limit checks. */
+                       if ((l = labellen(srcp - 1)) < 0) {
+                               errno = EMSGSIZE;
+                               return(-1);
+                       }
+                       if (dstp + l + 1 >= dstlim || srcp + l >= eom) {
+                               errno = EMSGSIZE;
+                               return (-1);
+                       }
+                       checked += l + 1;
+                       *dstp++ = n;
+                       memcpy(dstp, srcp, l);
+                       dstp += l;
+                       srcp += l;
+                       break;
+
+               case NS_CMPRSFLGS:
+                       if (srcp >= eom) {
+                               errno = EMSGSIZE;
+                               return (-1);
+                       }
+                       if (len < 0)
+                               len = srcp - src + 1;
+                       srcp = msg + (((n & 0x3f) << 8) | (*srcp & 0xff));
+                       if (srcp < msg || srcp >= eom) {  /* Out of range. */
+                               errno = EMSGSIZE;
+                               return (-1);
+                       }
+                       checked += 2;
+                       /*
+                        * Check for loops in the compressed name;
+                        * if we've looked at the whole message,
+                        * there must be a loop.
+                        */
+                       if (checked >= eom - msg) {
+                               errno = EMSGSIZE;
+                               return (-1);
+                       }
+                       break;
+
+               default:
+                       errno = EMSGSIZE;
+                       return (-1);                    /* flag error */
+               }
+       }
+       *dstp = '\0';
+       if (len < 0)
+               len = srcp - src;
+       return (len);
+}
+
+/**
+ * Convert RFC1035 length-prefixed tag sequence to printable ASCII.
+ * @param[in] src Input tag sequence (effectively NUL terminated).
+ * @param[out] dst Buffer for uncompressed output.
+ * @param[in] dstsiz Number of bytes that can be written to \a dst.
+ * @return Number of bytes written to \a dst.
+ */
+int
+irc_ns_name_ntop(const char *src, char *dst, size_t dstsiz)
+{
+       const char *cp;
+       char *dn, *eom;
+       unsigned char c;
+       unsigned int n;
+       int l;
+
+       cp = src;
+       dn = dst;
+       eom = dst + dstsiz;
+
+       while ((n = *cp++) != 0) {
+               if ((n & NS_CMPRSFLGS) == NS_CMPRSFLGS) {
+                       /* Some kind of compression pointer. */
+                       errno = EMSGSIZE;
+                       return (-1);
+               }
+               if (dn != dst) {
+                       if (dn >= eom) {
+                               errno = EMSGSIZE;
+                               return (-1);
+                       }
+                       *dn++ = '.';
+               }
+               if ((l = labellen((const unsigned char*)(cp - 1))) < 0) {
+                       errno = EMSGSIZE; /* XXX */
+                       return(-1);
+               }
+               if (dn + l >= eom) {
+                       errno = EMSGSIZE;
+                       return (-1);
+               }
+               if ((n & NS_CMPRSFLGS) == NS_TYPE_ELT) {
+                       int m;
+
+                       if (n != DNS_LABELTYPE_BITSTRING) {
+                               /* XXX: labellen should reject this case */
+                               errno = EINVAL;
+                               return(-1);
+                       }
+                       if ((m = irc_decode_bitstring(&cp, dn, eom)) < 0)
+                       {
+                               errno = EMSGSIZE;
+                               return(-1);
+                       }
+                       dn += m; 
+                       continue;
+               }
+               for ((void)NULL; l > 0; l--) {
+                       c = *cp++;
+                       if (special(c)) {
+                               if (dn + 1 >= eom) {
+                                       errno = EMSGSIZE;
+                                       return (-1);
+                               }
+                               *dn++ = '\\';
+                               *dn++ = (char)c;
+                       } else if (!printable(c)) {
+                               if (dn + 3 >= eom) {
+                                       errno = EMSGSIZE;
+                                       return (-1);
+                               }
+                               *dn++ = '\\';
+                               *dn++ = digits[c / 100];
+                               *dn++ = digits[(c % 100) / 10];
+                               *dn++ = digits[c % 10];
+                       } else {
+                               if (dn >= eom) {
+                                       errno = EMSGSIZE;
+                                       return (-1);
+                               }
+                               *dn++ = (char)c;
+                       }
+               }
+       }
+       if (dn == dst) {
+               if (dn >= eom) {
+                       errno = EMSGSIZE;
+                       return (-1);
+               }
+               *dn++ = '.';
+       }
+       if (dn >= eom) {
+               errno = EMSGSIZE;
+               return (-1);
+       }
+       *dn++ = '\0';
+       return (dn - dst);
+}
+
+/** Pack domain name from presentation form into compressed format.
+ * @param[in] src Presentation form of name.
+ * @param[out] dst Output buffer.
+ * @param[in] dstsiz Number of bytes that can be written to \a dst.
+ * @param[in,out] dnptrs Array of previously seen labels.
+ * @param[in] lastdnptr End of \a dnptrs array.
+ * @return Number of bytes written to \a dst.
+ */
+int
+irc_dn_comp(const char *src, unsigned char *dst, int dstsiz,
+            unsigned char **dnptrs, unsigned char **lastdnptr)
+{
+  return(irc_ns_name_compress(src, dst, (size_t)dstsiz,
+                              (const unsigned char **)dnptrs,
+                              (const unsigned char **)lastdnptr));
+}
+
+/** Skip over a compressed domain name.
+ * @param[in] ptr Start of compressed name.
+ * @param[in] eom End of message.
+ * @return Length of the compressed name, or -1 on error.
+ */
+int
+irc_dn_skipname(const unsigned char *ptr, const unsigned char *eom) {
+  const unsigned char *saveptr = ptr;
+
+  if (irc_ns_name_skip(&ptr, eom) == -1)
+    return(-1);
+  return(ptr - saveptr);
+}
+
+/** Advance \a ptrptr to skip over the compressed name it points at.
+ * @param[in,out] ptrptr Pointer to the compressed name.
+ * @param[in] eom End of message.
+ * @return Zero on success; non-zero (with errno set) on failure.
+ */
+int
+irc_ns_name_skip(const unsigned char **ptrptr, const unsigned char *eom)
+{
+  const unsigned char *cp;
+  unsigned int n;
+  int l;
+
+  cp = *ptrptr;
+
+  while (cp < eom && (n = *cp++) != 0)
+  {
+    /* Check for indirection. */
+    switch (n & NS_CMPRSFLGS)
+    {
+      case 0: /* normal case, n == len */
+        cp += n;
+        continue;
+      case NS_TYPE_ELT: /* EDNS0 extended label */
+        if ((l = labellen(cp - 1)) < 0)
+        {
+          errno = EMSGSIZE; /* XXX */
+          return(-1);
+        }
+
+        cp += l;
+        continue;
+      case NS_CMPRSFLGS: /* indirection */
+        cp++;
+        break;
+      default: /* illegal type */
+        errno = EMSGSIZE;
+        return(-1);
+    }
+
+    break;
+  }
+
+  if (cp > eom)
+  {
+    errno = EMSGSIZE;
+    return (-1);
+  }
+
+  *ptrptr = cp;
+  return(0);
+}
+
+/** Read a 16-bit network-endian value from \a src.
+ * @param[in] src Input data buffer.
+ * @return Value retrieved from buffer.
+ */
+unsigned int
+irc_ns_get16(const unsigned char *src)
+{
+  unsigned int dst;
+
+  IRC_NS_GET16(dst, src);
+  return(dst);
+}
+
+/** Read a 32-bit network-endian value from \a src.
+ * @param[in] src Input data buffer.
+ * @return Value retrieved from buffer.
+ */
+unsigned long
+irc_ns_get32(const unsigned char *src)
+{
+  unsigned long dst;
+
+  IRC_NS_GET32(dst, src);
+  return(dst);
+}
+
+/** Write a 16-bit network-endian value to \a dst.
+ * @param[in] src Value to write.
+ * @param[out] dst Output buffer.
+ */
+void
+irc_ns_put16(unsigned int src, unsigned char *dst)
+{
+  IRC_NS_PUT16(src, dst);
+}
+
+/** Write a 32-bit network-endian value to \a dst.
+ * @param[in] src Value to write.
+ * @param[out] dst Output buffer.
+ */
+void
+irc_ns_put32(unsigned long src, unsigned char *dst)
+{
+  IRC_NS_PUT32(src, dst);
+}
+
+/* From ns_name.c */
+
+/** Indicate whether a character needs quoting.
+ * (What RFC does this come from?)
+ * @param[in] ch Character to check for specialness.
+ * @return Non-zero if the character should be quoted.
+ */
+static int
+special(int ch)
+{
+  switch (ch)
+  {
+    case 0x22: /* '"'  */
+    case 0x2E: /* '.'  */
+    case 0x3B: /* ';'  */
+    case 0x5C: /* '\\' */
+    case 0x28: /* '('  */
+    case 0x29: /* ')'  */
+    /* Special modifiers in zone files. */
+    case 0x40: /* '@'  */
+    case 0x24: /* '$'  */
+      return(1);
+    default:
+      return(0);
+  }
+}
+
+/** Calculate the length of a particular DNS label.
+ * @param[in] lp Start of label.
+ * @return Length of label, or -1 on error.
+ */
+static int
+labellen(const unsigned char *lp)
+{
+  int bitlen;
+  unsigned char l = *lp;
+
+  if ((l & NS_CMPRSFLGS) == NS_CMPRSFLGS)
+  {
+    /* should be avoided by the caller */
+    return(-1);
+  }
+
+  if ((l & NS_CMPRSFLGS) == NS_TYPE_ELT)
+  {
+    if (l == DNS_LABELTYPE_BITSTRING)
+    {
+      if ((bitlen = *(lp + 1)) == 0)
+        bitlen = 256;
+      return((bitlen + 7 ) / 8 + 1);
+    }
+
+    return(-1); /* unknown ELT */
+  }
+
+  return(l);
+}
+
+
+/** Indicate whether a character is printable.
+ * @param[in] ch Character to check for printability.
+ * @return Non-zero if the character is printable; zero if it is not.
+ */
+static int
+printable(int ch)
+{
+  return(ch > 0x20 && ch < 0x7f);
+}
+
+/** Decode a bitstring label from DNS.
+ * @param[in,out] cpp Pointer to start of label.
+ * @param[in,out] dn Output buffer.
+ * @param[in] eom End of message.
+ */
+static int
+irc_decode_bitstring(const char **cpp, char *dn, const char *eom)
+{
+        const char *cp = *cpp;
+        char *beg = dn, tc;
+        int b, blen, plen;
+
+        if ((blen = (*cp & 0xff)) == 0)
+                blen = 256;
+        plen = (blen + 3) / 4;
+        plen += sizeof("\\[x/]") + (blen > 99 ? 3 : (blen > 9) ? 2 : 1);
+        if (dn + plen >= eom)
+                return(-1);
+
+        cp++;
+        dn += sprintf(dn, "\\[x");
+        for (b = blen; b > 7; b -= 8, cp++)
+                dn += sprintf(dn, "%02x", *cp & 0xff);
+        if (b > 4) {
+                tc = *cp++;
+                dn += sprintf(dn, "%02x", tc & (0xff << (8 - b)));
+        } else if (b > 0) {
+                tc = *cp++;
+               dn += sprintf(dn, "%1x",
+                               ((tc >> 4) & 0x0f) & (0x0f << (4 - b)));
+        }
+        dn += sprintf(dn, "/%d]", blen);
+
+        *cpp = cp;
+        return(dn - beg);
+}
+
+/** Convert an ASCII name string into an encoded domain name.
+ * This function enforces per-label and total name lengths.
+ * @param[in] src ASCII name string.
+ * @param[out] dst Destination buffer.
+ * @param[in] dstsiz Number of bytes that can be written to \a dst.
+ * @return -1 on failure, 0 if \a src was not fully qualified, 1 if \a
+ * src was fully qualified.
+ */
+int
+irc_ns_name_pton(const char *src, unsigned char *dst, size_t dstsiz)
+{
+  unsigned char *label, *bp, *eom;
+  char *cp;
+  int c, n, escaped, e = 0;
+
+  escaped = 0;
+  bp = dst;
+  eom = dst + dstsiz;
+  label = bp++;
+
+
+  while ((c = *src++) != 0) {
+    if (escaped) {
+      if (c == '[') { /* start a bit string label */
+        if ((cp = strchr(src, ']')) == NULL) {
+          errno = EINVAL; /* ??? */
+          return(-1);
+        }
+        if ((e = irc_encode_bitsring(&src,
+               cp + 2,
+               &label,
+               &bp,
+               (const char *)eom))
+            != 0) {
+          errno = e;
+          return(-1);
+        }
+        escaped = 0;
+        label = bp++;
+        if ((c = *src++) == 0)
+          goto done;
+        else if (c != '.') {
+          errno = EINVAL;
+          return(-1);
+        }
+        continue;
+      }
+      else if ((cp = strchr(digits, c)) != NULL) {
+        n = (cp - digits) * 100;
+        if ((c = *src++) == 0 ||
+            (cp = strchr(digits, c)) == NULL) {
+          errno = EMSGSIZE;
+          return (-1);
+        }
+        n += (cp - digits) * 10;
+        if ((c = *src++) == 0 ||
+            (cp = strchr(digits, c)) == NULL) {
+          errno = EMSGSIZE;
+          return (-1);
+        }
+        n += (cp - digits);
+        if (n > 255) {
+          errno = EMSGSIZE;
+          return (-1);
+        }
+        c = n;
+      }
+      escaped = 0;
+    } else if (c == '\\') {
+      escaped = 1;
+      continue;
+    } else if (c == '.') {
+      c = (bp - label - 1);
+      if ((c & NS_CMPRSFLGS) != 0) {  /* Label too big. */
+        errno = EMSGSIZE;
+        return (-1);
+      }
+      if (label >= eom) {
+        errno = EMSGSIZE;
+        return (-1);
+      }
+      *label = c;
+      /* Fully qualified ? */
+      if (*src == '\0') {
+        if (c != 0) {
+          if (bp >= eom) {
+            errno = EMSGSIZE;
+            return (-1);
+          }
+          *bp++ = '\0';
+        }
+        if ((bp - dst) > NS_MAXCDNAME) {
+          errno = EMSGSIZE;
+          return (-1);
+        }
+        return (1);
+      }
+      if (c == 0 || *src == '.') {
+        errno = EMSGSIZE;
+        return (-1);
+      }
+      label = bp++;
+      continue;
+    }
+    if (bp >= eom) {
+      errno = EMSGSIZE;
+      return (-1);
+    }
+    *bp++ = (unsigned char)c;
+  }
+  c = (bp - label - 1);
+  if ((c & NS_CMPRSFLGS) != 0) {    /* Label too big. */
+    errno = EMSGSIZE;
+    return (-1);
+  }
+  done:
+  if (label >= eom) {
+    errno = EMSGSIZE;
+    return (-1);
+  }
+  *label = c;
+  if (c != 0) {
+    if (bp >= eom) {
+      errno = EMSGSIZE;
+      return (-1);
+    }
+    *bp++ = 0;
+  }
+
+  if ((bp - dst) > NS_MAXCDNAME)
+  { /* src too big */
+    errno = EMSGSIZE;
+    return (-1);
+  }
+
+  return (0);
+}
+
+/** Compress a domain name.
+ * @param[in] src List of length-prefixed labels.
+ * @param[out] dst Output buffer.
+ * @param[in] dstsiz Number of bytes that can be written to \a dst.
+ * @param[in,out] dnptrs Array of pointers to previously compressed names.
+ * @param[in] lastdnptr End of \a dnptrs array.
+ * @return Number of bytes written to \a dst.
+ */
+int
+irc_ns_name_pack(const unsigned char *src, unsigned char *dst, int dstsiz,
+                 const unsigned char **dnptrs, const unsigned char **lastdnptr)
+{
+  unsigned char *dstp;
+  const unsigned char **cpp, **lpp, *eob, *msg;
+  const unsigned char *srcp;
+  int n, l, first = 1;
+
+  srcp = src;
+  dstp = dst;
+  eob = dstp + dstsiz;
+  lpp = cpp = NULL;
+  if (dnptrs != NULL) {
+    if ((msg = *dnptrs++) != NULL) {
+      for (cpp = dnptrs; *cpp != NULL; cpp++)
+        (void)NULL;
+      lpp = cpp;  /* end of list to search */
+    }
+  } else
+    msg = NULL;
+
+  /* make sure the domain we are about to add is legal */
+  l = 0;
+  do {
+    int l0;
+
+    n = *srcp;
+    if ((n & NS_CMPRSFLGS) == NS_CMPRSFLGS) {
+      errno = EMSGSIZE;
+      return (-1);
+    }
+    if ((l0 = labellen(srcp)) < 0) {
+      errno = EINVAL;
+      return(-1);
+    }
+    l += l0 + 1;
+    if (l > NS_MAXCDNAME) {
+      errno = EMSGSIZE;
+      return (-1);
+    }
+    srcp += l0 + 1;
+  } while (n != 0);
+
+  /* from here on we need to reset compression pointer array on error */
+  srcp = src;
+  do {
+    /* Look to see if we can use pointers. */
+    n = *srcp;
+    if (n != 0 && msg != NULL) {
+      l = irc_dn_find(srcp, msg, (const unsigned char * const *)dnptrs,
+            (const unsigned char * const *)lpp);
+      if (l >= 0) {
+        if (dstp + 1 >= eob) {
+          goto cleanup;
+        }
+        *dstp++ = (l >> 8) | NS_CMPRSFLGS;
+        *dstp++ = l % 256;
+        return (dstp - dst);
+      }
+      /* Not found, save it. */
+      if (lastdnptr != NULL && cpp < lastdnptr - 1 &&
+          (dstp - msg) < 0x4000 && first) {
+        *cpp++ = dstp;
+        *cpp = NULL;
+        first = 0;
+      }
+    }
+    /* copy label to buffer */
+    if ((n & NS_CMPRSFLGS) == NS_CMPRSFLGS) {
+      /* Should not happen. */
+      goto cleanup;
+    }
+    n = labellen(srcp);
+    if (dstp + 1 + n >= eob) {
+      goto cleanup;
+    }
+    memcpy(dstp, srcp, n + 1);
+    srcp += n + 1;
+    dstp += n + 1;
+  } while (n != 0);
+
+  if (dstp > eob) {
+cleanup:
+    if (msg != NULL)
+      *lpp = NULL;
+    errno = EMSGSIZE;
+    return (-1);
+  }
+  return(dstp - dst);
+}
+
+/** Encode and compress an ASCII domain name.
+ * @param[in] src ASCII domain name.
+ * @param[out] dst Output buffer.
+ * @param[in] dstsiz Number of bytes that can be written to \a dst.
+ * @param[in] dnptrs Array of previously compressed names.
+ * @param[in] lastdnptr End of \a dnptrs array.
+ */
+static int
+irc_ns_name_compress(const char *src, unsigned char *dst, size_t dstsiz,
+                     const unsigned char **dnptrs, const unsigned char **lastdnptr)
+{
+  unsigned char tmp[NS_MAXCDNAME];
+
+  if (irc_ns_name_pton(src, tmp, sizeof tmp) == -1)
+    return(-1);
+  return(irc_ns_name_pack(tmp, dst, dstsiz, dnptrs, lastdnptr));
+}
+
+/** Encode a bitstring label.
+ * @param[in,out] bp Input buffer pointer.
+ * @param[in] end End of input buffer.
+ * @param[out] labelp Pointer to output label.
+ * @param[out] dst Output buffer.
+ * @param[out] eom End of output buffer.
+ */
+static int
+irc_encode_bitsring(const char **bp, const char *end, unsigned char **labelp,
+                    unsigned char **dst, const char *eom)
+{
+  int afterslash = 0;
+  const char *cp = *bp;
+  char *tp, c;
+  const char *beg_blen;
+  char *end_blen = NULL;
+  int value = 0, count = 0, tbcount = 0, blen = 0;
+
+  beg_blen = end_blen = NULL;
+
+  /* a bitstring must contain at least 2 characters */
+  if (end - cp < 2)
+    return(EINVAL);
+
+  /* XXX: currently, only hex strings are supported */
+  if (*cp++ != 'x')
+    return(EINVAL);
+  if (!isxdigit((*cp) & 0xff)) /* reject '\[x/BLEN]' */
+    return(EINVAL);
+
+  for (tp = (char*)(*dst + 1); cp < end && tp < eom; cp++) {
+    switch((c = *cp)) {
+    case ']': /* end of the bitstring */
+      if (afterslash) {
+        if (beg_blen == NULL)
+          return(EINVAL);
+        blen = (int)strtol(beg_blen, &end_blen, 10);
+        if (*end_blen != ']')
+          return(EINVAL);
+      }
+      if (count)
+        *tp++ = ((value << 4) & 0xff);
+      cp++; /* skip ']' */
+      goto done;
+    case '/':
+      afterslash = 1;
+      break;
+    default:
+      if (afterslash) {
+        if (!isdigit(c&0xff))
+          return(EINVAL);
+        if (beg_blen == NULL) {
+
+          if (c == '0') {
+            /* blen never begins with 0 */
+            return(EINVAL);
+          }
+          beg_blen = cp;
+        }
+      } else {
+        if (!isxdigit(c&0xff))
+          return(EINVAL);
+        value <<= 4;
+        value += digitvalue[(int)c];
+        count += 4;
+        tbcount += 4;
+        if (tbcount > 256)
+          return(EINVAL);
+        if (count == 8) {
+          *tp++ = value;
+          count = 0;
+        }
+      }
+      break;
+    }
+  }
+  done:
+  if (cp >= end || tp >= eom)
+    return(EMSGSIZE);
+
+  /*
+   * bit length validation:
+   * If a <length> is present, the number of digits in the <bit-data>
+   * MUST be just sufficient to contain the number of bits specified
+   * by the <length>. If there are insignificant bits in a final
+   * hexadecimal or octal digit, they MUST be zero.
+   * RFC 2673, Section 3.2.
+   */
+  if (blen > 0) {
+    int traillen;
+
+    if (((blen + 3) & ~3) != tbcount)
+      return(EINVAL);
+    traillen = tbcount - blen; /* between 0 and 3 */
+    if (((value << (8 - traillen)) & 0xff) != 0)
+      return(EINVAL);
+  }
+  else
+    blen = tbcount;
+  if (blen == 256)
+    blen = 0;
+
+  /* encode the type and the significant bit fields */
+  **labelp = DNS_LABELTYPE_BITSTRING;
+  **dst = blen;
+
+  *bp = cp;
+  *dst = (unsigned char*)tp;
+
+  return(0);
+}
+
+/** Find a name in an array of compressed name.
+ * @param[in] domain Name to search for.
+ * @param[in] msg Start of DNS message.
+ * @param[in] dnptrs Start of compressed name array.
+ * @param[in] lastdnptr End of compressed name array.
+ * @return Non-negative offset from \a msg, or -1 if not found.
+ */
+static int
+irc_dn_find(const unsigned char *domain, const unsigned char *msg,
+            const unsigned char * const *dnptrs,
+            const unsigned char * const *lastdnptr)
+{
+  const unsigned char *dn, *cp, *sp;
+  const unsigned char * const *cpp;
+  unsigned int n;
+
+  for (cpp = dnptrs; cpp < lastdnptr; cpp++)
+  {
+    sp = *cpp;
+    /*
+     * terminate search on:
+     * root label
+     * compression pointer
+     * unusable offset
+     */
+    while (*sp != 0 && (*sp & NS_CMPRSFLGS) == 0 &&
+           (sp - msg) < 0x4000) {
+      dn = domain;
+      cp = sp;
+      while ((n = *cp++) != 0) {
+        /*
+         * check for indirection
+         */
+        switch (n & NS_CMPRSFLGS) {
+        case 0:   /* normal case, n == len */
+          n = labellen(cp - 1); /* XXX */
+
+          if (n != *dn++)
+            goto next;
+
+          for ((void)NULL; n > 0; n--)
+            if (mklower(*dn++) !=
+                mklower(*cp++))
+              goto next;
+          /* Is next root for both ? */
+          if (*dn == '\0' && *cp == '\0')
+            return (sp - msg);
+          if (*dn)
+            continue;
+          goto next;
+        case NS_CMPRSFLGS:  /* indirection */
+          cp = msg + (((n & 0x3f) << 8) | *cp);
+          break;
+
+        default:  /* illegal type */
+          errno = EMSGSIZE;
+          return (-1);
+        }
+      }
+ next: ;
+      sp += *sp + 1;
+    }
+  }
+  errno = ENOENT;
+  return (-1);
+}
+
+/** Convert a character to lowercase, assuming ASCII encoded English.
+ * @param[in] ch Character to convert.
+ * @return Lower-case version of \a ch.
+ */
+static int
+mklower(int ch)
+{
+  if (ch >= 0x41 && ch <= 0x5A)
+    return(ch + 0x20);
+
+  return(ch);
+}
+
+/* From resolv/mkquery.c */
+
+/** Form a query for \a dname in \a buf.
+ * @param[in] dname Domain name to look up.
+ * @param[in] class Query class to set in header.
+ * @param[in] type Query type to set in header.
+ * @param[out] buf Output buffer for query.
+ * @param[in] buflen Number of bytes that can be written to \a buf.
+ * @return Length of message written to \a buf, or -1 on error.
+ */
+int
+irc_res_mkquery(
+            const char *dname,         /* domain name */
+            int class, int type,       /* class and type of query */
+            unsigned char *buf,                /* buffer to put query */
+            int buflen)                /* size of buffer */
+{
+       HEADER *hp;
+       unsigned char *cp;
+       int n;
+       unsigned char *dnptrs[20], **dpp, **lastdnptr;
+
+       /*
+        * Initialize header fields.
+        */
+       if ((buf == NULL) || (buflen < HFIXEDSZ))
+               return (-1);
+       memset(buf, 0, HFIXEDSZ);
+       hp = (HEADER *) buf;
+
+       hp->id = 0;
+       hp->opcode = QUERY;
+       hp->rd = 1;             /* recurse */
+       hp->rcode = NO_ERRORS;
+       cp = buf + HFIXEDSZ;
+       buflen -= HFIXEDSZ;
+       dpp = dnptrs;
+       *dpp++ = buf;
+       *dpp++ = NULL;
+       lastdnptr = dnptrs + sizeof dnptrs / sizeof dnptrs[0];
+
+       if ((buflen -= QFIXEDSZ) < 0)
+         return (-1);
+       if ((n = irc_dn_comp(dname, cp, buflen, dnptrs, lastdnptr)) < 0)
+         return (-1);
+
+       cp += n;
+       buflen -= n;
+       IRC_NS_PUT16(type, cp);
+       IRC_NS_PUT16(class, cp);
+       hp->qdcount = htons(1);
+
+       return (cp - buf);
+}
diff --git a/ircd/ircd_signal.c b/ircd/ircd_signal.c
new file mode 100644 (file)
index 0000000..2b02fb0
--- /dev/null
@@ -0,0 +1,267 @@
+/*
+ * IRC - Internet Relay Chat, ircd/ircd_signal.c
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ *                    University of Oulu, Computing Center
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+/** @file
+ * @brief Signal handlers for ircu.
+ * @version $Id: ircd_signal.c 1633 2006-03-25 03:46:56Z entrope $
+ */
+#include "config.h"
+
+#include "ircd.h"
+#include "ircd_alloc.h"
+#include "ircd_events.h"
+#include "ircd_log.h"
+#include "ircd_signal.h"
+#include "s_conf.h"
+
+/* #include <assert.h> -- Now using assert in ircd_log.h */
+#include <signal.h>
+#include <string.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+/** Records a function to be called when a child process terminates. */
+struct ChildRecord {
+  struct ChildRecord *next;
+  SigChldCallBack call;
+  void *datum;
+  pid_t cpid;
+};
+
+/** Counts various types of signals that we receive. */
+static struct tag_SignalCounter {
+  unsigned int alrm; /**< Received SIGALRM count. */
+  unsigned int hup;  /**< Received SIGHUP count. */
+  unsigned int chld; /**< Received SIGCHLD count. */
+} SignalCounter;
+
+/** Event generator for SIGHUP. */
+static struct Signal sig_hup;
+/** Event generator for SIGINT. */
+static struct Signal sig_int;
+/** Event generator for SIGTERM. */
+static struct Signal sig_term;
+/** Event generator for SIGCHLD. */
+static struct Signal sig_chld;
+/** List of active child process callback requests. */
+static struct ChildRecord *children;
+/** List of inactive (free) child records. */
+static struct ChildRecord *crec_freelist;
+
+/* Make sure we have a definition for SIGCHLD. */
+#if !defined(SIGCHLD)
+# define SIGCHLD SIGCLD
+#endif
+
+/** Signal handler for SIGALRM.
+ * @param[in] sig Signal number (ignored).
+ */
+static void sigalrm_handler(int sig)
+{
+  ++SignalCounter.alrm;
+}
+
+/** Signal callback for SIGTERM.
+ * @param[in] ev Signal event descriptor.
+ */
+static void sigterm_callback(struct Event* ev)
+{
+  assert(0 != ev_signal(ev));
+  assert(ET_SIGNAL == ev_type(ev));
+  assert(SIGTERM == sig_signal(ev_signal(ev)));
+  assert(SIGTERM == ev_data(ev));
+
+  server_die("received signal SIGTERM");
+}
+
+/** Signal callback for SIGHUP.
+ * @param[in] ev Signal event descriptor.
+ */
+static void sighup_callback(struct Event* ev)
+{
+  assert(0 != ev_signal(ev));
+  assert(ET_SIGNAL == ev_type(ev));
+  assert(SIGHUP == sig_signal(ev_signal(ev)));
+  assert(SIGHUP == ev_data(ev));
+
+  ++SignalCounter.hup;
+  rehash(&me, 1);
+}
+
+/** Signal callback for SIGINT.
+ * @param[in] ev Signal event descriptor.
+ */
+static void sigint_callback(struct Event* ev)
+{
+  assert(0 != ev_signal(ev));
+  assert(ET_SIGNAL == ev_type(ev));
+  assert(SIGINT == sig_signal(ev_signal(ev)));
+  assert(SIGINT == ev_data(ev));
+
+  server_restart("caught signal: SIGINT");
+}
+
+/** Allocate a child callback record.
+ * @return Newly allocated callback record.
+ */
+static struct ChildRecord *alloc_crec(void)
+{
+  struct ChildRecord *crec;
+
+  if (crec_freelist)
+  {
+    crec = crec_freelist;
+    crec_freelist = crec->next;
+  }
+  else
+  {
+    crec = MyCalloc(1, sizeof(*crec));
+  }
+
+  memset(crec, 0, sizeof(*crec));
+  crec->next = NULL;
+  return crec;
+}
+
+/** Release \a crec, which is after \a prev.
+ * @param[in] crec Child process callback record to release.
+ */
+static void release_crec(struct ChildRecord *crec)
+{
+  memset(crec, 0, sizeof(*crec));
+  crec->next = crec_freelist;
+  crec_freelist = crec;
+}
+
+/** Register a function to be called when a child process terminates.
+ * @param[in] child Child process ID.
+ * @param[in] call Function to call when process \a child terminates.
+ * @param[in] datum Additional data parameter to pass to \a call.
+ */
+void register_child(pid_t child, SigChldCallBack call, void *datum)
+{
+  struct ChildRecord *crec;
+
+  crec = alloc_crec();
+  /* Link into #children list. */
+  crec->next = children;
+  children = crec;
+  /* Fill in user fields. */
+  crec->call = call;
+  crec->datum = datum;
+  crec->cpid = child;
+}
+
+/** Unregister all callbacks for a child process, optionally calling
+ * them first.
+ * @param[in] child Child process ID to unregister.
+ * @param[in] do_call If non-zero, make the callbacks.
+ * @param[in] status If \a do_call is non-zero, the child's exit status.
+ */
+static void do_unregister_child(pid_t child, int do_call, int status)
+{
+  struct ChildRecord *crec = children;
+  struct ChildRecord *prev = NULL;
+
+  while (crec != NULL)
+  {
+    if (crec->cpid == child)
+    {
+      if (do_call)
+        crec->call(child, crec->datum, status);
+
+      if (prev)
+        prev->next = crec->next;
+      else
+        children = crec->next;
+
+      release_crec(crec);
+    }
+    else
+      prev = crec;
+    crec = prev ? prev->next : children;
+  }
+}
+
+/** Unregister all callbacks for a child process.
+ * @param[in] child Child process ID to unregister.
+ */
+void unregister_child(pid_t child)
+{
+  do_unregister_child(child, 0, 0);
+}
+
+/** Signal handler for SIGCHLD.
+ * @param[in] ev Signal event descriptor.
+ */
+static void sigchld_callback(struct Event *ev)
+{
+  pid_t cpid;
+  int status;
+
+  ++SignalCounter.chld;
+  do {
+    cpid = waitpid(-1, &status, WNOHANG);
+    if (cpid > 0)
+      do_unregister_child(cpid, 1, status);
+  } while (cpid > 0);
+}
+
+/** Register all necessary signal handlers. */
+void setup_signals(void)
+{
+  struct sigaction act;
+
+  act.sa_handler = SIG_IGN;
+  act.sa_flags = 0;
+  sigemptyset(&act.sa_mask);
+  sigaddset(&act.sa_mask, SIGPIPE);
+  sigaddset(&act.sa_mask, SIGALRM);
+#ifdef  SIGWINCH
+  sigaddset(&act.sa_mask, SIGWINCH);
+  sigaction(SIGWINCH, &act, 0);
+#endif
+  sigaction(SIGPIPE, &act, 0);
+
+  act.sa_handler = sigalrm_handler;
+  sigaction(SIGALRM, &act, 0);
+
+  signal_add(&sig_hup, sighup_callback, 0, SIGHUP);
+  signal_add(&sig_int, sigint_callback, 0, SIGINT);
+  signal_add(&sig_term, sigterm_callback, 0, SIGTERM);
+  signal_add(&sig_chld, sigchld_callback, 0, SIGCHLD);
+
+  /*
+   * At least on Apollo sr10.1 it seems continuing system calls
+   * after signal is the default. The following 'siginterrupt'
+   * should change that default to interrupting calls.
+   */
+  siginterrupt(SIGALRM, 1);
+}
+
+/** Kill and clean up all child processes. */
+void reap_children(void)
+{
+  /* Send SIGTERM to all children in process group.  Sleep for a
+   * second to let them exit before we try to clean them up.
+   */
+  kill(0, SIGTERM);
+  sleep(1);
+  sigchld_callback(NULL);
+}
diff --git a/ircd/ircd_snprintf.c b/ircd/ircd_snprintf.c
new file mode 100644 (file)
index 0000000..6f2f246
--- /dev/null
@@ -0,0 +1,2169 @@
+/*
+ * IRC - Internet Relay Chat, ircd/ircd_snprintf.c
+ * Copyright (C) 2000 Kevin L. Mitchell <klmitch@mit.edu>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+/** @file
+ * @brief IRC-specific printf() clone implementation.
+ * @version $Id: ircd_snprintf.c 1642 2006-04-07 03:56:22Z entrope $
+ */
+#include "config.h"
+
+#include "client.h"
+#include "channel.h"
+#include "ircd_log.h"
+#include "ircd_snprintf.h"
+#include "struct.h"
+
+/* #include <assert.h> -- Now using assert in ircd_log.h */
+#include <errno.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+/* Inhibit complaints when we use GCC extensions */
+#if defined(__GNUC__) && SIZEOF_LONG_LONG
+# define EXTENSION __extension__
+#else
+/** Fallback (empty) definition of EXTENSION. */
+# define EXTENSION
+#endif
+
+/* Find the largest type */
+#if SIZEOF_LONG_LONG
+EXTENSION typedef long long _large_t;
+EXTENSION typedef unsigned long long _ularge_t;
+# define SIZEOF__LARGE_T SIZEOF_LONG_LONG
+/* Oh, if long long happens to be the size of void *, set _pointer_t, too */
+# if SIZEOF_LONG_LONG == SIZEOF_VOID_P
+typedef _ularge_t _pointer_t;
+#  define HAVE_POINTER_T
+# endif
+#else
+/** Fallback definition of the largest integer type. */
+typedef long _large_t;
+/** Fallback definition of the largest unsigned integer type. */
+typedef unsigned long _ularge_t;
+/** Fallback definition of SIZEOF__LARGE_T. */
+# define SIZEOF__LARGE_T SIZEOF_LONG
+#endif
+
+/* Select something for _pointer_t */
+#ifndef HAVE_POINTER_T
+# if SIZEOF_LONG == SIZEOF_VOID_P
+/** Unsigned integer type large enough to hold a pointer. */
+typedef unsigned long _pointer_t;
+# elif SIZEOF_INT == SIZEOF_VOID_P
+typedef unsigned int _pointer_t;
+# else
+#  error Unable to find a suitable type for _pointer_t
+# endif
+#endif /* HAVE_POINTER_T */
+
+/** rough length sufficient to hold an octal number, since those can be large */
+#define INTBUF_LEN (SIZEOF__LARGE_T * 3)
+
+/** Return minimum of \a i1 and \a i2. */
+#define SNP_MIN(i1, i2)        ((i1) < (i2) ? (i1) : (i2))
+/** Return maximum of \a i1 and \a i2. */
+#define SNP_MAX(i1, i2)        ((i1) > (i2) ? (i1) : (i2))
+/** Indicate total number of bytes "pseudo-output" in buffer. */
+#define TOTAL(buf_p)   ((buf_p)->buf_loc + \
+                        SNP_MAX((buf_p)->buf_overflow, (buf_p)->overflow))
+
+#define WIDTH_MAX      999     /**< keep from overflowing width */
+
+/** data about the output buffer */
+struct BufData {
+  char        *buf;            /**< pointer to buffer */
+  size_t       buf_size;       /**< maximum size of buffer */
+  size_t       buf_overflow;   /**< how much buffer has been overflowed */
+  size_t       buf_loc;        /**< where we are in the buffer */
+  short                limit;          /**< max # of chars to convert */
+  size_t       overflow;       /**< how much we overflowed the limit */
+};
+
+/** initializer for BufData */
+#define BUFDATA_INIT   { 0, 0, 0, 0, 0, 0 }
+
+/** data about format fields */
+struct FieldData {
+  unsigned int flags;          /**< flags describing argument */
+  short                base;           /**< base for integer conversions */
+  short                width;          /**< width of field */
+  short                prec;           /**< precision of field */
+  union {
+    _ularge_t  v_int;          /**< an integer value */
+    long double        v_float;        /**< a floating point value -- NOT SUPPORTED */
+    void       *v_ptr;         /**< a pointer value */
+  }            value;          /**< value of a field */
+};
+
+/** initializer for FieldData */
+#define FIELDDATA_INIT { 0, 0, 0, 0, { 0 } }
+
+/* Specifier flags */
+#define FLAG_MINUS     0x00000001      /**< found a '-' flag */
+#define FLAG_PLUS      0x00000002      /**< found a '+' flag */
+#define FLAG_SPACE     0x00000004      /**< found a ' ' flag */
+#define FLAG_ALT       0x00000008      /**< found a '#' flag */
+#define FLAG_ZERO      0x00000010      /**< found a '0' flag */
+#define FLAG_COLON     0x00000020      /**< found a ':' flag */
+
+#define FLAG_RESERVED1 0x00000040      /**< reserved for future expansion */
+#define FLAG_RESERVED0 0x00000080      /**< reserved for future expansion */
+
+/* integer types */
+#define TYPE_CHAR      0x00000100      /**< number is a char */
+#define TYPE_SHORT     0x00000200      /**< number is a short */
+#define TYPE_LONG      0x00000400      /**< number is a long */
+#define TYPE_QUAD      0x00000800      /**< number is a quad */
+
+/* special integer types */
+#define TYPE_INTMAX    0x00001000      /**< number is an intmax_t */
+#define TYPE_PTRDIFF   0x00002000      /**< number is a ptrdiff_t */
+#define TYPE_SIZE      0x00004000      /**< number is a size_t */
+#define TYPE_TIME      0x00008000      /**< number is a time_t */
+#define TYPE_POINTER   0x00010000      /**< number is a pointer_t */
+
+/* floating point types */
+#define TYPE_LONGDOUBLE        0x00020000      /**< number is a long double */
+
+#define TYPE_RESERVED1 0x00040000      /**< reserved for future expansion */
+#define TYPE_RESERVED0 0x00080000      /**< reserved for future expansion */
+
+/** Mask to get just the type data */
+#define TYPE_MASK      (TYPE_CHAR | TYPE_SHORT | TYPE_LONG | TYPE_QUAD | \
+                        TYPE_INTMAX | TYPE_PTRDIFF | TYPE_SIZE | TYPE_TIME | \
+                        TYPE_POINTER | TYPE_LONGDOUBLE)
+
+/* type of argument to extract */
+#define ARG_INT                0x00100000      /**< argument is an integer */
+#define ARG_FLOAT      0x00200000      /**< argument is a float */
+#define ARG_PTR                0x00300000      /**< argument is a pointer */
+
+#define ARG_RESERVED11 0x00400000      /**< reserved for future expansion */
+#define ARG_RESERVED10 0x00500000      /**< reserved for future expansion */
+#define ARG_RESERVED9  0x00600000      /**< reserved for future expansion */
+#define ARG_RESERVED8  0x00700000      /**< reserved for future expansion */
+#define ARG_RESERVED7  0x00800000      /**< reserved for future expansion */
+#define ARG_RESERVED6  0x00900000      /**< reserved for future expansion */
+#define ARG_RESERVED5  0x00a00000      /**< reserved for future expansion */
+#define ARG_RESERVED4  0x00b00000      /**< reserved for future expansion */
+#define ARG_RESERVED3  0x00c00000      /**< reserved for future expansion */
+#define ARG_RESERVED2  0x00d00000      /**< reserved for future expansion */
+#define ARG_RESERVED1  0x00e00000      /**< reserved for future expansion */
+#define ARG_RESERVED0  0x00f00000      /**< reserved for future expansion */
+
+/* Mask to get just the argument data */
+#define ARG_MASK       0x00f00000      /**< masks off non-argument bits */
+
+/* type of conversion to perform */
+#define CONV_INT       0x01000000      /**< convert integers */
+#define CONV_FLOAT     0x02000000      /**< convert floats */
+#define CONV_CHAR      0x03000000      /**< convert chars */
+#define CONV_STRING    0x04000000      /**< convert strings */
+#define CONV_VARARGS   0x05000000      /**< convert a %v */
+#define CONV_CLIENT    0x06000000      /**< convert a struct Client */
+#define CONV_CHANNEL   0x07000000      /**< convert a struct Channel */
+
+#define CONV_RESERVED7 0x08000000      /**< reserved for future expansion */
+#define CONV_RESERVED6 0x09000000      /**< reserved for future expansion */
+#define CONV_RESERVED5 0x0a000000      /**< reserved for future expansion */
+#define CONV_RESERVED4 0x0b000000      /**< reserved for future expansion */
+#define CONV_RESERVED3 0x0c000000      /**< reserved for future expansion */
+#define CONV_RESERVED2 0x0d000000      /**< reserved for future expansion */
+#define CONV_RESERVED1 0x0e000000      /**< reserved for future expansion */
+#define CONV_RESERVED0 0x0f000000      /**< reserved for future expansion */
+
+/* Mask to get just the conversion data */
+#define CONV_MASK      0x0f000000      /**< masks off non-conversion bits */
+
+/* Value information flags */
+#define INFO_RESERVED0 0x10000000      /**< reserved for future expansion */
+#define INFO_UPPERCASE 0x20000000      /**< use uppercase characters */
+#define INFO_UNSIGNED  0x40000000      /**< number is unsigned */
+#define INFO_NEGATIVE  0x80000000      /**< number is negative */
+
+#define BASE_OCTAL     9       /**< octal base; bits-per-char * 3 */
+#define BASE_DECIMAL   -1000   /**< decimal base; 10 ** 3 */
+#define BASE_HEX       12      /**< hexadecimal base; bits-per-char * 3 */
+
+
+/* padding...                   1         2         3         4         5 */
+/*                     12345678901234567890123456789012345678901234567890 */
+/** Predefined space padding. */
+static char spaces[] = "                                                  ";
+/** Predefined zero padding. */
+static char zeros[]  = "00000000000000000000000000000000000000000000000000";
+
+/** Length of predefined padding strings. */
+#define PAD_LENGTH     (sizeof(spaces) - 1)
+
+/*
+ * Note that these string tables have characters reversed.  There is, of
+ * course, a reason for this; check out how they're built in doprintf.
+ */
+
+/** string table for octal values */
+static char *octal[] = {
+     "",   "1",   "2",   "3",   "4",   "5",   "6",   "7",
+   "01",  "11",  "21",  "31",  "41",  "51",  "61",  "71",
+   "02",  "12",  "22",  "32",  "42",  "52",  "62",  "72",
+   "03",  "13",  "23",  "33",  "43",  "53",  "63",  "73",
+   "04",  "14",  "24",  "34",  "44",  "54",  "64",  "74",
+   "05",  "15",  "25",  "35",  "45",  "55",  "65",  "75",
+   "06",  "16",  "26",  "36",  "46",  "56",  "66",  "76",
+   "07",  "17",  "27",  "37",  "47",  "57",  "67",  "77",
+  "001", "101", "201", "301", "401", "501", "601", "701",
+  "011", "111", "211", "311", "411", "511", "611", "711",
+  "021", "121", "221", "321", "421", "521", "621", "721",
+  "031", "131", "231", "331", "431", "531", "631", "731",
+  "041", "141", "241", "341", "441", "541", "641", "741",
+  "051", "151", "251", "351", "451", "551", "651", "751",
+  "061", "161", "261", "361", "461", "561", "661", "761",
+  "071", "171", "271", "371", "471", "571", "671", "771",
+  "002", "102", "202", "302", "402", "502", "602", "702",
+  "012", "112", "212", "312", "412", "512", "612", "712",
+  "022", "122", "222", "322", "422", "522", "622", "722",
+  "032", "132", "232", "332", "432", "532", "632", "732",
+  "042", "142", "242", "342", "442", "542", "642", "742",
+  "052", "152", "252", "352", "452", "552", "652", "752",
+  "062", "162", "262", "362", "462", "562", "662", "762",
+  "072", "172", "272", "372", "472", "572", "672", "772",
+  "003", "103", "203", "303", "403", "503", "603", "703",
+  "013", "113", "213", "313", "413", "513", "613", "713",
+  "023", "123", "223", "323", "423", "523", "623", "723",
+  "033", "133", "233", "333", "433", "533", "633", "733",
+  "043", "143", "243", "343", "443", "543", "643", "743",
+  "053", "153", "253", "353", "453", "553", "653", "753",
+  "063", "163", "263", "363", "463", "563", "663", "763",
+  "073", "173", "273", "373", "473", "573", "673", "773",
+  "004", "104", "204", "304", "404", "504", "604", "704",
+  "014", "114", "214", "314", "414", "514", "614", "714",
+  "024", "124", "224", "324", "424", "524", "624", "724",
+  "034", "134", "234", "334", "434", "534", "634", "734",
+  "044", "144", "244", "344", "444", "544", "644", "744",
+  "054", "154", "254", "354", "454", "554", "654", "754",
+  "064", "164", "264", "364", "464", "564", "664", "764",
+  "074", "174", "274", "374", "474", "574", "674", "774",
+  "005", "105", "205", "305", "405", "505", "605", "705",
+  "015", "115", "215", "315", "415", "515", "615", "715",
+  "025", "125", "225", "325", "425", "525", "625", "725",
+  "035", "135", "235", "335", "435", "535", "635", "735",
+  "045", "145", "245", "345", "445", "545", "645", "745",
+  "055", "155", "255", "355", "455", "555", "655", "755",
+  "065", "165", "265", "365", "465", "565", "665", "765",
+  "075", "175", "275", "375", "475", "575", "675", "775",
+  "006", "106", "206", "306", "406", "506", "606", "706",
+  "016", "116", "216", "316", "416", "516", "616", "716",
+  "026", "126", "226", "326", "426", "526", "626", "726",
+  "036", "136", "236", "336", "436", "536", "636", "736",
+  "046", "146", "246", "346", "446", "546", "646", "746",
+  "056", "156", "256", "356", "456", "556", "656", "756",
+  "066", "166", "266", "366", "466", "566", "666", "766",
+  "076", "176", "276", "376", "476", "576", "676", "776",
+  "007", "107", "207", "307", "407", "507", "607", "707",
+  "017", "117", "217", "317", "417", "517", "617", "717",
+  "027", "127", "227", "327", "427", "527", "627", "727",
+  "037", "137", "237", "337", "437", "537", "637", "737",
+  "047", "147", "247", "347", "447", "547", "647", "747",
+  "057", "157", "257", "357", "457", "557", "657", "757",
+  "067", "167", "267", "367", "467", "567", "667", "767",
+  "077", "177", "277", "377", "477", "577", "677", "777"
+};
+
+/** string table for decimal values */
+static char *decimal[] = {
+     "",   "1",   "2",   "3",   "4",   "5",   "6",   "7",   "8",   "9",
+   "01",  "11",  "21",  "31",  "41",  "51",  "61",  "71",  "81",  "91",
+   "02",  "12",  "22",  "32",  "42",  "52",  "62",  "72",  "82",  "92",
+   "03",  "13",  "23",  "33",  "43",  "53",  "63",  "73",  "83",  "93",
+   "04",  "14",  "24",  "34",  "44",  "54",  "64",  "74",  "84",  "94",
+   "05",  "15",  "25",  "35",  "45",  "55",  "65",  "75",  "85",  "95",
+   "06",  "16",  "26",  "36",  "46",  "56",  "66",  "76",  "86",  "96",
+   "07",  "17",  "27",  "37",  "47",  "57",  "67",  "77",  "87",  "97",
+   "08",  "18",  "28",  "38",  "48",  "58",  "68",  "78",  "88",  "98",
+   "09",  "19",  "29",  "39",  "49",  "59",  "69",  "79",  "89",  "99",
+  "001", "101", "201", "301", "401", "501", "601", "701", "801", "901",
+  "011", "111", "211", "311", "411", "511", "611", "711", "811", "911",
+  "021", "121", "221", "321", "421", "521", "621", "721", "821", "921",
+  "031", "131", "231", "331", "431", "531", "631", "731", "831", "931",
+  "041", "141", "241", "341", "441", "541", "641", "741", "841", "941",
+  "051", "151", "251", "351", "451", "551", "651", "751", "851", "951",
+  "061", "161", "261", "361", "461", "561", "661", "761", "861", "961",
+  "071", "171", "271", "371", "471", "571", "671", "771", "871", "971",
+  "081", "181", "281", "381", "481", "581", "681", "781", "881", "981",
+  "091", "191", "291", "391", "491", "591", "691", "791", "891", "991",
+  "002", "102", "202", "302", "402", "502", "602", "702", "802", "902",
+  "012", "112", "212", "312", "412", "512", "612", "712", "812", "912",
+  "022", "122", "222", "322", "422", "522", "622", "722", "822", "922",
+  "032", "132", "232", "332", "432", "532", "632", "732", "832", "932",
+  "042", "142", "242", "342", "442", "542", "642", "742", "842", "942",
+  "052", "152", "252", "352", "452", "552", "652", "752", "852", "952",
+  "062", "162", "262", "362", "462", "562", "662", "762", "862", "962",
+  "072", "172", "272", "372", "472", "572", "672", "772", "872", "972",
+  "082", "182", "282", "382", "482", "582", "682", "782", "882", "982",
+  "092", "192", "292", "392", "492", "592", "692", "792", "892", "992",
+  "003", "103", "203", "303", "403", "503", "603", "703", "803", "903",
+  "013", "113", "213", "313", "413", "513", "613", "713", "813", "913",
+  "023", "123", "223", "323", "423", "523", "623", "723", "823", "923",
+  "033", "133", "233", "333", "433", "533", "633", "733", "833", "933",
+  "043", "143", "243", "343", "443", "543", "643", "743", "843", "943",
+  "053", "153", "253", "353", "453", "553", "653", "753", "853", "953",
+  "063", "163", "263", "363", "463", "563", "663", "763", "863", "963",
+  "073", "173", "273", "373", "473", "573", "673", "773", "873", "973",
+  "083", "183", "283", "383", "483", "583", "683", "783", "883", "983",
+  "093", "193", "293", "393", "493", "593", "693", "793", "893", "993",
+  "004", "104", "204", "304", "404", "504", "604", "704", "804", "904",
+  "014", "114", "214", "314", "414", "514", "614", "714", "814", "914",
+  "024", "124", "224", "324", "424", "524", "624", "724", "824", "924",
+  "034", "134", "234", "334", "434", "534", "634", "734", "834", "934",
+  "044", "144", "244", "344", "444", "544", "644", "744", "844", "944",
+  "054", "154", "254", "354", "454", "554", "654", "754", "854", "954",
+  "064", "164", "264", "364", "464", "564", "664", "764", "864", "964",
+  "074", "174", "274", "374", "474", "574", "674", "774", "874", "974",
+  "084", "184", "284", "384", "484", "584", "684", "784", "884", "984",
+  "094", "194", "294", "394", "494", "594", "694", "794", "894", "994",
+  "005", "105", "205", "305", "405", "505", "605", "705", "805", "905",
+  "015", "115", "215", "315", "415", "515", "615", "715", "815", "915",
+  "025", "125", "225", "325", "425", "525", "625", "725", "825", "925",
+  "035", "135", "235", "335", "435", "535", "635", "735", "835", "935",
+  "045", "145", "245", "345", "445", "545", "645", "745", "845", "945",
+  "055", "155", "255", "355", "455", "555", "655", "755", "855", "955",
+  "065", "165", "265", "365", "465", "565", "665", "765", "865", "965",
+  "075", "175", "275", "375", "475", "575", "675", "775", "875", "975",
+  "085", "185", "285", "385", "485", "585", "685", "785", "885", "985",
+  "095", "195", "295", "395", "495", "595", "695", "795", "895", "995",
+  "006", "106", "206", "306", "406", "506", "606", "706", "806", "906",
+  "016", "116", "216", "316", "416", "516", "616", "716", "816", "916",
+  "026", "126", "226", "326", "426", "526", "626", "726", "826", "926",
+  "036", "136", "236", "336", "436", "536", "636", "736", "836", "936",
+  "046", "146", "246", "346", "446", "546", "646", "746", "846", "946",
+  "056", "156", "256", "356", "456", "556", "656", "756", "856", "956",
+  "066", "166", "266", "366", "466", "566", "666", "766", "866", "966",
+  "076", "176", "276", "376", "476", "576", "676", "776", "876", "976",
+  "086", "186", "286", "386", "486", "586", "686", "786", "886", "986",
+  "096", "196", "296", "396", "496", "596", "696", "796", "896", "996",
+  "007", "107", "207", "307", "407", "507", "607", "707", "807", "907",
+  "017", "117", "217", "317", "417", "517", "617", "717", "817", "917",
+  "027", "127", "227", "327", "427", "527", "627", "727", "827", "927",
+  "037", "137", "237", "337", "437", "537", "637", "737", "837", "937",
+  "047", "147", "247", "347", "447", "547", "647", "747", "847", "947",
+  "057", "157", "257", "357", "457", "557", "657", "757", "857", "957",
+  "067", "167", "267", "367", "467", "567", "667", "767", "867", "967",
+  "077", "177", "277", "377", "477", "577", "677", "777", "877", "977",
+  "087", "187", "287", "387", "487", "587", "687", "787", "887", "987",
+  "097", "197", "297", "397", "497", "597", "697", "797", "897", "997",
+  "008", "108", "208", "308", "408", "508", "608", "708", "808", "908",
+  "018", "118", "218", "318", "418", "518", "618", "718", "818", "918",
+  "028", "128", "228", "328", "428", "528", "628", "728", "828", "928",
+  "038", "138", "238", "338", "438", "538", "638", "738", "838", "938",
+  "048", "148", "248", "348", "448", "548", "648", "748", "848", "948",
+  "058", "158", "258", "358", "458", "558", "658", "758", "858", "958",
+  "068", "168", "268", "368", "468", "568", "668", "768", "868", "968",
+  "078", "178", "278", "378", "478", "578", "678", "778", "878", "978",
+  "088", "188", "288", "388", "488", "588", "688", "788", "888", "988",
+  "098", "198", "298", "398", "498", "598", "698", "798", "898", "998",
+  "009", "109", "209", "309", "409", "509", "609", "709", "809", "909",
+  "019", "119", "219", "319", "419", "519", "619", "719", "819", "919",
+  "029", "129", "229", "329", "429", "529", "629", "729", "829", "929",
+  "039", "139", "239", "339", "439", "539", "639", "739", "839", "939",
+  "049", "149", "249", "349", "449", "549", "649", "749", "849", "949",
+  "059", "159", "259", "359", "459", "559", "659", "759", "859", "959",
+  "069", "169", "269", "369", "469", "569", "669", "769", "869", "969",
+  "079", "179", "279", "379", "479", "579", "679", "779", "879", "979",
+  "089", "189", "289", "389", "489", "589", "689", "789", "889", "989",
+  "099", "199", "299", "399", "499", "599", "699", "799", "899", "999"
+};
+
+/** string table for lower-case hexadecimal values */
+static char *hex[] = {
+     "",   "1",   "2",   "3",   "4",   "5",   "6",   "7",
+    "8",   "9",   "a",   "b",   "c",   "d",   "e",   "f",
+   "01",  "11",  "21",  "31",  "41",  "51",  "61",  "71",
+   "81",  "91",  "a1",  "b1",  "c1",  "d1",  "e1",  "f1",
+   "02",  "12",  "22",  "32",  "42",  "52",  "62",  "72",
+   "82",  "92",  "a2",  "b2",  "c2",  "d2",  "e2",  "f2",
+   "03",  "13",  "23",  "33",  "43",  "53",  "63",  "73",
+   "83",  "93",  "a3",  "b3",  "c3",  "d3",  "e3",  "f3",
+   "04",  "14",  "24",  "34",  "44",  "54",  "64",  "74",
+   "84",  "94",  "a4",  "b4",  "c4",  "d4",  "e4",  "f4",
+   "05",  "15",  "25",  "35",  "45",  "55",  "65",  "75",
+   "85",  "95",  "a5",  "b5",  "c5",  "d5",  "e5",  "f5",
+   "06",  "16",  "26",  "36",  "46",  "56",  "66",  "76",
+   "86",  "96",  "a6",  "b6",  "c6",  "d6",  "e6",  "f6",
+   "07",  "17",  "27",  "37",  "47",  "57",  "67",  "77",
+   "87",  "97",  "a7",  "b7",  "c7",  "d7",  "e7",  "f7",
+   "08",  "18",  "28",  "38",  "48",  "58",  "68",  "78",
+   "88",  "98",  "a8",  "b8",  "c8",  "d8",  "e8",  "f8",
+   "09",  "19",  "29",  "39",  "49",  "59",  "69",  "79",
+   "89",  "99",  "a9",  "b9",  "c9",  "d9",  "e9",  "f9",
+   "0a",  "1a",  "2a",  "3a",  "4a",  "5a",  "6a",  "7a",
+   "8a",  "9a",  "aa",  "ba",  "ca",  "da",  "ea",  "fa",
+   "0b",  "1b",  "2b",  "3b",  "4b",  "5b",  "6b",  "7b",
+   "8b",  "9b",  "ab",  "bb",  "cb",  "db",  "eb",  "fb",
+   "0c",  "1c",  "2c",  "3c",  "4c",  "5c",  "6c",  "7c",
+   "8c",  "9c",  "ac",  "bc",  "cc",  "dc",  "ec",  "fc",
+   "0d",  "1d",  "2d",  "3d",  "4d",  "5d",  "6d",  "7d",
+   "8d",  "9d",  "ad",  "bd",  "cd",  "dd",  "ed",  "fd",
+   "0e",  "1e",  "2e",  "3e",  "4e",  "5e",  "6e",  "7e",
+   "8e",  "9e",  "ae",  "be",  "ce",  "de",  "ee",  "fe",
+   "0f",  "1f",  "2f",  "3f",  "4f",  "5f",  "6f",  "7f",
+   "8f",  "9f",  "af",  "bf",  "cf",  "df",  "ef",  "ff",
+  "001", "101", "201", "301", "401", "501", "601", "701",
+  "801", "901", "a01", "b01", "c01", "d01", "e01", "f01",
+  "011", "111", "211", "311", "411", "511", "611", "711",
+  "811", "911", "a11", "b11", "c11", "d11", "e11", "f11",
+  "021", "121", "221", "321", "421", "521", "621", "721",
+  "821", "921", "a21", "b21", "c21", "d21", "e21", "f21",
+  "031", "131", "231", "331", "431", "531", "631", "731",
+  "831", "931", "a31", "b31", "c31", "d31", "e31", "f31",
+  "041", "141", "241", "341", "441", "541", "641", "741",
+  "841", "941", "a41", "b41", "c41", "d41", "e41", "f41",
+  "051", "151", "251", "351", "451", "551", "651", "751",
+  "851", "951", "a51", "b51", "c51", "d51", "e51", "f51",
+  "061", "161", "261", "361", "461", "561", "661", "761",
+  "861", "961", "a61", "b61", "c61", "d61", "e61", "f61",
+  "071", "171", "271", "371", "471", "571", "671", "771",
+  "871", "971", "a71", "b71", "c71", "d71", "e71", "f71",
+  "081", "181", "281", "381", "481", "581", "681", "781",
+  "881", "981", "a81", "b81", "c81", "d81", "e81", "f81",
+  "091", "191", "291", "391", "491", "591", "691", "791",
+  "891", "991", "a91", "b91", "c91", "d91", "e91", "f91",
+  "0a1", "1a1", "2a1", "3a1", "4a1", "5a1", "6a1", "7a1",
+  "8a1", "9a1", "aa1", "ba1", "ca1", "da1", "ea1", "fa1",
+  "0b1", "1b1", "2b1", "3b1", "4b1", "5b1", "6b1", "7b1",
+  "8b1", "9b1", "ab1", "bb1", "cb1", "db1", "eb1", "fb1",
+  "0c1", "1c1", "2c1", "3c1", "4c1", "5c1", "6c1", "7c1",
+  "8c1", "9c1", "ac1", "bc1", "cc1", "dc1", "ec1", "fc1",
+  "0d1", "1d1", "2d1", "3d1", "4d1", "5d1", "6d1", "7d1",
+  "8d1", "9d1", "ad1", "bd1", "cd1", "dd1", "ed1", "fd1",
+  "0e1", "1e1", "2e1", "3e1", "4e1", "5e1", "6e1", "7e1",
+  "8e1", "9e1", "ae1", "be1", "ce1", "de1", "ee1", "fe1",
+  "0f1", "1f1", "2f1", "3f1", "4f1", "5f1", "6f1", "7f1",
+  "8f1", "9f1", "af1", "bf1", "cf1", "df1", "ef1", "ff1",
+  "002", "102", "202", "302", "402", "502", "602", "702",
+  "802", "902", "a02", "b02", "c02", "d02", "e02", "f02",
+  "012", "112", "212", "312", "412", "512", "612", "712",
+  "812", "912", "a12", "b12", "c12", "d12", "e12", "f12",
+  "022", "122", "222", "322", "422", "522", "622", "722",
+  "822", "922", "a22", "b22", "c22", "d22", "e22", "f22",
+  "032", "132", "232", "332", "432", "532", "632", "732",
+  "832", "932", "a32", "b32", "c32", "d32", "e32", "f32",
+  "042", "142", "242", "342", "442", "542", "642", "742",
+  "842", "942", "a42", "b42", "c42", "d42", "e42", "f42",
+  "052", "152", "252", "352", "452", "552", "652", "752",
+  "852", "952", "a52", "b52", "c52", "d52", "e52", "f52",
+  "062", "162", "262", "362", "462", "562", "662", "762",
+  "862", "962", "a62", "b62", "c62", "d62", "e62", "f62",
+  "072", "172", "272", "372", "472", "572", "672", "772",
+  "872", "972", "a72", "b72", "c72", "d72", "e72", "f72",
+  "082", "182", "282", "382", "482", "582", "682", "782",
+  "882", "982", "a82", "b82", "c82", "d82", "e82", "f82",
+  "092", "192", "292", "392", "492", "592", "692", "792",
+  "892", "992", "a92", "b92", "c92", "d92", "e92", "f92",
+  "0a2", "1a2", "2a2", "3a2", "4a2", "5a2", "6a2", "7a2",
+  "8a2", "9a2", "aa2", "ba2", "ca2", "da2", "ea2", "fa2",
+  "0b2", "1b2", "2b2", "3b2", "4b2", "5b2", "6b2", "7b2",
+  "8b2", "9b2", "ab2", "bb2", "cb2", "db2", "eb2", "fb2",
+  "0c2", "1c2", "2c2", "3c2", "4c2", "5c2", "6c2", "7c2",
+  "8c2", "9c2", "ac2", "bc2", "cc2", "dc2", "ec2", "fc2",
+  "0d2", "1d2", "2d2", "3d2", "4d2", "5d2", "6d2", "7d2",
+  "8d2", "9d2", "ad2", "bd2", "cd2", "dd2", "ed2", "fd2",
+  "0e2", "1e2", "2e2", "3e2", "4e2", "5e2", "6e2", "7e2",
+  "8e2", "9e2", "ae2", "be2", "ce2", "de2", "ee2", "fe2",
+  "0f2", "1f2", "2f2", "3f2", "4f2", "5f2", "6f2", "7f2",
+  "8f2", "9f2", "af2", "bf2", "cf2", "df2", "ef2", "ff2",
+  "003", "103", "203", "303", "403", "503", "603", "703",
+  "803", "903", "a03", "b03", "c03", "d03", "e03", "f03",
+  "013", "113", "213", "313", "413", "513", "613", "713",
+  "813", "913", "a13", "b13", "c13", "d13", "e13", "f13",
+  "023", "123", "223", "323", "423", "523", "623", "723",
+  "823", "923", "a23", "b23", "c23", "d23", "e23", "f23",
+  "033", "133", "233", "333", "433", "533", "633", "733",
+  "833", "933", "a33", "b33", "c33", "d33", "e33", "f33",
+  "043", "143", "243", "343", "443", "543", "643", "743",
+  "843", "943", "a43", "b43", "c43", "d43", "e43", "f43",
+  "053", "153", "253", "353", "453", "553", "653", "753",
+  "853", "953", "a53", "b53", "c53", "d53", "e53", "f53",
+  "063", "163", "263", "363", "463", "563", "663", "763",
+  "863", "963", "a63", "b63", "c63", "d63", "e63", "f63",
+  "073", "173", "273", "373", "473", "573", "673", "773",
+  "873", "973", "a73", "b73", "c73", "d73", "e73", "f73",
+  "083", "183", "283", "383", "483", "583", "683", "783",
+  "883", "983", "a83", "b83", "c83", "d83", "e83", "f83",
+  "093", "193", "293", "393", "493", "593", "693", "793",
+  "893", "993", "a93", "b93", "c93", "d93", "e93", "f93",
+  "0a3", "1a3", "2a3", "3a3", "4a3", "5a3", "6a3", "7a3",
+  "8a3", "9a3", "aa3", "ba3", "ca3", "da3", "ea3", "fa3",
+  "0b3", "1b3", "2b3", "3b3", "4b3", "5b3", "6b3", "7b3",
+  "8b3", "9b3", "ab3", "bb3", "cb3", "db3", "eb3", "fb3",
+  "0c3", "1c3", "2c3", "3c3", "4c3", "5c3", "6c3", "7c3",
+  "8c3", "9c3", "ac3", "bc3", "cc3", "dc3", "ec3", "fc3",
+  "0d3", "1d3", "2d3", "3d3", "4d3", "5d3", "6d3", "7d3",
+  "8d3", "9d3", "ad3", "bd3", "cd3", "dd3", "ed3", "fd3",
+  "0e3", "1e3", "2e3", "3e3", "4e3", "5e3", "6e3", "7e3",
+  "8e3", "9e3", "ae3", "be3", "ce3", "de3", "ee3", "fe3",
+  "0f3", "1f3", "2f3", "3f3", "4f3", "5f3", "6f3", "7f3",
+  "8f3", "9f3", "af3", "bf3", "cf3", "df3", "ef3", "ff3",
+  "004", "104", "204", "304", "404", "504", "604", "704",
+  "804", "904", "a04", "b04", "c04", "d04", "e04", "f04",
+  "014", "114", "214", "314", "414", "514", "614", "714",
+  "814", "914", "a14", "b14", "c14", "d14", "e14", "f14",
+  "024", "124", "224", "324", "424", "524", "624", "724",
+  "824", "924", "a24", "b24", "c24", "d24", "e24", "f24",
+  "034", "134", "234", "334", "434", "534", "634", "734",
+  "834", "934", "a34", "b34", "c34", "d34", "e34", "f34",
+  "044", "144", "244", "344", "444", "544", "644", "744",
+  "844", "944", "a44", "b44", "c44", "d44", "e44", "f44",
+  "054", "154", "254", "354", "454", "554", "654", "754",
+  "854", "954", "a54", "b54", "c54", "d54", "e54", "f54",
+  "064", "164", "264", "364", "464", "564", "664", "764",
+  "864", "964", "a64", "b64", "c64", "d64", "e64", "f64",
+  "074", "174", "274", "374", "474", "574", "674", "774",
+  "874", "974", "a74", "b74", "c74", "d74", "e74", "f74",
+  "084", "184", "284", "384", "484", "584", "684", "784",
+  "884", "984", "a84", "b84", "c84", "d84", "e84", "f84",
+  "094", "194", "294", "394", "494", "594", "694", "794",
+  "894", "994", "a94", "b94", "c94", "d94", "e94", "f94",
+  "0a4", "1a4", "2a4", "3a4", "4a4", "5a4", "6a4", "7a4",
+  "8a4", "9a4", "aa4", "ba4", "ca4", "da4", "ea4", "fa4",
+  "0b4", "1b4", "2b4", "3b4", "4b4", "5b4", "6b4", "7b4",
+  "8b4", "9b4", "ab4", "bb4", "cb4", "db4", "eb4", "fb4",
+  "0c4", "1c4", "2c4", "3c4", "4c4", "5c4", "6c4", "7c4",
+  "8c4", "9c4", "ac4", "bc4", "cc4", "dc4", "ec4", "fc4",
+  "0d4", "1d4", "2d4", "3d4", "4d4", "5d4", "6d4", "7d4",
+  "8d4", "9d4", "ad4", "bd4", "cd4", "dd4", "ed4", "fd4",
+  "0e4", "1e4", "2e4", "3e4", "4e4", "5e4", "6e4", "7e4",
+  "8e4", "9e4", "ae4", "be4", "ce4", "de4", "ee4", "fe4",
+  "0f4", "1f4", "2f4", "3f4", "4f4", "5f4", "6f4", "7f4",
+  "8f4", "9f4", "af4", "bf4", "cf4", "df4", "ef4", "ff4",
+  "005", "105", "205", "305", "405", "505", "605", "705",
+  "805", "905", "a05", "b05", "c05", "d05", "e05", "f05",
+  "015", "115", "215", "315", "415", "515", "615", "715",
+  "815", "915", "a15", "b15", "c15", "d15", "e15", "f15",
+  "025", "125", "225", "325", "425", "525", "625", "725",
+  "825", "925", "a25", "b25", "c25", "d25", "e25", "f25",
+  "035", "135", "235", "335", "435", "535", "635", "735",
+  "835", "935", "a35", "b35", "c35", "d35", "e35", "f35",
+  "045", "145", "245", "345", "445", "545", "645", "745",
+  "845", "945", "a45", "b45", "c45", "d45", "e45", "f45",
+  "055", "155", "255", "355", "455", "555", "655", "755",
+  "855", "955", "a55", "b55", "c55", "d55", "e55", "f55",
+  "065", "165", "265", "365", "465", "565", "665", "765",
+  "865", "965", "a65", "b65", "c65", "d65", "e65", "f65",
+  "075", "175", "275", "375", "475", "575", "675", "775",
+  "875", "975", "a75", "b75", "c75", "d75", "e75", "f75",
+  "085", "185", "285", "385", "485", "585", "685", "785",
+  "885", "985", "a85", "b85", "c85", "d85", "e85", "f85",
+  "095", "195", "295", "395", "495", "595", "695", "795",
+  "895", "995", "a95", "b95", "c95", "d95", "e95", "f95",
+  "0a5", "1a5", "2a5", "3a5", "4a5", "5a5", "6a5", "7a5",
+  "8a5", "9a5", "aa5", "ba5", "ca5", "da5", "ea5", "fa5",
+  "0b5", "1b5", "2b5", "3b5", "4b5", "5b5", "6b5", "7b5",
+  "8b5", "9b5", "ab5", "bb5", "cb5", "db5", "eb5", "fb5",
+  "0c5", "1c5", "2c5", "3c5", "4c5", "5c5", "6c5", "7c5",
+  "8c5", "9c5", "ac5", "bc5", "cc5", "dc5", "ec5", "fc5",
+  "0d5", "1d5", "2d5", "3d5", "4d5", "5d5", "6d5", "7d5",
+  "8d5", "9d5", "ad5", "bd5", "cd5", "dd5", "ed5", "fd5",
+  "0e5", "1e5", "2e5", "3e5", "4e5", "5e5", "6e5", "7e5",
+  "8e5", "9e5", "ae5", "be5", "ce5", "de5", "ee5", "fe5",
+  "0f5", "1f5", "2f5", "3f5", "4f5", "5f5", "6f5", "7f5",
+  "8f5", "9f5", "af5", "bf5", "cf5", "df5", "ef5", "ff5",
+  "006", "106", "206", "306", "406", "506", "606", "706",
+  "806", "906", "a06", "b06", "c06", "d06", "e06", "f06",
+  "016", "116", "216", "316", "416", "516", "616", "716",
+  "816", "916", "a16", "b16", "c16", "d16", "e16", "f16",
+  "026", "126", "226", "326", "426", "526", "626", "726",
+  "826", "926", "a26", "b26", "c26", "d26", "e26", "f26",
+  "036", "136", "236", "336", "436", "536", "636", "736",
+  "836", "936", "a36", "b36", "c36", "d36", "e36", "f36",
+  "046", "146", "246", "346", "446", "546", "646", "746",
+  "846", "946", "a46", "b46", "c46", "d46", "e46", "f46",
+  "056", "156", "256", "356", "456", "556", "656", "756",
+  "856", "956", "a56", "b56", "c56", "d56", "e56", "f56",
+  "066", "166", "266", "366", "466", "566", "666", "766",
+  "866", "966", "a66", "b66", "c66", "d66", "e66", "f66",
+  "076", "176", "276", "376", "476", "576", "676", "776",
+  "876", "976", "a76", "b76", "c76", "d76", "e76", "f76",
+  "086", "186", "286", "386", "486", "586", "686", "786",
+  "886", "986", "a86", "b86", "c86", "d86", "e86", "f86",
+  "096", "196", "296", "396", "496", "596", "696", "796",
+  "896", "996", "a96", "b96", "c96", "d96", "e96", "f96",
+  "0a6", "1a6", "2a6", "3a6", "4a6", "5a6", "6a6", "7a6",
+  "8a6", "9a6", "aa6", "ba6", "ca6", "da6", "ea6", "fa6",
+  "0b6", "1b6", "2b6", "3b6", "4b6", "5b6", "6b6", "7b6",
+  "8b6", "9b6", "ab6", "bb6", "cb6", "db6", "eb6", "fb6",
+  "0c6", "1c6", "2c6", "3c6", "4c6", "5c6", "6c6", "7c6",
+  "8c6", "9c6", "ac6", "bc6", "cc6", "dc6", "ec6", "fc6",
+  "0d6", "1d6", "2d6", "3d6", "4d6", "5d6", "6d6", "7d6",
+  "8d6", "9d6", "ad6", "bd6", "cd6", "dd6", "ed6", "fd6",
+  "0e6", "1e6", "2e6", "3e6", "4e6", "5e6", "6e6", "7e6",
+  "8e6", "9e6", "ae6", "be6", "ce6", "de6", "ee6", "fe6",
+  "0f6", "1f6", "2f6", "3f6", "4f6", "5f6", "6f6", "7f6",
+  "8f6", "9f6", "af6", "bf6", "cf6", "df6", "ef6", "ff6",
+  "007", "107", "207", "307", "407", "507", "607", "707",
+  "807", "907", "a07", "b07", "c07", "d07", "e07", "f07",
+  "017", "117", "217", "317", "417", "517", "617", "717",
+  "817", "917", "a17", "b17", "c17", "d17", "e17", "f17",
+  "027", "127", "227", "327", "427", "527", "627", "727",
+  "827", "927", "a27", "b27", "c27", "d27", "e27", "f27",
+  "037", "137", "237", "337", "437", "537", "637", "737",
+  "837", "937", "a37", "b37", "c37", "d37", "e37", "f37",
+  "047", "147", "247", "347", "447", "547", "647", "747",
+  "847", "947", "a47", "b47", "c47", "d47", "e47", "f47",
+  "057", "157", "257", "357", "457", "557", "657", "757",
+  "857", "957", "a57", "b57", "c57", "d57", "e57", "f57",
+  "067", "167", "267", "367", "467", "567", "667", "767",
+  "867", "967", "a67", "b67", "c67", "d67", "e67", "f67",
+  "077", "177", "277", "377", "477", "577", "677", "777",
+  "877", "977", "a77", "b77", "c77", "d77", "e77", "f77",
+  "087", "187", "287", "387", "487", "587", "687", "787",
+  "887", "987", "a87", "b87", "c87", "d87", "e87", "f87",
+  "097", "197", "297", "397", "497", "597", "697", "797",
+  "897", "997", "a97", "b97", "c97", "d97", "e97", "f97",
+  "0a7", "1a7", "2a7", "3a7", "4a7", "5a7", "6a7", "7a7",
+  "8a7", "9a7", "aa7", "ba7", "ca7", "da7", "ea7", "fa7",
+  "0b7", "1b7", "2b7", "3b7", "4b7", "5b7", "6b7", "7b7",
+  "8b7", "9b7", "ab7", "bb7", "cb7", "db7", "eb7", "fb7",
+  "0c7", "1c7", "2c7", "3c7", "4c7", "5c7", "6c7", "7c7",
+  "8c7", "9c7", "ac7", "bc7", "cc7", "dc7", "ec7", "fc7",
+  "0d7", "1d7", "2d7", "3d7", "4d7", "5d7", "6d7", "7d7",
+  "8d7", "9d7", "ad7", "bd7", "cd7", "dd7", "ed7", "fd7",
+  "0e7", "1e7", "2e7", "3e7", "4e7", "5e7", "6e7", "7e7",
+  "8e7", "9e7", "ae7", "be7", "ce7", "de7", "ee7", "fe7",
+  "0f7", "1f7", "2f7", "3f7", "4f7", "5f7", "6f7", "7f7",
+  "8f7", "9f7", "af7", "bf7", "cf7", "df7", "ef7", "ff7",
+  "008", "108", "208", "308", "408", "508", "608", "708",
+  "808", "908", "a08", "b08", "c08", "d08", "e08", "f08",
+  "018", "118", "218", "318", "418", "518", "618", "718",
+  "818", "918", "a18", "b18", "c18", "d18", "e18", "f18",
+  "028", "128", "228", "328", "428", "528", "628", "728",
+  "828", "928", "a28", "b28", "c28", "d28", "e28", "f28",
+  "038", "138", "238", "338", "438", "538", "638", "738",
+  "838", "938", "a38", "b38", "c38", "d38", "e38", "f38",
+  "048", "148", "248", "348", "448", "548", "648", "748",
+  "848", "948", "a48", "b48", "c48", "d48", "e48", "f48",
+  "058", "158", "258", "358", "458", "558", "658", "758",
+  "858", "958", "a58", "b58", "c58", "d58", "e58", "f58",
+  "068", "168", "268", "368", "468", "568", "668", "768",
+  "868", "968", "a68", "b68", "c68", "d68", "e68", "f68",
+  "078", "178", "278", "378", "478", "578", "678", "778",
+  "878", "978", "a78", "b78", "c78", "d78", "e78", "f78",
+  "088", "188", "288", "388", "488", "588", "688", "788",
+  "888", "988", "a88", "b88", "c88", "d88", "e88", "f88",
+  "098", "198", "298", "398", "498", "598", "698", "798",
+  "898", "998", "a98", "b98", "c98", "d98", "e98", "f98",
+  "0a8", "1a8", "2a8", "3a8", "4a8", "5a8", "6a8", "7a8",
+  "8a8", "9a8", "aa8", "ba8", "ca8", "da8", "ea8", "fa8",
+  "0b8", "1b8", "2b8", "3b8", "4b8", "5b8", "6b8", "7b8",
+  "8b8", "9b8", "ab8", "bb8", "cb8", "db8", "eb8", "fb8",
+  "0c8", "1c8", "2c8", "3c8", "4c8", "5c8", "6c8", "7c8",
+  "8c8", "9c8", "ac8", "bc8", "cc8", "dc8", "ec8", "fc8",
+  "0d8", "1d8", "2d8", "3d8", "4d8", "5d8", "6d8", "7d8",
+  "8d8", "9d8", "ad8", "bd8", "cd8", "dd8", "ed8", "fd8",
+  "0e8", "1e8", "2e8", "3e8", "4e8", "5e8", "6e8", "7e8",
+  "8e8", "9e8", "ae8", "be8", "ce8", "de8", "ee8", "fe8",
+  "0f8", "1f8", "2f8", "3f8", "4f8", "5f8", "6f8", "7f8",
+  "8f8", "9f8", "af8", "bf8", "cf8", "df8", "ef8", "ff8",
+  "009", "109", "209", "309", "409", "509", "609", "709",
+  "809", "909", "a09", "b09", "c09", "d09", "e09", "f09",
+  "019", "119", "219", "319", "419", "519", "619", "719",
+  "819", "919", "a19", "b19", "c19", "d19", "e19", "f19",
+  "029", "129", "229", "329", "429", "529", "629", "729",
+  "829", "929", "a29", "b29", "c29", "d29", "e29", "f29",
+  "039", "139", "239", "339", "439", "539", "639", "739",
+  "839", "939", "a39", "b39", "c39", "d39", "e39", "f39",
+  "049", "149", "249", "349", "449", "549", "649", "749",
+  "849", "949", "a49", "b49", "c49", "d49", "e49", "f49",
+  "059", "159", "259", "359", "459", "559", "659", "759",
+  "859", "959", "a59", "b59", "c59", "d59", "e59", "f59",
+  "069", "169", "269", "369", "469", "569", "669", "769",
+  "869", "969", "a69", "b69", "c69", "d69", "e69", "f69",
+  "079", "179", "279", "379", "479", "579", "679", "779",
+  "879", "979", "a79", "b79", "c79", "d79", "e79", "f79",
+  "089", "189", "289", "389", "489", "589", "689", "789",
+  "889", "989", "a89", "b89", "c89", "d89", "e89", "f89",
+  "099", "199", "299", "399", "499", "599", "699", "799",
+  "899", "999", "a99", "b99", "c99", "d99", "e99", "f99",
+  "0a9", "1a9", "2a9", "3a9", "4a9", "5a9", "6a9", "7a9",
+  "8a9", "9a9", "aa9", "ba9", "ca9", "da9", "ea9", "fa9",
+  "0b9", "1b9", "2b9", "3b9", "4b9", "5b9", "6b9", "7b9",
+  "8b9", "9b9", "ab9", "bb9", "cb9", "db9", "eb9", "fb9",
+  "0c9", "1c9", "2c9", "3c9", "4c9", "5c9", "6c9", "7c9",
+  "8c9", "9c9", "ac9", "bc9", "cc9", "dc9", "ec9", "fc9",
+  "0d9", "1d9", "2d9", "3d9", "4d9", "5d9", "6d9", "7d9",
+  "8d9", "9d9", "ad9", "bd9", "cd9", "dd9", "ed9", "fd9",
+  "0e9", "1e9", "2e9", "3e9", "4e9", "5e9", "6e9", "7e9",
+  "8e9", "9e9", "ae9", "be9", "ce9", "de9", "ee9", "fe9",
+  "0f9", "1f9", "2f9", "3f9", "4f9", "5f9", "6f9", "7f9",
+  "8f9", "9f9", "af9", "bf9", "cf9", "df9", "ef9", "ff9",
+  "00a", "10a", "20a", "30a", "40a", "50a", "60a", "70a",
+  "80a", "90a", "a0a", "b0a", "c0a", "d0a", "e0a", "f0a",
+  "01a", "11a", "21a", "31a", "41a", "51a", "61a", "71a",
+  "81a", "91a", "a1a", "b1a", "c1a", "d1a", "e1a", "f1a",
+  "02a", "12a", "22a", "32a", "42a", "52a", "62a", "72a",
+  "82a", "92a", "a2a", "b2a", "c2a", "d2a", "e2a", "f2a",
+  "03a", "13a", "23a", "33a", "43a", "53a", "63a", "73a",
+  "83a", "93a", "a3a", "b3a", "c3a", "d3a", "e3a", "f3a",
+  "04a", "14a", "24a", "34a", "44a", "54a", "64a", "74a",
+  "84a", "94a", "a4a", "b4a", "c4a", "d4a", "e4a", "f4a",
+  "05a", "15a", "25a", "35a", "45a", "55a", "65a", "75a",
+  "85a", "95a", "a5a", "b5a", "c5a", "d5a", "e5a", "f5a",
+  "06a", "16a", "26a", "36a", "46a", "56a", "66a", "76a",
+  "86a", "96a", "a6a", "b6a", "c6a", "d6a", "e6a", "f6a",
+  "07a", "17a", "27a", "37a", "47a", "57a", "67a", "77a",
+  "87a", "97a", "a7a", "b7a", "c7a", "d7a", "e7a", "f7a",
+  "08a", "18a", "28a", "38a", "48a", "58a", "68a", "78a",
+  "88a", "98a", "a8a", "b8a", "c8a", "d8a", "e8a", "f8a",
+  "09a", "19a", "29a", "39a", "49a", "59a", "69a", "79a",
+  "89a", "99a", "a9a", "b9a", "c9a", "d9a", "e9a", "f9a",
+  "0aa", "1aa", "2aa", "3aa", "4aa", "5aa", "6aa", "7aa",
+  "8aa", "9aa", "aaa", "baa", "caa", "daa", "eaa", "faa",
+  "0ba", "1ba", "2ba", "3ba", "4ba", "5ba", "6ba", "7ba",
+  "8ba", "9ba", "aba", "bba", "cba", "dba", "eba", "fba",
+  "0ca", "1ca", "2ca", "3ca", "4ca", "5ca", "6ca", "7ca",
+  "8ca", "9ca", "aca", "bca", "cca", "dca", "eca", "fca",
+  "0da", "1da", "2da", "3da", "4da", "5da", "6da", "7da",
+  "8da", "9da", "ada", "bda", "cda", "dda", "eda", "fda",
+  "0ea", "1ea", "2ea", "3ea", "4ea", "5ea", "6ea", "7ea",
+  "8ea", "9ea", "aea", "bea", "cea", "dea", "eea", "fea",
+  "0fa", "1fa", "2fa", "3fa", "4fa", "5fa", "6fa", "7fa",
+  "8fa", "9fa", "afa", "bfa", "cfa", "dfa", "efa", "ffa",
+  "00b", "10b", "20b", "30b", "40b", "50b", "60b", "70b",
+  "80b", "90b", "a0b", "b0b", "c0b", "d0b", "e0b", "f0b",
+  "01b", "11b", "21b", "31b", "41b", "51b", "61b", "71b",
+  "81b", "91b", "a1b", "b1b", "c1b", "d1b", "e1b", "f1b",
+  "02b", "12b", "22b", "32b", "42b", "52b", "62b", "72b",
+  "82b", "92b", "a2b", "b2b", "c2b", "d2b", "e2b", "f2b",
+  "03b", "13b", "23b", "33b", "43b", "53b", "63b", "73b",
+  "83b", "93b", "a3b", "b3b", "c3b", "d3b", "e3b", "f3b",
+  "04b", "14b", "24b", "34b", "44b", "54b", "64b", "74b",
+  "84b", "94b", "a4b", "b4b", "c4b", "d4b", "e4b", "f4b",
+  "05b", "15b", "25b", "35b", "45b", "55b", "65b", "75b",
+  "85b", "95b", "a5b", "b5b", "c5b", "d5b", "e5b", "f5b",
+  "06b", "16b", "26b", "36b", "46b", "56b", "66b", "76b",
+  "86b", "96b", "a6b", "b6b", "c6b", "d6b", "e6b", "f6b",
+  "07b", "17b", "27b", "37b", "47b", "57b", "67b", "77b",
+  "87b", "97b", "a7b", "b7b", "c7b", "d7b", "e7b", "f7b",
+  "08b", "18b", "28b", "38b", "48b", "58b", "68b", "78b",
+  "88b", "98b", "a8b", "b8b", "c8b", "d8b", "e8b", "f8b",
+  "09b", "19b", "29b", "39b", "49b", "59b", "69b", "79b",
+  "89b", "99b", "a9b", "b9b", "c9b", "d9b", "e9b", "f9b",
+  "0ab", "1ab", "2ab", "3ab", "4ab", "5ab", "6ab", "7ab",
+  "8ab", "9ab", "aab", "bab", "cab", "dab", "eab", "fab",
+  "0bb", "1bb", "2bb", "3bb", "4bb", "5bb", "6bb", "7bb",
+  "8bb", "9bb", "abb", "bbb", "cbb", "dbb", "ebb", "fbb",
+  "0cb", "1cb", "2cb", "3cb", "4cb", "5cb", "6cb", "7cb",
+  "8cb", "9cb", "acb", "bcb", "ccb", "dcb", "ecb", "fcb",
+  "0db", "1db", "2db", "3db", "4db", "5db", "6db", "7db",
+  "8db", "9db", "adb", "bdb", "cdb", "ddb", "edb", "fdb",
+  "0eb", "1eb", "2eb", "3eb", "4eb", "5eb", "6eb", "7eb",
+  "8eb", "9eb", "aeb", "beb", "ceb", "deb", "eeb", "feb",
+  "0fb", "1fb", "2fb", "3fb", "4fb", "5fb", "6fb", "7fb",
+  "8fb", "9fb", "afb", "bfb", "cfb", "dfb", "efb", "ffb",
+  "00c", "10c", "20c", "30c", "40c", "50c", "60c", "70c",
+  "80c", "90c", "a0c", "b0c", "c0c", "d0c", "e0c", "f0c",
+  "01c", "11c", "21c", "31c", "41c", "51c", "61c", "71c",
+  "81c", "91c", "a1c", "b1c", "c1c", "d1c", "e1c", "f1c",
+  "02c", "12c", "22c", "32c", "42c", "52c", "62c", "72c",
+  "82c", "92c", "a2c", "b2c", "c2c", "d2c", "e2c", "f2c",
+  "03c", "13c", "23c", "33c", "43c", "53c", "63c", "73c",
+  "83c", "93c", "a3c", "b3c", "c3c", "d3c", "e3c", "f3c",
+  "04c", "14c", "24c", "34c", "44c", "54c", "64c", "74c",
+  "84c", "94c", "a4c", "b4c", "c4c", "d4c", "e4c", "f4c",
+  "05c", "15c", "25c", "35c", "45c", "55c", "65c", "75c",
+  "85c", "95c", "a5c", "b5c", "c5c", "d5c", "e5c", "f5c",
+  "06c", "16c", "26c", "36c", "46c", "56c", "66c", "76c",
+  "86c", "96c", "a6c", "b6c", "c6c", "d6c", "e6c", "f6c",
+  "07c", "17c", "27c", "37c", "47c", "57c", "67c", "77c",
+  "87c", "97c", "a7c", "b7c", "c7c", "d7c", "e7c", "f7c",
+  "08c", "18c", "28c", "38c", "48c", "58c", "68c", "78c",
+  "88c", "98c", "a8c", "b8c", "c8c", "d8c", "e8c", "f8c",
+  "09c", "19c", "29c", "39c", "49c", "59c", "69c", "79c",
+  "89c", "99c", "a9c", "b9c", "c9c", "d9c", "e9c", "f9c",
+  "0ac", "1ac", "2ac", "3ac", "4ac", "5ac", "6ac", "7ac",
+  "8ac", "9ac", "aac", "bac", "cac", "dac", "eac", "fac",
+  "0bc", "1bc", "2bc", "3bc", "4bc", "5bc", "6bc", "7bc",
+  "8bc", "9bc", "abc", "bbc", "cbc", "dbc", "ebc", "fbc",
+  "0cc", "1cc", "2cc", "3cc", "4cc", "5cc", "6cc", "7cc",
+  "8cc", "9cc", "acc", "bcc", "ccc", "dcc", "ecc", "fcc",
+  "0dc", "1dc", "2dc", "3dc", "4dc", "5dc", "6dc", "7dc",
+  "8dc", "9dc", "adc", "bdc", "cdc", "ddc", "edc", "fdc",
+  "0ec", "1ec", "2ec", "3ec", "4ec", "5ec", "6ec", "7ec",
+  "8ec", "9ec", "aec", "bec", "cec", "dec", "eec", "fec",
+  "0fc", "1fc", "2fc", "3fc", "4fc", "5fc", "6fc", "7fc",
+  "8fc", "9fc", "afc", "bfc", "cfc", "dfc", "efc", "ffc",
+  "00d", "10d", "20d", "30d", "40d", "50d", "60d", "70d",
+  "80d", "90d", "a0d", "b0d", "c0d", "d0d", "e0d", "f0d",
+  "01d", "11d", "21d", "31d", "41d", "51d", "61d", "71d",
+  "81d", "91d", "a1d", "b1d", "c1d", "d1d", "e1d", "f1d",
+  "02d", "12d", "22d", "32d", "42d", "52d", "62d", "72d",
+  "82d", "92d", "a2d", "b2d", "c2d", "d2d", "e2d", "f2d",
+  "03d", "13d", "23d", "33d", "43d", "53d", "63d", "73d",
+  "83d", "93d", "a3d", "b3d", "c3d", "d3d", "e3d", "f3d",
+  "04d", "14d", "24d", "34d", "44d", "54d", "64d", "74d",
+  "84d", "94d", "a4d", "b4d", "c4d", "d4d", "e4d", "f4d",
+  "05d", "15d", "25d", "35d", "45d", "55d", "65d", "75d",
+  "85d", "95d", "a5d", "b5d", "c5d", "d5d", "e5d", "f5d",
+  "06d", "16d", "26d", "36d", "46d", "56d", "66d", "76d",
+  "86d", "96d", "a6d", "b6d", "c6d", "d6d", "e6d", "f6d",
+  "07d", "17d", "27d", "37d", "47d", "57d", "67d", "77d",
+  "87d", "97d", "a7d", "b7d", "c7d", "d7d", "e7d", "f7d",
+  "08d", "18d", "28d", "38d", "48d", "58d", "68d", "78d",
+  "88d", "98d", "a8d", "b8d", "c8d", "d8d", "e8d", "f8d",
+  "09d", "19d", "29d", "39d", "49d", "59d", "69d", "79d",
+  "89d", "99d", "a9d", "b9d", "c9d", "d9d", "e9d", "f9d",
+  "0ad", "1ad", "2ad", "3ad", "4ad", "5ad", "6ad", "7ad",
+  "8ad", "9ad", "aad", "bad", "cad", "dad", "ead", "fad",
+  "0bd", "1bd", "2bd", "3bd", "4bd", "5bd", "6bd", "7bd",
+  "8bd", "9bd", "abd", "bbd", "cbd", "dbd", "ebd", "fbd",
+  "0cd", "1cd", "2cd", "3cd", "4cd", "5cd", "6cd", "7cd",
+  "8cd", "9cd", "acd", "bcd", "ccd", "dcd", "ecd", "fcd",
+  "0dd", "1dd", "2dd", "3dd", "4dd", "5dd", "6dd", "7dd",
+  "8dd", "9dd", "add", "bdd", "cdd", "ddd", "edd", "fdd",
+  "0ed", "1ed", "2ed", "3ed", "4ed", "5ed", "6ed", "7ed",
+  "8ed", "9ed", "aed", "bed", "ced", "ded", "eed", "fed",
+  "0fd", "1fd", "2fd", "3fd", "4fd", "5fd", "6fd", "7fd",
+  "8fd", "9fd", "afd", "bfd", "cfd", "dfd", "efd", "ffd",
+  "00e", "10e", "20e", "30e", "40e", "50e", "60e", "70e",
+  "80e", "90e", "a0e", "b0e", "c0e", "d0e", "e0e", "f0e",
+  "01e", "11e", "21e", "31e", "41e", "51e", "61e", "71e",
+  "81e", "91e", "a1e", "b1e", "c1e", "d1e", "e1e", "f1e",
+  "02e", "12e", "22e", "32e", "42e", "52e", "62e", "72e",
+  "82e", "92e", "a2e", "b2e", "c2e", "d2e", "e2e", "f2e",
+  "03e", "13e", "23e", "33e", "43e", "53e", "63e", "73e",
+  "83e", "93e", "a3e", "b3e", "c3e", "d3e", "e3e", "f3e",
+  "04e", "14e", "24e", "34e", "44e", "54e", "64e", "74e",
+  "84e", "94e", "a4e", "b4e", "c4e", "d4e", "e4e", "f4e",
+  "05e", "15e", "25e", "35e", "45e", "55e", "65e", "75e",
+  "85e", "95e", "a5e", "b5e", "c5e", "d5e", "e5e", "f5e",
+  "06e", "16e", "26e", "36e", "46e", "56e", "66e", "76e",
+  "86e", "96e", "a6e", "b6e", "c6e", "d6e", "e6e", "f6e",
+  "07e", "17e", "27e", "37e", "47e", "57e", "67e", "77e",
+  "87e", "97e", "a7e", "b7e", "c7e", "d7e", "e7e", "f7e",
+  "08e", "18e", "28e", "38e", "48e", "58e", "68e", "78e",
+  "88e", "98e", "a8e", "b8e", "c8e", "d8e", "e8e", "f8e",
+  "09e", "19e", "29e", "39e", "49e", "59e", "69e", "79e",
+  "89e", "99e", "a9e", "b9e", "c9e", "d9e", "e9e", "f9e",
+  "0ae", "1ae", "2ae", "3ae", "4ae", "5ae", "6ae", "7ae",
+  "8ae", "9ae", "aae", "bae", "cae", "dae", "eae", "fae",
+  "0be", "1be", "2be", "3be", "4be", "5be", "6be", "7be",
+  "8be", "9be", "abe", "bbe", "cbe", "dbe", "ebe", "fbe",
+  "0ce", "1ce", "2ce", "3ce", "4ce", "5ce", "6ce", "7ce",
+  "8ce", "9ce", "ace", "bce", "cce", "dce", "ece", "fce",
+  "0de", "1de", "2de", "3de", "4de", "5de", "6de", "7de",
+  "8de", "9de", "ade", "bde", "cde", "dde", "ede", "fde",
+  "0ee", "1ee", "2ee", "3ee", "4ee", "5ee", "6ee", "7ee",
+  "8ee", "9ee", "aee", "bee", "cee", "dee", "eee", "fee",
+  "0fe", "1fe", "2fe", "3fe", "4fe", "5fe", "6fe", "7fe",
+  "8fe", "9fe", "afe", "bfe", "cfe", "dfe", "efe", "ffe",
+  "00f", "10f", "20f", "30f", "40f", "50f", "60f", "70f",
+  "80f", "90f", "a0f", "b0f", "c0f", "d0f", "e0f", "f0f",
+  "01f", "11f", "21f", "31f", "41f", "51f", "61f", "71f",
+  "81f", "91f", "a1f", "b1f", "c1f", "d1f", "e1f", "f1f",
+  "02f", "12f", "22f", "32f", "42f", "52f", "62f", "72f",
+  "82f", "92f", "a2f", "b2f", "c2f", "d2f", "e2f", "f2f",
+  "03f", "13f", "23f", "33f", "43f", "53f", "63f", "73f",
+  "83f", "93f", "a3f", "b3f", "c3f", "d3f", "e3f", "f3f",
+  "04f", "14f", "24f", "34f", "44f", "54f", "64f", "74f",
+  "84f", "94f", "a4f", "b4f", "c4f", "d4f", "e4f", "f4f",
+  "05f", "15f", "25f", "35f", "45f", "55f", "65f", "75f",
+  "85f", "95f", "a5f", "b5f", "c5f", "d5f", "e5f", "f5f",
+  "06f", "16f", "26f", "36f", "46f", "56f", "66f", "76f",
+  "86f", "96f", "a6f", "b6f", "c6f", "d6f", "e6f", "f6f",
+  "07f", "17f", "27f", "37f", "47f", "57f", "67f", "77f",
+  "87f", "97f", "a7f", "b7f", "c7f", "d7f", "e7f", "f7f",
+  "08f", "18f", "28f", "38f", "48f", "58f", "68f", "78f",
+  "88f", "98f", "a8f", "b8f", "c8f", "d8f", "e8f", "f8f",
+  "09f", "19f", "29f", "39f", "49f", "59f", "69f", "79f",
+  "89f", "99f", "a9f", "b9f", "c9f", "d9f", "e9f", "f9f",
+  "0af", "1af", "2af", "3af", "4af", "5af", "6af", "7af",
+  "8af", "9af", "aaf", "baf", "caf", "daf", "eaf", "faf",
+  "0bf", "1bf", "2bf", "3bf", "4bf", "5bf", "6bf", "7bf",
+  "8bf", "9bf", "abf", "bbf", "cbf", "dbf", "ebf", "fbf",
+  "0cf", "1cf", "2cf", "3cf", "4cf", "5cf", "6cf", "7cf",
+  "8cf", "9cf", "acf", "bcf", "ccf", "dcf", "ecf", "fcf",
+  "0df", "1df", "2df", "3df", "4df", "5df", "6df", "7df",
+  "8df", "9df", "adf", "bdf", "cdf", "ddf", "edf", "fdf",
+  "0ef", "1ef", "2ef", "3ef", "4ef", "5ef", "6ef", "7ef",
+  "8ef", "9ef", "aef", "bef", "cef", "def", "eef", "fef",
+  "0ff", "1ff", "2ff", "3ff", "4ff", "5ff", "6ff", "7ff",
+  "8ff", "9ff", "aff", "bff", "cff", "dff", "eff", "fff"
+};
+
+/** string table for upper-case hexadecimal values */
+static char *HEX[] = {
+     "",   "1",   "2",   "3",   "4",   "5",   "6",   "7",
+    "8",   "9",   "A",   "B",   "C",   "D",   "E",   "F",
+   "01",  "11",  "21",  "31",  "41",  "51",  "61",  "71",
+   "81",  "91",  "A1",  "B1",  "C1",  "D1",  "E1",  "F1",
+   "02",  "12",  "22",  "32",  "42",  "52",  "62",  "72",
+   "82",  "92",  "A2",  "B2",  "C2",  "D2",  "E2",  "F2",
+   "03",  "13",  "23",  "33",  "43",  "53",  "63",  "73",
+   "83",  "93",  "A3",  "B3",  "C3",  "D3",  "E3",  "F3",
+   "04",  "14",  "24",  "34",  "44",  "54",  "64",  "74",
+   "84",  "94",  "A4",  "B4",  "C4",  "D4",  "E4",  "F4",
+   "05",  "15",  "25",  "35",  "45",  "55",  "65",  "75",
+   "85",  "95",  "A5",  "B5",  "C5",  "D5",  "E5",  "F5",
+   "06",  "16",  "26",  "36",  "46",  "56",  "66",  "76",
+   "86",  "96",  "A6",  "B6",  "C6",  "D6",  "E6",  "F6",
+   "07",  "17",  "27",  "37",  "47",  "57",  "67",  "77",
+   "87",  "97",  "A7",  "B7",  "C7",  "D7",  "E7",  "F7",
+   "08",  "18",  "28",  "38",  "48",  "58",  "68",  "78",
+   "88",  "98",  "A8",  "B8",  "C8",  "D8",  "E8",  "F8",
+   "09",  "19",  "29",  "39",  "49",  "59",  "69",  "79",
+   "89",  "99",  "A9",  "B9",  "C9",  "D9",  "E9",  "F9",
+   "0A",  "1A",  "2A",  "3A",  "4A",  "5A",  "6A",  "7A",
+   "8A",  "9A",  "AA",  "BA",  "CA",  "DA",  "EA",  "FA",
+   "0B",  "1B",  "2B",  "3B",  "4B",  "5B",  "6B",  "7B",
+   "8B",  "9B",  "AB",  "BB",  "CB",  "DB",  "EB",  "FB",
+   "0C",  "1C",  "2C",  "3C",  "4C",  "5C",  "6C",  "7C",
+   "8C",  "9C",  "AC",  "BC",  "CC",  "DC",  "EC",  "FC",
+   "0D",  "1D",  "2D",  "3D",  "4D",  "5D",  "6D",  "7D",
+   "8D",  "9D",  "AD",  "BD",  "CD",  "DD",  "ED",  "FD",
+   "0E",  "1E",  "2E",  "3E",  "4E",  "5E",  "6E",  "7E",
+   "8E",  "9E",  "AE",  "BE",  "CE",  "DE",  "EE",  "FE",
+   "0F",  "1F",  "2F",  "3F",  "4F",  "5F",  "6F",  "7F",
+   "8F",  "9F",  "AF",  "BF",  "CF",  "DF",  "EF",  "FF",
+  "001", "101", "201", "301", "401", "501", "601", "701",
+  "801", "901", "A01", "B01", "C01", "D01", "E01", "F01",
+  "011", "111", "211", "311", "411", "511", "611", "711",
+  "811", "911", "A11", "B11", "C11", "D11", "E11", "F11",
+  "021", "121", "221", "321", "421", "521", "621", "721",
+  "821", "921", "A21", "B21", "C21", "D21", "E21", "F21",
+  "031", "131", "231", "331", "431", "531", "631", "731",
+  "831", "931", "A31", "B31", "C31", "D31", "E31", "F31",
+  "041", "141", "241", "341", "441", "541", "641", "741",
+  "841", "941", "A41", "B41", "C41", "D41", "E41", "F41",
+  "051", "151", "251", "351", "451", "551", "651", "751",
+  "851", "951", "A51", "B51", "C51", "D51", "E51", "F51",
+  "061", "161", "261", "361", "461", "561", "661", "761",
+  "861", "961", "A61", "B61", "C61", "D61", "E61", "F61",
+  "071", "171", "271", "371", "471", "571", "671", "771",
+  "871", "971", "A71", "B71", "C71", "D71", "E71", "F71",
+  "081", "181", "281", "381", "481", "581", "681", "781",
+  "881", "981", "A81", "B81", "C81", "D81", "E81", "F81",
+  "091", "191", "291", "391", "491", "591", "691", "791",
+  "891", "991", "A91", "B91", "C91", "D91", "E91", "F91",
+  "0A1", "1A1", "2A1", "3A1", "4A1", "5A1", "6A1", "7A1",
+  "8A1", "9A1", "AA1", "BA1", "CA1", "DA1", "EA1", "FA1",
+  "0B1", "1B1", "2B1", "3B1", "4B1", "5B1", "6B1", "7B1",
+  "8B1", "9B1", "AB1", "BB1", "CB1", "DB1", "EB1", "FB1",
+  "0C1", "1C1", "2C1", "3C1", "4C1", "5C1", "6C1", "7C1",
+  "8C1", "9C1", "AC1", "BC1", "CC1", "DC1", "EC1", "FC1",
+  "0D1", "1D1", "2D1", "3D1", "4D1", "5D1", "6D1", "7D1",
+  "8D1", "9D1", "AD1", "BD1", "CD1", "DD1", "ED1", "FD1",
+  "0E1", "1E1", "2E1", "3E1", "4E1", "5E1", "6E1", "7E1",
+  "8E1", "9E1", "AE1", "BE1", "CE1", "DE1", "EE1", "FE1",
+  "0F1", "1F1", "2F1", "3F1", "4F1", "5F1", "6F1", "7F1",
+  "8F1", "9F1", "AF1", "BF1", "CF1", "DF1", "EF1", "FF1",
+  "002", "102", "202", "302", "402", "502", "602", "702",
+  "802", "902", "A02", "B02", "C02", "D02", "E02", "F02",
+  "012", "112", "212", "312", "412", "512", "612", "712",
+  "812", "912", "A12", "B12", "C12", "D12", "E12", "F12",
+  "022", "122", "222", "322", "422", "522", "622", "722",
+  "822", "922", "A22", "B22", "C22", "D22", "E22", "F22",
+  "032", "132", "232", "332", "432", "532", "632", "732",
+  "832", "932", "A32", "B32", "C32", "D32", "E32", "F32",
+  "042", "142", "242", "342", "442", "542", "642", "742",
+  "842", "942", "A42", "B42", "C42", "D42", "E42", "F42",
+  "052", "152", "252", "352", "452", "552", "652", "752",
+  "852", "952", "A52", "B52", "C52", "D52", "E52", "F52",
+  "062", "162", "262", "362", "462", "562", "662", "762",
+  "862", "962", "A62", "B62", "C62", "D62", "E62", "F62",
+  "072", "172", "272", "372", "472", "572", "672", "772",
+  "872", "972", "A72", "B72", "C72", "D72", "E72", "F72",
+  "082", "182", "282", "382", "482", "582", "682", "782",
+  "882", "982", "A82", "B82", "C82", "D82", "E82", "F82",
+  "092", "192", "292", "392", "492", "592", "692", "792",
+  "892", "992", "A92", "B92", "C92", "D92", "E92", "F92",
+  "0A2", "1A2", "2A2", "3A2", "4A2", "5A2", "6A2", "7A2",
+  "8A2", "9A2", "AA2", "BA2", "CA2", "DA2", "EA2", "FA2",
+  "0B2", "1B2", "2B2", "3B2", "4B2", "5B2", "6B2", "7B2",
+  "8B2", "9B2", "AB2", "BB2", "CB2", "DB2", "EB2", "FB2",
+  "0C2", "1C2", "2C2", "3C2", "4C2", "5C2", "6C2", "7C2",
+  "8C2", "9C2", "AC2", "BC2", "CC2", "DC2", "EC2", "FC2",
+  "0D2", "1D2", "2D2", "3D2", "4D2", "5D2", "6D2", "7D2",
+  "8D2", "9D2", "AD2", "BD2", "CD2", "DD2", "ED2", "FD2",
+  "0E2", "1E2", "2E2", "3E2", "4E2", "5E2", "6E2", "7E2",
+  "8E2", "9E2", "AE2", "BE2", "CE2", "DE2", "EE2", "FE2",
+  "0F2", "1F2", "2F2", "3F2", "4F2", "5F2", "6F2", "7F2",
+  "8F2", "9F2", "AF2", "BF2", "CF2", "DF2", "EF2", "FF2",
+  "003", "103", "203", "303", "403", "503", "603", "703",
+  "803", "903", "A03", "B03", "C03", "D03", "E03", "F03",
+  "013", "113", "213", "313", "413", "513", "613", "713",
+  "813", "913", "A13", "B13", "C13", "D13", "E13", "F13",
+  "023", "123", "223", "323", "423", "523", "623", "723",
+  "823", "923", "A23", "B23", "C23", "D23", "E23", "F23",
+  "033", "133", "233", "333", "433", "533", "633", "733",
+  "833", "933", "A33", "B33", "C33", "D33", "E33", "F33",
+  "043", "143", "243", "343", "443", "543", "643", "743",
+  "843", "943", "A43", "B43", "C43", "D43", "E43", "F43",
+  "053", "153", "253", "353", "453", "553", "653", "753",
+  "853", "953", "A53", "B53", "C53", "D53", "E53", "F53",
+  "063", "163", "263", "363", "463", "563", "663", "763",
+  "863", "963", "A63", "B63", "C63", "D63", "E63", "F63",
+  "073", "173", "273", "373", "473", "573", "673", "773",
+  "873", "973", "A73", "B73", "C73", "D73", "E73", "F73",
+  "083", "183", "283", "383", "483", "583", "683", "783",
+  "883", "983", "A83", "B83", "C83", "D83", "E83", "F83",
+  "093", "193", "293", "393", "493", "593", "693", "793",
+  "893", "993", "A93", "B93", "C93", "D93", "E93", "F93",
+  "0A3", "1A3", "2A3", "3A3", "4A3", "5A3", "6A3", "7A3",
+  "8A3", "9A3", "AA3", "BA3", "CA3", "DA3", "EA3", "FA3",
+  "0B3", "1B3", "2B3", "3B3", "4B3", "5B3", "6B3", "7B3",
+  "8B3", "9B3", "AB3", "BB3", "CB3", "DB3", "EB3", "FB3",
+  "0C3", "1C3", "2C3", "3C3", "4C3", "5C3", "6C3", "7C3",
+  "8C3", "9C3", "AC3", "BC3", "CC3", "DC3", "EC3", "FC3",
+  "0D3", "1D3", "2D3", "3D3", "4D3", "5D3", "6D3", "7D3",
+  "8D3", "9D3", "AD3", "BD3", "CD3", "DD3", "ED3", "FD3",
+  "0E3", "1E3", "2E3", "3E3", "4E3", "5E3", "6E3", "7E3",
+  "8E3", "9E3", "AE3", "BE3", "CE3", "DE3", "EE3", "FE3",
+  "0F3", "1F3", "2F3", "3F3", "4F3", "5F3", "6F3", "7F3",
+  "8F3", "9F3", "AF3", "BF3", "CF3", "DF3", "EF3", "FF3",
+  "004", "104", "204", "304", "404", "504", "604", "704",
+  "804", "904", "A04", "B04", "C04", "D04", "E04", "F04",
+  "014", "114", "214", "314", "414", "514", "614", "714",
+  "814", "914", "A14", "B14", "C14", "D14", "E14", "F14",
+  "024", "124", "224", "324", "424", "524", "624", "724",
+  "824", "924", "A24", "B24", "C24", "D24", "E24", "F24",
+  "034", "134", "234", "334", "434", "534", "634", "734",
+  "834", "934", "A34", "B34", "C34", "D34", "E34", "F34",
+  "044", "144", "244", "344", "444", "544", "644", "744",
+  "844", "944", "A44", "B44", "C44", "D44", "E44", "F44",
+  "054", "154", "254", "354", "454", "554", "654", "754",
+  "854", "954", "A54", "B54", "C54", "D54", "E54", "F54",
+  "064", "164", "264", "364", "464", "564", "664", "764",
+  "864", "964", "A64", "B64", "C64", "D64", "E64", "F64",
+  "074", "174", "274", "374", "474", "574", "674", "774",
+  "874", "974", "A74", "B74", "C74", "D74", "E74", "F74",
+  "084", "184", "284", "384", "484", "584", "684", "784",
+  "884", "984", "A84", "B84", "C84", "D84", "E84", "F84",
+  "094", "194", "294", "394", "494", "594", "694", "794",
+  "894", "994", "A94", "B94", "C94", "D94", "E94", "F94",
+  "0A4", "1A4", "2A4", "3A4", "4A4", "5A4", "6A4", "7A4",
+  "8A4", "9A4", "AA4", "BA4", "CA4", "DA4", "EA4", "FA4",
+  "0B4", "1B4", "2B4", "3B4", "4B4", "5B4", "6B4", "7B4",
+  "8B4", "9B4", "AB4", "BB4", "CB4", "DB4", "EB4", "FB4",
+  "0C4", "1C4", "2C4", "3C4", "4C4", "5C4", "6C4", "7C4",
+  "8C4", "9C4", "AC4", "BC4", "CC4", "DC4", "EC4", "FC4",
+  "0D4", "1D4", "2D4", "3D4", "4D4", "5D4", "6D4", "7D4",
+  "8D4", "9D4", "AD4", "BD4", "CD4", "DD4", "ED4", "FD4",
+  "0E4", "1E4", "2E4", "3E4", "4E4", "5E4", "6E4", "7E4",
+  "8E4", "9E4", "AE4", "BE4", "CE4", "DE4", "EE4", "FE4",
+  "0F4", "1F4", "2F4", "3F4", "4F4", "5F4", "6F4", "7F4",
+  "8F4", "9F4", "AF4", "BF4", "CF4", "DF4", "EF4", "FF4",
+  "005", "105", "205", "305", "405", "505", "605", "705",
+  "805", "905", "A05", "B05", "C05", "D05", "E05", "F05",
+  "015", "115", "215", "315", "415", "515", "615", "715",
+  "815", "915", "A15", "B15", "C15", "D15", "E15", "F15",
+  "025", "125", "225", "325", "425", "525", "625", "725",
+  "825", "925", "A25", "B25", "C25", "D25", "E25", "F25",
+  "035", "135", "235", "335", "435", "535", "635", "735",
+  "835", "935", "A35", "B35", "C35", "D35", "E35", "F35",
+  "045", "145", "245", "345", "445", "545", "645", "745",
+  "845", "945", "A45", "B45", "C45", "D45", "E45", "F45",
+  "055", "155", "255", "355", "455", "555", "655", "755",
+  "855", "955", "A55", "B55", "C55", "D55", "E55", "F55",
+  "065", "165", "265", "365", "465", "565", "665", "765",
+  "865", "965", "A65", "B65", "C65", "D65", "E65", "F65",
+  "075", "175", "275", "375", "475", "575", "675", "775",
+  "875", "975", "A75", "B75", "C75", "D75", "E75", "F75",
+  "085", "185", "285", "385", "485", "585", "685", "785",
+  "885", "985", "A85", "B85", "C85", "D85", "E85", "F85",
+  "095", "195", "295", "395", "495", "595", "695", "795",
+  "895", "995", "A95", "B95", "C95", "D95", "E95", "F95",
+  "0A5", "1A5", "2A5", "3A5", "4A5", "5A5", "6A5", "7A5",
+  "8A5", "9A5", "AA5", "BA5", "CA5", "DA5", "EA5", "FA5",
+  "0B5", "1B5", "2B5", "3B5", "4B5", "5B5", "6B5", "7B5",
+  "8B5", "9B5", "AB5", "BB5", "CB5", "DB5", "EB5", "FB5",
+  "0C5", "1C5", "2C5", "3C5", "4C5", "5C5", "6C5", "7C5",
+  "8C5", "9C5", "AC5", "BC5", "CC5", "DC5", "EC5", "FC5",
+  "0D5", "1D5", "2D5", "3D5", "4D5", "5D5", "6D5", "7D5",
+  "8D5", "9D5", "AD5", "BD5", "CD5", "DD5", "ED5", "FD5",
+  "0E5", "1E5", "2E5", "3E5", "4E5", "5E5", "6E5", "7E5",
+  "8E5", "9E5", "AE5", "BE5", "CE5", "DE5", "EE5", "FE5",
+  "0F5", "1F5", "2F5", "3F5", "4F5", "5F5", "6F5", "7F5",
+  "8F5", "9F5", "AF5", "BF5", "CF5", "DF5", "EF5", "FF5",
+  "006", "106", "206", "306", "406", "506", "606", "706",
+  "806", "906", "A06", "B06", "C06", "D06", "E06", "F06",
+  "016", "116", "216", "316", "416", "516", "616", "716",
+  "816", "916", "A16", "B16", "C16", "D16", "E16", "F16",
+  "026", "126", "226", "326", "426", "526", "626", "726",
+  "826", "926", "A26", "B26", "C26", "D26", "E26", "F26",
+  "036", "136", "236", "336", "436", "536", "636", "736",
+  "836", "936", "A36", "B36", "C36", "D36", "E36", "F36",
+  "046", "146", "246", "346", "446", "546", "646", "746",
+  "846", "946", "A46", "B46", "C46", "D46", "E46", "F46",
+  "056", "156", "256", "356", "456", "556", "656", "756",
+  "856", "956", "A56", "B56", "C56", "D56", "E56", "F56",
+  "066", "166", "266", "366", "466", "566", "666", "766",
+  "866", "966", "A66", "B66", "C66", "D66", "E66", "F66",
+  "076", "176", "276", "376", "476", "576", "676", "776",
+  "876", "976", "A76", "B76", "C76", "D76", "E76", "F76",
+  "086", "186", "286", "386", "486", "586", "686", "786",
+  "886", "986", "A86", "B86", "C86", "D86", "E86", "F86",
+  "096", "196", "296", "396", "496", "596", "696", "796",
+  "896", "996", "A96", "B96", "C96", "D96", "E96", "F96",
+  "0A6", "1A6", "2A6", "3A6", "4A6", "5A6", "6A6", "7A6",
+  "8A6", "9A6", "AA6", "BA6", "CA6", "DA6", "EA6", "FA6",
+  "0B6", "1B6", "2B6", "3B6", "4B6", "5B6", "6B6", "7B6",
+  "8B6", "9B6", "AB6", "BB6", "CB6", "DB6", "EB6", "FB6",
+  "0C6", "1C6", "2C6", "3C6", "4C6", "5C6", "6C6", "7C6",
+  "8C6", "9C6", "AC6", "BC6", "CC6", "DC6", "EC6", "FC6",
+  "0D6", "1D6", "2D6", "3D6", "4D6", "5D6", "6D6", "7D6",
+  "8D6", "9D6", "AD6", "BD6", "CD6", "DD6", "ED6", "FD6",
+  "0E6", "1E6", "2E6", "3E6", "4E6", "5E6", "6E6", "7E6",
+  "8E6", "9E6", "AE6", "BE6", "CE6", "DE6", "EE6", "FE6",
+  "0F6", "1F6", "2F6", "3F6", "4F6", "5F6", "6F6", "7F6",
+  "8F6", "9F6", "AF6", "BF6", "CF6", "DF6", "EF6", "FF6",
+  "007", "107", "207", "307", "407", "507", "607", "707",
+  "807", "907", "A07", "B07", "C07", "D07", "E07", "F07",
+  "017", "117", "217", "317", "417", "517", "617", "717",
+  "817", "917", "A17", "B17", "C17", "D17", "E17", "F17",
+  "027", "127", "227", "327", "427", "527", "627", "727",
+  "827", "927", "A27", "B27", "C27", "D27", "E27", "F27",
+  "037", "137", "237", "337", "437", "537", "637", "737",
+  "837", "937", "A37", "B37", "C37", "D37", "E37", "F37",
+  "047", "147", "247", "347", "447", "547", "647", "747",
+  "847", "947", "A47", "B47", "C47", "D47", "E47", "F47",
+  "057", "157", "257", "357", "457", "557", "657", "757",
+  "857", "957", "A57", "B57", "C57", "D57", "E57", "F57",
+  "067", "167", "267", "367", "467", "567", "667", "767",
+  "867", "967", "A67", "B67", "C67", "D67", "E67", "F67",
+  "077", "177", "277", "377", "477", "577", "677", "777",
+  "877", "977", "A77", "B77", "C77", "D77", "E77", "F77",
+  "087", "187", "287", "387", "487", "587", "687", "787",
+  "887", "987", "A87", "B87", "C87", "D87", "E87", "F87",
+  "097", "197", "297", "397", "497", "597", "697", "797",
+  "897", "997", "A97", "B97", "C97", "D97", "E97", "F97",
+  "0A7", "1A7", "2A7", "3A7", "4A7", "5A7", "6A7", "7A7",
+  "8A7", "9A7", "AA7", "BA7", "CA7", "DA7", "EA7", "FA7",
+  "0B7", "1B7", "2B7", "3B7", "4B7", "5B7", "6B7", "7B7",
+  "8B7", "9B7", "AB7", "BB7", "CB7", "DB7", "EB7", "FB7",
+  "0C7", "1C7", "2C7", "3C7", "4C7", "5C7", "6C7", "7C7",
+  "8C7", "9C7", "AC7", "BC7", "CC7", "DC7", "EC7", "FC7",
+  "0D7", "1D7", "2D7", "3D7", "4D7", "5D7", "6D7", "7D7",
+  "8D7", "9D7", "AD7", "BD7", "CD7", "DD7", "ED7", "FD7",
+  "0E7", "1E7", "2E7", "3E7", "4E7", "5E7", "6E7", "7E7",
+  "8E7", "9E7", "AE7", "BE7", "CE7", "DE7", "EE7", "FE7",
+  "0F7", "1F7", "2F7", "3F7", "4F7", "5F7", "6F7", "7F7",
+  "8F7", "9F7", "AF7", "BF7", "CF7", "DF7", "EF7", "FF7",
+  "008", "108", "208", "308", "408", "508", "608", "708",
+  "808", "908", "A08", "B08", "C08", "D08", "E08", "F08",
+  "018", "118", "218", "318", "418", "518", "618", "718",
+  "818", "918", "A18", "B18", "C18", "D18", "E18", "F18",
+  "028", "128", "228", "328", "428", "528", "628", "728",
+  "828", "928", "A28", "B28", "C28", "D28", "E28", "F28",
+  "038", "138", "238", "338", "438", "538", "638", "738",
+  "838", "938", "A38", "B38", "C38", "D38", "E38", "F38",
+  "048", "148", "248", "348", "448", "548", "648", "748",
+  "848", "948", "A48", "B48", "C48", "D48", "E48", "F48",
+  "058", "158", "258", "358", "458", "558", "658", "758",
+  "858", "958", "A58", "B58", "C58", "D58", "E58", "F58",
+  "068", "168", "268", "368", "468", "568", "668", "768",
+  "868", "968", "A68", "B68", "C68", "D68", "E68", "F68",
+  "078", "178", "278", "378", "478", "578", "678", "778",
+  "878", "978", "A78", "B78", "C78", "D78", "E78", "F78",
+  "088", "188", "288", "388", "488", "588", "688", "788",
+  "888", "988", "A88", "B88", "C88", "D88", "E88", "F88",
+  "098", "198", "298", "398", "498", "598", "698", "798",
+  "898", "998", "A98", "B98", "C98", "D98", "E98", "F98",
+  "0A8", "1A8", "2A8", "3A8", "4A8", "5A8", "6A8", "7A8",
+  "8A8", "9A8", "AA8", "BA8", "CA8", "DA8", "EA8", "FA8",
+  "0B8", "1B8", "2B8", "3B8", "4B8", "5B8", "6B8", "7B8",
+  "8B8", "9B8", "AB8", "BB8", "CB8", "DB8", "EB8", "FB8",
+  "0C8", "1C8", "2C8", "3C8", "4C8", "5C8", "6C8", "7C8",
+  "8C8", "9C8", "AC8", "BC8", "CC8", "DC8", "EC8", "FC8",
+  "0D8", "1D8", "2D8", "3D8", "4D8", "5D8", "6D8", "7D8",
+  "8D8", "9D8", "AD8", "BD8", "CD8", "DD8", "ED8", "FD8",
+  "0E8", "1E8", "2E8", "3E8", "4E8", "5E8", "6E8", "7E8",
+  "8E8", "9E8", "AE8", "BE8", "CE8", "DE8", "EE8", "FE8",
+  "0F8", "1F8", "2F8", "3F8", "4F8", "5F8", "6F8", "7F8",
+  "8F8", "9F8", "AF8", "BF8", "CF8", "DF8", "EF8", "FF8",
+  "009", "109", "209", "309", "409", "509", "609", "709",
+  "809", "909", "A09", "B09", "C09", "D09", "E09", "F09",
+  "019", "119", "219", "319", "419", "519", "619", "719",
+  "819", "919", "A19", "B19", "C19", "D19", "E19", "F19",
+  "029", "129", "229", "329", "429", "529", "629", "729",
+  "829", "929", "A29", "B29", "C29", "D29", "E29", "F29",
+  "039", "139", "239", "339", "439", "539", "639", "739",
+  "839", "939", "A39", "B39", "C39", "D39", "E39", "F39",
+  "049", "149", "249", "349", "449", "549", "649", "749",
+  "849", "949", "A49", "B49", "C49", "D49", "E49", "F49",
+  "059", "159", "259", "359", "459", "559", "659", "759",
+  "859", "959", "A59", "B59", "C59", "D59", "E59", "F59",
+  "069", "169", "269", "369", "469", "569", "669", "769",
+  "869", "969", "A69", "B69", "C69", "D69", "E69", "F69",
+  "079", "179", "279", "379", "479", "579", "679", "779",
+  "879", "979", "A79", "B79", "C79", "D79", "E79", "F79",
+  "089", "189", "289", "389", "489", "589", "689", "789",
+  "889", "989", "A89", "B89", "C89", "D89", "E89", "F89",
+  "099", "199", "299", "399", "499", "599", "699", "799",
+  "899", "999", "A99", "B99", "C99", "D99", "E99", "F99",
+  "0A9", "1A9", "2A9", "3A9", "4A9", "5A9", "6A9", "7A9",
+  "8A9", "9A9", "AA9", "BA9", "CA9", "DA9", "EA9", "FA9",
+  "0B9", "1B9", "2B9", "3B9", "4B9", "5B9", "6B9", "7B9",
+  "8B9", "9B9", "AB9", "BB9", "CB9", "DB9", "EB9", "FB9",
+  "0C9", "1C9", "2C9", "3C9", "4C9", "5C9", "6C9", "7C9",
+  "8C9", "9C9", "AC9", "BC9", "CC9", "DC9", "EC9", "FC9",
+  "0D9", "1D9", "2D9", "3D9", "4D9", "5D9", "6D9", "7D9",
+  "8D9", "9D9", "AD9", "BD9", "CD9", "DD9", "ED9", "FD9",
+  "0E9", "1E9", "2E9", "3E9", "4E9", "5E9", "6E9", "7E9",
+  "8E9", "9E9", "AE9", "BE9", "CE9", "DE9", "EE9", "FE9",
+  "0F9", "1F9", "2F9", "3F9", "4F9", "5F9", "6F9", "7F9",
+  "8F9", "9F9", "AF9", "BF9", "CF9", "DF9", "EF9", "FF9",
+  "00A", "10A", "20A", "30A", "40A", "50A", "60A", "70A",
+  "80A", "90A", "A0A", "B0A", "C0A", "D0A", "E0A", "F0A",
+  "01A", "11A", "21A", "31A", "41A", "51A", "61A", "71A",
+  "81A", "91A", "A1A", "B1A", "C1A", "D1A", "E1A", "F1A",
+  "02A", "12A", "22A", "32A", "42A", "52A", "62A", "72A",
+  "82A", "92A", "A2A", "B2A", "C2A", "D2A", "E2A", "F2A",
+  "03A", "13A", "23A", "33A", "43A", "53A", "63A", "73A",
+  "83A", "93A", "A3A", "B3A", "C3A", "D3A", "E3A", "F3A",
+  "04A", "14A", "24A", "34A", "44A", "54A", "64A", "74A",
+  "84A", "94A", "A4A", "B4A", "C4A", "D4A", "E4A", "F4A",
+  "05A", "15A", "25A", "35A", "45A", "55A", "65A", "75A",
+  "85A", "95A", "A5A", "B5A", "C5A", "D5A", "E5A", "F5A",
+  "06A", "16A", "26A", "36A", "46A", "56A", "66A", "76A",
+  "86A", "96A", "A6A", "B6A", "C6A", "D6A", "E6A", "F6A",
+  "07A", "17A", "27A", "37A", "47A", "57A", "67A", "77A",
+  "87A", "97A", "A7A", "B7A", "C7A", "D7A", "E7A", "F7A",
+  "08A", "18A", "28A", "38A", "48A", "58A", "68A", "78A",
+  "88A", "98A", "A8A", "B8A", "C8A", "D8A", "E8A", "F8A",
+  "09A", "19A", "29A", "39A", "49A", "59A", "69A", "79A",
+  "89A", "99A", "A9A", "B9A", "C9A", "D9A", "E9A", "F9A",
+  "0AA", "1AA", "2AA", "3AA", "4AA", "5AA", "6AA", "7AA",
+  "8AA", "9AA", "AAA", "BAA", "CAA", "DAA", "EAA", "FAA",
+  "0BA", "1BA", "2BA", "3BA", "4BA", "5BA", "6BA", "7BA",
+  "8BA", "9BA", "ABA", "BBA", "CBA", "DBA", "EBA", "FBA",
+  "0CA", "1CA", "2CA", "3CA", "4CA", "5CA", "6CA", "7CA",
+  "8CA", "9CA", "ACA", "BCA", "CCA", "DCA", "ECA", "FCA",
+  "0DA", "1DA", "2DA", "3DA", "4DA", "5DA", "6DA", "7DA",
+  "8DA", "9DA", "ADA", "BDA", "CDA", "DDA", "EDA", "FDA",
+  "0EA", "1EA", "2EA", "3EA", "4EA", "5EA", "6EA", "7EA",
+  "8EA", "9EA", "AEA", "BEA", "CEA", "DEA", "EEA", "FEA",
+  "0FA", "1FA", "2FA", "3FA", "4FA", "5FA", "6FA", "7FA",
+  "8FA", "9FA", "AFA", "BFA", "CFA", "DFA", "EFA", "FFA",
+  "00B", "10B", "20B", "30B", "40B", "50B", "60B", "70B",
+  "80B", "90B", "A0B", "B0B", "C0B", "D0B", "E0B", "F0B",
+  "01B", "11B", "21B", "31B", "41B", "51B", "61B", "71B",
+  "81B", "91B", "A1B", "B1B", "C1B", "D1B", "E1B", "F1B",
+  "02B", "12B", "22B", "32B", "42B", "52B", "62B", "72B",
+  "82B", "92B", "A2B", "B2B", "C2B", "D2B", "E2B", "F2B",
+  "03B", "13B", "23B", "33B", "43B", "53B", "63B", "73B",
+  "83B", "93B", "A3B", "B3B", "C3B", "D3B", "E3B", "F3B",
+  "04B", "14B", "24B", "34B", "44B", "54B", "64B", "74B",
+  "84B", "94B", "A4B", "B4B", "C4B", "D4B", "E4B", "F4B",
+  "05B", "15B", "25B", "35B", "45B", "55B", "65B", "75B",
+  "85B", "95B", "A5B", "B5B", "C5B", "D5B", "E5B", "F5B",
+  "06B", "16B", "26B", "36B", "46B", "56B", "66B", "76B",
+  "86B", "96B", "A6B", "B6B", "C6B", "D6B", "E6B", "F6B",
+  "07B", "17B", "27B", "37B", "47B", "57B", "67B", "77B",
+  "87B", "97B", "A7B", "B7B", "C7B", "D7B", "E7B", "F7B",
+  "08B", "18B", "28B", "38B", "48B", "58B", "68B", "78B",
+  "88B", "98B", "A8B", "B8B", "C8B", "D8B", "E8B", "F8B",
+  "09B", "19B", "29B", "39B", "49B", "59B", "69B", "79B",
+  "89B", "99B", "A9B", "B9B", "C9B", "D9B", "E9B", "F9B",
+  "0AB", "1AB", "2AB", "3AB", "4AB", "5AB", "6AB", "7AB",
+  "8AB", "9AB", "AAB", "BAB", "CAB", "DAB", "EAB", "FAB",
+  "0BB", "1BB", "2BB", "3BB", "4BB", "5BB", "6BB", "7BB",
+  "8BB", "9BB", "ABB", "BBB", "CBB", "DBB", "EBB", "FBB",
+  "0CB", "1CB", "2CB", "3CB", "4CB", "5CB", "6CB", "7CB",
+  "8CB", "9CB", "ACB", "BCB", "CCB", "DCB", "ECB", "FCB",
+  "0DB", "1DB", "2DB", "3DB", "4DB", "5DB", "6DB", "7DB",
+  "8DB", "9DB", "ADB", "BDB", "CDB", "DDB", "EDB", "FDB",
+  "0EB", "1EB", "2EB", "3EB", "4EB", "5EB", "6EB", "7EB",
+  "8EB", "9EB", "AEB", "BEB", "CEB", "DEB", "EEB", "FEB",
+  "0FB", "1FB", "2FB", "3FB", "4FB", "5FB", "6FB", "7FB",
+  "8FB", "9FB", "AFB", "BFB", "CFB", "DFB", "EFB", "FFB",
+  "00C", "10C", "20C", "30C", "40C", "50C", "60C", "70C",
+  "80C", "90C", "A0C", "B0C", "C0C", "D0C", "E0C", "F0C",
+  "01C", "11C", "21C", "31C", "41C", "51C", "61C", "71C",
+  "81C", "91C", "A1C", "B1C", "C1C", "D1C", "E1C", "F1C",
+  "02C", "12C", "22C", "32C", "42C", "52C", "62C", "72C",
+  "82C", "92C", "A2C", "B2C", "C2C", "D2C", "E2C", "F2C",
+  "03C", "13C", "23C", "33C", "43C", "53C", "63C", "73C",
+  "83C", "93C", "A3C", "B3C", "C3C", "D3C", "E3C", "F3C",
+  "04C", "14C", "24C", "34C", "44C", "54C", "64C", "74C",
+  "84C", "94C", "A4C", "B4C", "C4C", "D4C", "E4C", "F4C",
+  "05C", "15C", "25C", "35C", "45C", "55C", "65C", "75C",
+  "85C", "95C", "A5C", "B5C", "C5C", "D5C", "E5C", "F5C",
+  "06C", "16C", "26C", "36C", "46C", "56C", "66C", "76C",
+  "86C", "96C", "A6C", "B6C", "C6C", "D6C", "E6C", "F6C",
+  "07C", "17C", "27C", "37C", "47C", "57C", "67C", "77C",
+  "87C", "97C", "A7C", "B7C", "C7C", "D7C", "E7C", "F7C",
+  "08C", "18C", "28C", "38C", "48C", "58C", "68C", "78C",
+  "88C", "98C", "A8C", "B8C", "C8C", "D8C", "E8C", "F8C",
+  "09C", "19C", "29C", "39C", "49C", "59C", "69C", "79C",
+  "89C", "99C", "A9C", "B9C", "C9C", "D9C", "E9C", "F9C",
+  "0AC", "1AC", "2AC", "3AC", "4AC", "5AC", "6AC", "7AC",
+  "8AC", "9AC", "AAC", "BAC", "CAC", "DAC", "EAC", "FAC",
+  "0BC", "1BC", "2BC", "3BC", "4BC", "5BC", "6BC", "7BC",
+  "8BC", "9BC", "ABC", "BBC", "CBC", "DBC", "EBC", "FBC",
+  "0CC", "1CC", "2CC", "3CC", "4CC", "5CC", "6CC", "7CC",
+  "8CC", "9CC", "ACC", "BCC", "CCC", "DCC", "ECC", "FCC",
+  "0DC", "1DC", "2DC", "3DC", "4DC", "5DC", "6DC", "7DC",
+  "8DC", "9DC", "ADC", "BDC", "CDC", "DDC", "EDC", "FDC",
+  "0EC", "1EC", "2EC", "3EC", "4EC", "5EC", "6EC", "7EC",
+  "8EC", "9EC", "AEC", "BEC", "CEC", "DEC", "EEC", "FEC",
+  "0FC", "1FC", "2FC", "3FC", "4FC", "5FC", "6FC", "7FC",
+  "8FC", "9FC", "AFC", "BFC", "CFC", "DFC", "EFC", "FFC",
+  "00D", "10D", "20D", "30D", "40D", "50D", "60D", "70D",
+  "80D", "90D", "A0D", "B0D", "C0D", "D0D", "E0D", "F0D",
+  "01D", "11D", "21D", "31D", "41D", "51D", "61D", "71D",
+  "81D", "91D", "A1D", "B1D", "C1D", "D1D", "E1D", "F1D",
+  "02D", "12D", "22D", "32D", "42D", "52D", "62D", "72D",
+  "82D", "92D", "A2D", "B2D", "C2D", "D2D", "E2D", "F2D",
+  "03D", "13D", "23D", "33D", "43D", "53D", "63D", "73D",
+  "83D", "93D", "A3D", "B3D", "C3D", "D3D", "E3D", "F3D",
+  "04D", "14D", "24D", "34D", "44D", "54D", "64D", "74D",
+  "84D", "94D", "A4D", "B4D", "C4D", "D4D", "E4D", "F4D",
+  "05D", "15D", "25D", "35D", "45D", "55D", "65D", "75D",
+  "85D", "95D", "A5D", "B5D", "C5D", "D5D", "E5D", "F5D",
+  "06D", "16D", "26D", "36D", "46D", "56D", "66D", "76D",
+  "86D", "96D", "A6D", "B6D", "C6D", "D6D", "E6D", "F6D",
+  "07D", "17D", "27D", "37D", "47D", "57D", "67D", "77D",
+  "87D", "97D", "A7D", "B7D", "C7D", "D7D", "E7D", "F7D",
+  "08D", "18D", "28D", "38D", "48D", "58D", "68D", "78D",
+  "88D", "98D", "A8D", "B8D", "C8D", "D8D", "E8D", "F8D",
+  "09D", "19D", "29D", "39D", "49D", "59D", "69D", "79D",
+  "89D", "99D", "A9D", "B9D", "C9D", "D9D", "E9D", "F9D",
+  "0AD", "1AD", "2AD", "3AD", "4AD", "5AD", "6AD", "7AD",
+  "8AD", "9AD", "AAD", "BAD", "CAD", "DAD", "EAD", "FAD",
+  "0BD", "1BD", "2BD", "3BD", "4BD", "5BD", "6BD", "7BD",
+  "8BD", "9BD", "ABD", "BBD", "CBD", "DBD", "EBD", "FBD",
+  "0CD", "1CD", "2CD", "3CD", "4CD", "5CD", "6CD", "7CD",
+  "8CD", "9CD", "ACD", "BCD", "CCD", "DCD", "ECD", "FCD",
+  "0DD", "1DD", "2DD", "3DD", "4DD", "5DD", "6DD", "7DD",
+  "8DD", "9DD", "ADD", "BDD", "CDD", "DDD", "EDD", "FDD",
+  "0ED", "1ED", "2ED", "3ED", "4ED", "5ED", "6ED", "7ED",
+  "8ED", "9ED", "AED", "BED", "CED", "DED", "EED", "FED",
+  "0FD", "1FD", "2FD", "3FD", "4FD", "5FD", "6FD", "7FD",
+  "8FD", "9FD", "AFD", "BFD", "CFD", "DFD", "EFD", "FFD",
+  "00E", "10E", "20E", "30E", "40E", "50E", "60E", "70E",
+  "80E", "90E", "A0E", "B0E", "C0E", "D0E", "E0E", "F0E",
+  "01E", "11E", "21E", "31E", "41E", "51E", "61E", "71E",
+  "81E", "91E", "A1E", "B1E", "C1E", "D1E", "E1E", "F1E",
+  "02E", "12E", "22E", "32E", "42E", "52E", "62E", "72E",
+  "82E", "92E", "A2E", "B2E", "C2E", "D2E", "E2E", "F2E",
+  "03E", "13E", "23E", "33E", "43E", "53E", "63E", "73E",
+  "83E", "93E", "A3E", "B3E", "C3E", "D3E", "E3E", "F3E",
+  "04E", "14E", "24E", "34E", "44E", "54E", "64E", "74E",
+  "84E", "94E", "A4E", "B4E", "C4E", "D4E", "E4E", "F4E",
+  "05E", "15E", "25E", "35E", "45E", "55E", "65E", "75E",
+  "85E", "95E", "A5E", "B5E", "C5E", "D5E", "E5E", "F5E",
+  "06E", "16E", "26E", "36E", "46E", "56E", "66E", "76E",
+  "86E", "96E", "A6E", "B6E", "C6E", "D6E", "E6E", "F6E",
+  "07E", "17E", "27E", "37E", "47E", "57E", "67E", "77E",
+  "87E", "97E", "A7E", "B7E", "C7E", "D7E", "E7E", "F7E",
+  "08E", "18E", "28E", "38E", "48E", "58E", "68E", "78E",
+  "88E", "98E", "A8E", "B8E", "C8E", "D8E", "E8E", "F8E",
+  "09E", "19E", "29E", "39E", "49E", "59E", "69E", "79E",
+  "89E", "99E", "A9E", "B9E", "C9E", "D9E", "E9E", "F9E",
+  "0AE", "1AE", "2AE", "3AE", "4AE", "5AE", "6AE", "7AE",
+  "8AE", "9AE", "AAE", "BAE", "CAE", "DAE", "EAE", "FAE",
+  "0BE", "1BE", "2BE", "3BE", "4BE", "5BE", "6BE", "7BE",
+  "8BE", "9BE", "ABE", "BBE", "CBE", "DBE", "EBE", "FBE",
+  "0CE", "1CE", "2CE", "3CE", "4CE", "5CE", "6CE", "7CE",
+  "8CE", "9CE", "ACE", "BCE", "CCE", "DCE", "ECE", "FCE",
+  "0DE", "1DE", "2DE", "3DE", "4DE", "5DE", "6DE", "7DE",
+  "8DE", "9DE", "ADE", "BDE", "CDE", "DDE", "EDE", "FDE",
+  "0EE", "1EE", "2EE", "3EE", "4EE", "5EE", "6EE", "7EE",
+  "8EE", "9EE", "AEE", "BEE", "CEE", "DEE", "EEE", "FEE",
+  "0FE", "1FE", "2FE", "3FE", "4FE", "5FE", "6FE", "7FE",
+  "8FE", "9FE", "AFE", "BFE", "CFE", "DFE", "EFE", "FFE",
+  "00F", "10F", "20F", "30F", "40F", "50F", "60F", "70F",
+  "80F", "90F", "A0F", "B0F", "C0F", "D0F", "E0F", "F0F",
+  "01F", "11F", "21F", "31F", "41F", "51F", "61F", "71F",
+  "81F", "91F", "A1F", "B1F", "C1F", "D1F", "E1F", "F1F",
+  "02F", "12F", "22F", "32F", "42F", "52F", "62F", "72F",
+  "82F", "92F", "A2F", "B2F", "C2F", "D2F", "E2F", "F2F",
+  "03F", "13F", "23F", "33F", "43F", "53F", "63F", "73F",
+  "83F", "93F", "A3F", "B3F", "C3F", "D3F", "E3F", "F3F",
+  "04F", "14F", "24F", "34F", "44F", "54F", "64F", "74F",
+  "84F", "94F", "A4F", "B4F", "C4F", "D4F", "E4F", "F4F",
+  "05F", "15F", "25F", "35F", "45F", "55F", "65F", "75F",
+  "85F", "95F", "A5F", "B5F", "C5F", "D5F", "E5F", "F5F",
+  "06F", "16F", "26F", "36F", "46F", "56F", "66F", "76F",
+  "86F", "96F", "A6F", "B6F", "C6F", "D6F", "E6F", "F6F",
+  "07F", "17F", "27F", "37F", "47F", "57F", "67F", "77F",
+  "87F", "97F", "A7F", "B7F", "C7F", "D7F", "E7F", "F7F",
+  "08F", "18F", "28F", "38F", "48F", "58F", "68F", "78F",
+  "88F", "98F", "A8F", "B8F", "C8F", "D8F", "E8F", "F8F",
+  "09F", "19F", "29F", "39F", "49F", "59F", "69F", "79F",
+  "89F", "99F", "A9F", "B9F", "C9F", "D9F", "E9F", "F9F",
+  "0AF", "1AF", "2AF", "3AF", "4AF", "5AF", "6AF", "7AF",
+  "8AF", "9AF", "AAF", "BAF", "CAF", "DAF", "EAF", "FAF",
+  "0BF", "1BF", "2BF", "3BF", "4BF", "5BF", "6BF", "7BF",
+  "8BF", "9BF", "ABF", "BBF", "CBF", "DBF", "EBF", "FBF",
+  "0CF", "1CF", "2CF", "3CF", "4CF", "5CF", "6CF", "7CF",
+  "8CF", "9CF", "ACF", "BCF", "CCF", "DCF", "ECF", "FCF",
+  "0DF", "1DF", "2DF", "3DF", "4DF", "5DF", "6DF", "7DF",
+  "8DF", "9DF", "ADF", "BDF", "CDF", "DDF", "EDF", "FDF",
+  "0EF", "1EF", "2EF", "3EF", "4EF", "5EF", "6EF", "7EF",
+  "8EF", "9EF", "AEF", "BEF", "CEF", "DEF", "EEF", "FEF",
+  "0FF", "1FF", "2FF", "3FF", "4FF", "5FF", "6FF", "7FF",
+  "8FF", "9FF", "AFF", "BFF", "CFF", "DFF", "EFF", "FFF"
+};
+
+/** Append a single character to an output buffer.
+ * @param[in,out] buf_p Buffer to append to.
+ * @param[in] c Character to append.
+ */
+static void
+addc(struct BufData *buf_p, int c)
+{
+  int overflow = 0;
+
+  if (buf_p->limit == 0) { /* We've gone past the limit... */
+    buf_p->overflow++;
+    overflow++;
+  } else if (buf_p->limit > 0) /* update the limit */
+    buf_p->limit--;
+
+  if (buf_p->buf_loc >= buf_p->buf_size) { /* We've gone past buffer */
+    buf_p->buf_overflow++;
+    overflow++;
+  }
+
+  if (!overflow) /* add the character to the buffer */
+    buf_p->buf[buf_p->buf_loc++] = c;
+}
+
+/** Append a string to an output buffer.
+ * @param[in,out] buf_p Buffer to append to.
+ * @param[in] s_len Length of string to append.
+ * @param[in] s String to append.
+ */
+static void
+adds(struct BufData *buf_p, int s_len, const char *s)
+{
+  int overflow = 0;
+
+  /* while the string exists and has non-zero length */
+  while (s_len && *s)
+  {
+    /* poor man's inlining; see addc(), above */
+    if (buf_p->limit == 0) { /* We've gone past the limit... */
+      buf_p->overflow++;
+      overflow++;
+    } else if (buf_p->limit > 0) /* update the limit */
+      buf_p->limit--;
+
+    if (buf_p->buf_loc >= buf_p->buf_size) { /* We've gone past buffer */
+      buf_p->buf_overflow++;
+      overflow++;
+    }
+
+    if (!overflow) /* add the character to the buffer */
+      buf_p->buf[buf_p->buf_loc++] = *s;
+
+    s++; /* advance to next character */
+    if (s_len > 0) /* update string length left to copy */
+      s_len--;
+  }
+}
+
+/** Add certain padding to an output buffer.
+ * @param[in,out] buf_p Buffer to append to.
+ * @param[in] padlen Length of padding to add.
+ * @param[in] pad Padding string (at least PAD_LENGTH bytes long).
+ */
+static void
+do_pad(struct BufData *buf_p, int padlen, char *pad)
+{
+  /* do chunks of PAD_LENGTH first */
+  for (; padlen > PAD_LENGTH; padlen -= PAD_LENGTH)
+    adds(buf_p, PAD_LENGTH, pad);
+
+  /* add any left-over padding */
+  adds(buf_p, padlen, pad);
+}
+
+/** Return length of string, up to a maximum.
+ * @param[in] str String to find length for.
+ * @param[in] maxlen Maximum value to return.
+ * @return Minimum of \a maxlen and length of \a str.
+ */
+static int
+my_strnlen(const char *str, int maxlen)
+{
+  int len = 0;
+
+  while (*str++ && maxlen--)
+    len++;
+
+  return len;
+}
+
+/** Workhorse printing function.
+ * @param[in] dest Client to format the message.
+ * @param[in,out] buf_p Description of output buffer.
+ * @param[in] fmt Message format string.
+ * @param[in] vp Variable-length argument list for format string.
+ */
+static void
+doprintf(struct Client *dest, struct BufData *buf_p, const char *fmt,
+        va_list vp)
+{
+  enum {
+    FLAG,      /* Gathering flags */
+    WIDTH,     /* Gathering field width */
+    DOT,       /* Found a dot */
+    PREC,      /* Gathering field precision */
+    OPT,       /* Gathering field options (l, h, q, etc.) */
+    SPEC       /* Looking for field specifier */
+  } state = FLAG;
+  struct FieldData fld_s = FIELDDATA_INIT;
+  const char *fstart = 0;
+
+  for (; *fmt; fmt++) {
+    /* If it's not %, or if it's %%, append it to the string */
+    if (*fmt != '%' || (*fmt == '%' && *++fmt == '%')) {
+      addc(buf_p, *fmt); /* add the character to the string */
+
+      continue; /* go to the next character */
+    }
+
+    state = FLAG; /* initialize our field data */
+    fld_s.flags = 0;
+    fld_s.base = BASE_DECIMAL;
+    fld_s.width = 0;
+    fld_s.prec = -1;
+    fstart = fmt;
+
+    for (; *fmt; fmt++) {
+      switch (*fmt) {
+      case '-': /* Deal with a minus flag */
+       if (state == FLAG)
+         fld_s.flags |= FLAG_MINUS;
+       else if (state == PREC) { /* precisions may not be negative */
+         fld_s.prec = -1;
+         state = OPT; /* prohibit further precision wrangling */
+       }
+       continue;
+
+      case '+': /* Deal with a plus flag */
+       if (state == FLAG)
+         fld_s.flags |= FLAG_PLUS;
+       continue;
+
+      case ' ': /* Deal with a space flag */
+       if (state == FLAG)
+         fld_s.flags |= FLAG_SPACE;
+       continue;
+
+      case '#': /* Deal with the so-called "alternate" flag */
+       if (state == FLAG)
+         fld_s.flags |= FLAG_ALT;
+       continue;
+
+      case ':': /* Deal with the colon flag */
+       if (state == FLAG)
+         fld_s.flags |= FLAG_COLON;
+       continue;
+
+      case '0': /* Deal with a zero flag */
+       if (state == FLAG) {
+         fld_s.flags |= FLAG_ZERO;
+         continue;
+       }
+       /*FALLTHROUGH*/
+      case '1':  case '2':  case '3':  case '4':  case '5':
+      case '6':  case '7':  case '8':  case '9':
+       if (state == FLAG) /* switch to the WIDTH state if needed? */
+         state = WIDTH;
+       else if (state != WIDTH && state != PREC)
+         continue; /* don't process it any more */
+
+       /* convert number */
+       if (state == WIDTH) {
+         if (fld_s.width < WIDTH_MAX) /* prevent overflow */
+           fld_s.width = fld_s.width * 10 + (*fmt - '0');
+       } else {
+         if (fld_s.prec < WIDTH_MAX) /* prevent overflow */
+           fld_s.prec = fld_s.prec * 10 + (*fmt - '0');
+       }
+       continue;
+
+      case '.': /* We found a '.'; go to precision state */
+       if (state <= DOT) {
+         state = PREC;
+         fld_s.prec = 0;
+       }
+       continue;
+
+      case '*': /* Grab an argument containing a width or precision */
+       if (state <= WIDTH && fld_s.width <= 0) {
+         fld_s.width = (short)va_arg(vp, int); /* Get argument */
+
+         state = DOT; /* '.' better be next */
+
+         if (fld_s.width < 0) { /* deal with negative width */
+           fld_s.flags |= FLAG_MINUS;
+           fld_s.width = -fld_s.width;
+         }
+       } else if (state == PREC && fld_s.prec <= 0) {
+         fld_s.prec = (short)va_arg(vp, int); /* Get argument */
+
+         state = OPT; /* No more precision stuff */
+
+         if (fld_s.prec < 0) /* deal with negative precision */
+           fld_s.prec = -1;
+       }
+       continue;
+
+      case 'h': /* it's a short */
+       if (state <= OPT) {
+         state = OPT;
+         if (fld_s.flags & TYPE_SHORT) /* We support 'hh' */
+           fld_s.flags |= TYPE_CHAR;
+         else if (!(fld_s.flags & TYPE_MASK))
+           fld_s.flags |= TYPE_SHORT;
+       }
+       continue;
+
+      case 'l': /* it's a long */
+       if (state <= OPT) {
+         state = OPT;
+         if (fld_s.flags & TYPE_LONG) /* We support 'll' */
+           fld_s.flags |= TYPE_QUAD | TYPE_LONGDOUBLE;
+         else if (!(fld_s.flags & TYPE_MASK))
+           fld_s.flags |= TYPE_LONG;
+       }
+       continue;
+
+      case 'q':  case 'L': /* it's a quad or long double */
+       if (state <= OPT) {
+         state = OPT;
+         if (!(fld_s.flags & TYPE_MASK))
+           fld_s.flags |= TYPE_QUAD | TYPE_LONGDOUBLE;
+       }
+       continue;
+
+      case 'j': /* it's an intmax_t */
+       if (state <= OPT) {
+         state = OPT;
+         if (!(fld_s.flags & TYPE_MASK))
+           fld_s.flags |= TYPE_INTMAX;
+       }
+       continue;
+
+      case 't': /* it's a ptrdiff_t */
+       if (state <= OPT) {
+         state = OPT;
+         if (!(fld_s.flags & TYPE_MASK))
+           fld_s.flags |= TYPE_PTRDIFF;
+       }
+       continue;
+
+      case 'z':  case 'Z': /* it's a size_t */
+       if (state <= OPT) {
+         state = OPT;
+         if (!(fld_s.flags & TYPE_MASK))
+           fld_s.flags |= TYPE_SIZE;
+       }
+       continue;
+
+      case 'T': /* it's a time_t */
+       if (state <= OPT) {
+         state = OPT;
+         if (!(fld_s.flags & TYPE_MASK))
+           fld_s.flags |= TYPE_TIME;
+       }
+       continue;
+
+      case 's': /* convert a string */
+       fld_s.flags &= ~(FLAG_PLUS | FLAG_SPACE | FLAG_ALT | FLAG_ZERO |
+                        FLAG_COLON | TYPE_MASK);
+       fld_s.flags |= ARG_PTR | CONV_STRING;
+       break;
+
+      case 'd':  case 'i':
+       fld_s.flags &= ~(FLAG_COLON);
+       fld_s.flags |= ARG_INT | CONV_INT;
+       break;
+
+      case 'X': /* uppercase hexadecimal */
+       fld_s.flags |= INFO_UPPERCASE;
+       /*FALLTHROUGH*/
+      case 'o':  case 'x': /* octal or hexadecimal */
+       if (*fmt == 'o')
+         fld_s.base = BASE_OCTAL;
+       else
+         fld_s.base = BASE_HEX;
+       /*FALLTHROUGH*/
+      case 'u': /* Unsigned int */
+       fld_s.flags &= ~(FLAG_PLUS | FLAG_SPACE | FLAG_COLON);
+       fld_s.flags |= INFO_UNSIGNED | ARG_INT | CONV_INT;
+       break;
+
+       /* Don't support floating point at this time; it's too complicated */
+/*        case 'E':  case 'G':  case 'A': */
+/*     fld_s.flags |= INFO_UPPERCASE; */
+       /*FALLTHROUGH*/
+/*        case 'e':  case 'f':  case 'g':  case 'a': */
+/*     fld_s.flags |= ARG_FLOAT | CONV_FLOAT; */
+/*     break; */
+
+      case 'c': /* character */
+       fld_s.flags &= ~(FLAG_PLUS | FLAG_SPACE | FLAG_ALT | FLAG_ZERO |
+                        FLAG_COLON | TYPE_MASK);
+       fld_s.flags |= INFO_UNSIGNED | ARG_INT | TYPE_CHAR | CONV_CHAR;
+       fld_s.prec = -1;
+       break;
+
+      case 'p': /* display a pointer */
+       fld_s.flags &= ~(FLAG_PLUS | FLAG_SPACE | FLAG_COLON | TYPE_MASK);
+       fld_s.flags |= (FLAG_ALT | FLAG_ZERO | TYPE_POINTER | ARG_PTR |
+                       CONV_INT | INFO_UNSIGNED);
+       fld_s.prec = (SIZEOF_VOID_P * 2); /* number of characters */
+       fld_s.base = BASE_HEX;
+       break;
+
+      case 'n': /* write back a character count */
+       if (fld_s.flags & TYPE_CHAR) /* eg, %hhn */
+         *((char *)va_arg(vp, int *)) = TOTAL(buf_p);
+       else if (fld_s.flags & TYPE_SHORT) /* eg, %hn */
+         *((short *)va_arg(vp, int *)) = TOTAL(buf_p);
+       else if (fld_s.flags & TYPE_QUAD) /* eg, %qn */
+         *((int64_t *)va_arg(vp, int64_t *)) = TOTAL(buf_p);
+       else if (fld_s.flags & TYPE_LONG) /* eg, %ln */
+         *((long *)va_arg(vp, long *)) = TOTAL(buf_p);
+       else if (fld_s.flags & TYPE_INTMAX) /* eg, %jn */
+         *((_large_t *)va_arg(vp, _large_t *)) = TOTAL(buf_p);
+       else if (fld_s.flags & TYPE_PTRDIFF) /* eg, %tn */
+         *((ptrdiff_t *)va_arg(vp, ptrdiff_t *)) = TOTAL(buf_p);
+       else if (fld_s.flags & TYPE_SIZE) /* eg, %zn */
+         *((size_t *)va_arg(vp, size_t *)) = TOTAL(buf_p);
+       else if (fld_s.flags & TYPE_TIME) /* eg, %Tn */
+         *((time_t *)va_arg(vp, time_t *)) = TOTAL(buf_p);
+       else /* eg, %n */
+         *((int *)va_arg(vp, int *)) = TOTAL(buf_p);
+       fld_s.flags = 0; /* no further processing required */
+       break;
+
+      case 'm': /* write out a string describing an errno error */
+       fld_s.flags &= ~(FLAG_PLUS | FLAG_SPACE | FLAG_ALT | FLAG_ZERO |
+                        FLAG_COLON | TYPE_MASK);
+       fld_s.flags |= CONV_STRING;
+       fld_s.value.v_ptr = (void *)strerror(errno);
+       break;
+
+      case 'v': /* here's the infamous %v... */
+       fld_s.flags &= ~(FLAG_PLUS | FLAG_SPACE | FLAG_ALT | FLAG_ZERO |
+                        FLAG_COLON | TYPE_MASK);
+       fld_s.flags |= ARG_PTR | CONV_VARARGS;
+       break;
+
+      case 'C': /* convert a client name... */
+       fld_s.flags &= ~(FLAG_PLUS | FLAG_SPACE | FLAG_ZERO | TYPE_MASK);
+       fld_s.flags |= ARG_PTR | CONV_CLIENT;
+       break;
+
+      case 'H': /* convert a channel name... */
+       fld_s.flags &= ~(FLAG_PLUS | FLAG_SPACE | FLAG_ALT | FLAG_ZERO |
+                        FLAG_COLON | TYPE_MASK);
+       fld_s.flags |= ARG_PTR | CONV_CHANNEL;
+       break;
+
+      default: /* Unsupported, display a message and the entire format */
+       adds(buf_p, -1, "(Unsupported: %");
+       adds(buf_p, fmt - fstart + 1, fstart);
+       addc(buf_p, ')');
+       fld_s.flags = 0; /* no further processing required */
+       break;
+      } /* switch (*fmt) { */
+
+      break;
+    } /* for (; *fmt; fmt++) { */
+
+    if (!*fmt) /* hit the end */
+      break;
+    else if (!(fld_s.flags & (ARG_MASK | CONV_MASK))) /* is it done? */
+      continue;
+
+    if ((fld_s.flags & ARG_MASK) == ARG_INT) { /* grab an integer argument */
+      if (fld_s.flags & INFO_UNSIGNED) { /* go direct if unsigned */
+       if (fld_s.flags & TYPE_CHAR) /* eg, %hhu */
+         fld_s.value.v_int = (unsigned char)va_arg(vp, unsigned int);
+       else if (fld_s.flags & TYPE_SHORT) /* eg, %hu */
+         fld_s.value.v_int = (unsigned short)va_arg(vp, unsigned int);
+       else if (fld_s.flags & TYPE_QUAD) /* eg, %qu */
+         fld_s.value.v_int = va_arg(vp, uint64_t);
+       else if (fld_s.flags & TYPE_LONG) /* eg, %lu */
+         fld_s.value.v_int = va_arg(vp, unsigned long);
+       else if (fld_s.flags & TYPE_INTMAX) /* eg, %ju */
+         fld_s.value.v_int = va_arg(vp, _large_t);
+       else if (fld_s.flags & TYPE_PTRDIFF) /* eg, %tu */
+         fld_s.value.v_int = va_arg(vp, ptrdiff_t);
+       else if (fld_s.flags & TYPE_SIZE) /* eg, %zu */
+         fld_s.value.v_int = va_arg(vp, size_t);
+       else if (fld_s.flags & TYPE_TIME) /* eg, %Tu */
+         fld_s.value.v_int = va_arg(vp, time_t);
+       else if (fld_s.flags & TYPE_POINTER) /* eg, %p */
+         fld_s.value.v_int = va_arg(vp, _pointer_t);
+       else /* eg, %u */
+         fld_s.value.v_int = va_arg(vp, unsigned int);
+      } else {
+       _large_t signed_int; /* temp. store the signed integer */
+
+       if (fld_s.flags & TYPE_CHAR) /* eg, %hhd */
+         signed_int = (char)va_arg(vp, unsigned int);
+       else if (fld_s.flags & TYPE_SHORT) /* eg, %hd */
+         signed_int = (short)va_arg(vp, unsigned int);
+       else if (fld_s.flags & TYPE_QUAD) /* eg, %qd */
+         signed_int = va_arg(vp, int64_t);
+       else if (fld_s.flags & TYPE_LONG) /* eg, %ld */
+         signed_int = va_arg(vp, long);
+       else if (fld_s.flags & TYPE_INTMAX) /* eg, %jd */
+         signed_int = va_arg(vp, _large_t);
+       else if (fld_s.flags & TYPE_PTRDIFF) /* eg, %td */
+         signed_int = va_arg(vp, ptrdiff_t);
+       else if (fld_s.flags & TYPE_SIZE) /* eg, %zd */
+         signed_int = va_arg(vp, size_t);
+       else if (fld_s.flags & TYPE_TIME) /* eg, %Td */
+         signed_int = va_arg(vp, time_t);
+       else /* eg, %d */
+         signed_int = va_arg(vp, int);
+
+       if (signed_int < 0) { /* Now figure out if it's negative... */
+         fld_s.flags |= INFO_NEGATIVE;
+         fld_s.value.v_int = -signed_int; /* negate safely (I hope) */
+       } else
+         fld_s.value.v_int = signed_int;
+      }
+    } else if ((fld_s.flags & ARG_MASK) == ARG_FLOAT) { /* extract a float */
+      if (fld_s.flags & TYPE_LONGDOUBLE) /* eg, %Lf */
+       fld_s.value.v_float = va_arg(vp, long double);
+      else /* eg, %f */
+       fld_s.value.v_float = va_arg(vp, double);
+    } else if ((fld_s.flags & ARG_MASK) == ARG_PTR) { /* pointer argument */
+      fld_s.value.v_ptr = va_arg(vp, void *);
+    }
+
+    /* We've eaten the arguments, we have all the information we need for
+     * the conversion.  Time to actually *do* the conversion
+     */
+    if ((fld_s.flags & CONV_MASK) == CONV_INT) {
+      /* convert an integer */
+      char intbuf[INTBUF_LEN], **table = 0, *tstr;
+      int ibuf_loc = INTBUF_LEN, ilen, zlen = 0, plen = 0, elen = 0;
+
+      if (fld_s.base == BASE_OCTAL) /* select string table to use */
+       table = octal;
+      else if (fld_s.base == BASE_DECIMAL)
+       table = decimal;
+      else if (fld_s.base == BASE_HEX) { /* have to deal with upper case */
+       table = (fld_s.flags & INFO_UPPERCASE) ? HEX : hex;
+       if (fld_s.flags & FLAG_ALT)
+         elen = 2; /* account for the length of 0x */
+      }
+
+      if (fld_s.prec < 0) { /* default precision is 1 */
+       if ((fld_s.flags & (FLAG_MINUS | FLAG_ZERO)) == FLAG_ZERO &&
+           fld_s.width) {
+         fld_s.prec = fld_s.width - elen;
+         fld_s.width = 0;
+       } else
+         fld_s.prec = 1;
+      }
+
+      /* If there's a sign flag, account for it */
+      if (fld_s.flags & (FLAG_PLUS | FLAG_SPACE | INFO_NEGATIVE))
+       elen++;
+
+      if (fld_s.base < 0) { /* non-binary base flagged by negative */
+       fld_s.base = -fld_s.base; /* negate it... */
+
+       while (fld_s.value.v_int) { /* and convert it */
+         tstr = table[fld_s.value.v_int % fld_s.base]; /* which string? */
+         fld_s.value.v_int /= fld_s.base; /* next value */
+
+         ilen = 3; /* if we have to fill in zeros, here's how many */
+
+         while (*tstr) { /* add string to intbuf; note growing backwards */
+           intbuf[--ibuf_loc] = *(tstr++);
+           ilen--;
+         }
+
+         if (fld_s.value.v_int > 0 && ilen) /* add zeros if needed */
+           while (ilen--)
+             intbuf[--ibuf_loc] = '0';
+       }
+      } else { /* optimize for powers of 2 */
+       while (fld_s.value.v_int) { /* which string? */
+         tstr = table[(fld_s.value.v_int & ((1 << fld_s.base) - 1))];
+         fld_s.value.v_int >>= fld_s.base; /* next value */
+
+         ilen = 3; /* if we have to fill in zeros, here's how many */
+
+         while (*tstr) { /* add string to intbuf; note growing backwards */
+           intbuf[--ibuf_loc] = *(tstr++);
+           ilen--;
+         }
+
+         if (fld_s.value.v_int > 0 && ilen) /* add zeros if needed */
+           while (ilen--)
+             intbuf[--ibuf_loc] = '0';
+       }
+      }
+
+      ilen = INTBUF_LEN - ibuf_loc; /* how many chars did we add? */
+
+      if (fld_s.prec > ilen) /* do we need any leading zeros? */
+       zlen = fld_s.prec - ilen;
+
+      if (fld_s.base == BASE_OCTAL && zlen == 0 && fld_s.flags & FLAG_ALT)
+       zlen++; /* factor in a leading zero for %#o */
+
+      if (fld_s.width > ilen + zlen + elen) /* calculate space padding */
+       plen = fld_s.width - (ilen + zlen + elen);
+
+      if (plen > 0 && !(fld_s.flags & FLAG_MINUS))
+       do_pad(buf_p, plen, spaces); /* pre-padding */
+
+      if (fld_s.flags & INFO_NEGATIVE) /* leading signs */
+       addc(buf_p, '-');
+      else if (fld_s.flags & FLAG_PLUS)
+       addc(buf_p, '+');
+      else if (fld_s.flags & FLAG_SPACE)
+       addc(buf_p, ' ');
+
+      if ((fld_s.flags & FLAG_ALT) && fld_s.base == BASE_HEX) { /* hex 0x */
+       addc(buf_p, '0');
+       addc(buf_p, fld_s.flags & INFO_UPPERCASE ? 'X' : 'x');
+      }
+
+      if (zlen > 0) /* leading zeros */
+       do_pad(buf_p, zlen, zeros);
+
+      adds(buf_p, ilen, intbuf + ibuf_loc); /* add the integer string */
+
+      if (plen > 0 &&  (fld_s.flags & FLAG_MINUS))
+       do_pad(buf_p, plen, spaces); /* post-padding */
+
+      /* Don't support floating point at this time; it's too complicated */
+/*      } else if ((fld_s.flags & CONV_MASK) == CONV_FLOAT) { */
+      /* convert a float */
+    } else if ((fld_s.flags & CONV_MASK) == CONV_CHAR) {
+      if (fld_s.width > 0 && !(fld_s.flags & FLAG_MINUS))
+       do_pad(buf_p, fld_s.width - 1, spaces); /* pre-padding */
+
+      addc(buf_p, fld_s.value.v_int); /* add the character */
+
+      if (fld_s.width > 0 &&  (fld_s.flags & FLAG_MINUS))
+       do_pad(buf_p, fld_s.width - 1, spaces); /* post-padding */
+    } else if ((fld_s.flags & CONV_MASK) == CONV_STRING ||
+              fld_s.value.v_ptr == 0) { /* spaces or null pointers */
+      int slen, plen;
+      char *str = (char*) fld_s.value.v_ptr;
+
+      if (!str) /* NULL pointers print "(null)" */
+       str = "(null)";
+
+      slen = my_strnlen(str, fld_s.prec); /* str lengths and pad lengths */
+      plen = (fld_s.width - slen <= 0 ? 0 : fld_s.width - slen);
+
+      if (plen > 0 && !(fld_s.flags & FLAG_MINUS))
+       do_pad(buf_p, plen, spaces); /* pre-padding */
+
+      adds(buf_p, slen, str); /* add the string */
+
+      if (plen > 0 &&  (fld_s.flags & FLAG_MINUS))
+       do_pad(buf_p, plen, spaces); /* post-padding */
+    } else if ((fld_s.flags & CONV_MASK) == CONV_VARARGS) {
+      struct BufData buf_s = BUFDATA_INIT;
+      struct VarData *vdata = (struct VarData*) fld_s.value.v_ptr;
+      int plen, tlen;
+
+      buf_s.buf = buf_p->buf + buf_p->buf_loc;
+      buf_s.buf_size = buf_p->buf_size - buf_p->buf_loc;
+      buf_s.limit = fld_s.prec;
+
+      doprintf(dest, &buf_s, vdata->vd_format, vdata->vd_args);
+
+      plen = (fld_s.width - buf_s.buf_loc <= 0 ? 0 :
+             fld_s.width - buf_s.buf_loc);
+
+      if (plen > 0) {
+       if (fld_s.flags & FLAG_MINUS) { /* left aligned... */
+         buf_p->buf_loc += buf_s.buf_loc; /* remember the modifications */
+         buf_p->buf_overflow += buf_s.buf_overflow;
+
+         do_pad(buf_p, plen, spaces); /* and do the post-padding */
+       } else { /* right aligned... */
+         /* Ok, first, see if we'll have *anything* left after padding */
+         if (plen > buf_s.buf_size) {
+           /* nope, good, this is easy: everything overflowed buffer */
+           do_pad(buf_p, plen, spaces);
+
+           buf_s.buf_overflow += buf_s.buf_loc; /* update buf counts */
+           buf_s.buf_loc = 0;
+           buf_p->buf_overflow += buf_s.buf_overflow;
+         } else {
+           /* first figure out how much we're going to save */
+           tlen = SNP_MIN(buf_s.buf_loc, buf_s.buf_size - plen);
+
+           memmove(buf_s.buf + plen, buf_s.buf, tlen); /* save it... */
+           do_pad(buf_p, plen, spaces); /* add spaces... */
+
+           buf_s.buf_overflow += buf_s.buf_loc - tlen; /* update buf counts */
+           buf_s.buf_loc = tlen;
+           buf_p->buf_overflow += buf_s.buf_overflow;
+           buf_p->buf_loc += buf_s.buf_loc;
+         }
+       }
+      } else {
+       buf_p->buf_loc += buf_s.buf_loc; /* no padding, but remember mods */
+       buf_p->buf_overflow += buf_s.buf_overflow;
+      }
+
+      vdata->vd_chars = buf_s.buf_loc; /* return relevant data */
+      vdata->vd_overflow = SNP_MAX(buf_s.buf_overflow, buf_s.overflow);
+    } else if ((fld_s.flags & CONV_MASK) == CONV_CLIENT) {
+      struct Client *cptr = (struct Client*) fld_s.value.v_ptr;
+      const char *str1 = 0, *str2 = 0, *str3 = 0;
+      int slen1 = 0, slen2 = 0, slen3 = 0, elen = 0, plen = 0;
+
+      /* &me is used if it's not a definite server */
+      if (dest && (IsServer(dest) || IsMe(dest))) {
+       if (IsServer(cptr) || IsMe(cptr))
+         str1 = cli_yxx(cptr);
+       else {
+         str1 = cli_yxx(cli_user(cptr)->server);
+         str2 = cli_yxx(cptr);
+       }
+       fld_s.flags &= ~(FLAG_ALT | FLAG_COLON);
+      } else {
+       str1 = *cli_name(cptr) ? cli_name(cptr) : "*";
+       if (!IsServer(cptr) && !IsMe(cptr) && fld_s.flags & FLAG_ALT) {
+         assert(0 != cli_user(cptr));
+         assert(0 != *(cli_name(cptr)));
+         str2 = cli_user(cptr)->username;
+         str3 = cli_user(cptr)->host;
+       } else
+         fld_s.flags &= ~FLAG_ALT;
+      }
+
+      if (fld_s.flags & FLAG_COLON)
+       elen++; /* account for : */
+
+      slen1 = my_strnlen(str1, fld_s.prec < 0 ? -1 : fld_s.prec - elen);
+      if (fld_s.flags & FLAG_ALT)
+       elen++; /* account for ! */
+      if (str2 && (fld_s.prec < 0 || fld_s.prec - (slen1 + elen) > 0))
+       slen2 = my_strnlen(str2, fld_s.prec < 0 ? -1 : fld_s.prec -
+                          (slen1 + elen));
+      if (fld_s.flags & FLAG_ALT)
+       elen++; /* account for @ */
+      if (str3 && (fld_s.prec < 0 || fld_s.prec - (slen1 + slen2 + elen) > 0))
+       slen3 = my_strnlen(str3, fld_s.prec < 0 ? -1 : fld_s.prec -
+                          (slen1 + slen2 + elen));
+      plen = (fld_s.width - (slen1 + slen2 + slen3 + elen) <= 0 ? 0 :
+             fld_s.width - (slen1 + slen2 + slen3 + elen));
+
+      if (plen > 0 && !(fld_s.flags & FLAG_MINUS))
+       do_pad(buf_p, plen, spaces); /* pre-padding */
+
+      if (fld_s.flags & FLAG_COLON)
+       addc(buf_p, ':');
+      adds(buf_p, slen1, str1);
+      if (fld_s.flags & FLAG_ALT)
+       addc(buf_p, '!');
+      if (str2)
+       adds(buf_p, slen2, str2);
+      if (fld_s.flags & FLAG_ALT)
+       addc(buf_p, '@');
+      if (str3)
+       adds(buf_p, slen3, str3);
+
+      if (plen > 0 &&  (fld_s.flags & FLAG_MINUS))
+       do_pad(buf_p, plen, spaces); /* post-padding */
+    } else if ((fld_s.flags & CONV_MASK) == CONV_CHANNEL) {
+      struct Channel *chan = (struct Channel *)fld_s.value.v_ptr;
+      char *str = chan->chname;
+      int slen, plen;
+
+      slen = my_strnlen(str, fld_s.prec); /* str lengths and pad lengths */
+      plen = (fld_s.width - slen <= 0 ? 0 : fld_s.width - slen);
+
+      if (plen > 0 && !(fld_s.flags & FLAG_MINUS))
+       do_pad(buf_p, plen, spaces); /* pre-padding */
+
+      adds(buf_p, slen, str); /* add the string */
+
+      if (plen > 0 &&  (fld_s.flags & FLAG_MINUS))
+       do_pad(buf_p, plen, spaces); /* post-padding */
+    }
+  } /* for (; *fmt; fmt++) { */
+}
+
+/* ircd_snprintf() has a big Doxygen comment in the header file. */
+int
+ircd_snprintf(struct Client *dest, char *buf, size_t buf_len,
+             const char *format, ...)
+{
+  struct BufData buf_s = BUFDATA_INIT;
+  va_list args;
+
+  if (!format)
+    return 0;
+
+  buf_s.buf = buf; /* initialize buffer settings */
+  buf_s.buf_size = buf_len - 1;
+  buf_s.limit = -1;
+
+  va_start(args, format);
+  doprintf(dest, &buf_s, format, args); /* fill the buffer */
+  va_end(args);
+
+  buf_s.buf[buf_s.buf_loc] = '\0'; /* terminate buffer */
+
+  return TOTAL(&buf_s);
+}
+
+/** Like ircd_snprintf() but with a va_list argument list.
+ * @param[in] dest Client receiving of message.
+ * @param[out] buf Output buffer for formatted message.
+ * @param[in] buf_len Number of bytes that can be written to \a buf.
+ * @param[in] format Format string for message.
+ * @param[in] args Variable-length argument list for format string.
+ * @return Number of bytes that would be written to \a buf without truncation.
+ */
+int
+ircd_vsnprintf(struct Client *dest, char *buf, size_t buf_len,
+              const char *format, va_list args)
+{
+  struct BufData buf_s = BUFDATA_INIT;
+
+  if (!format)
+    return 0;
+
+  buf_s.buf = buf; /* initialize buffer settings */
+  buf_s.buf_size = buf_len - 1;
+  buf_s.limit = -1;
+
+  doprintf(dest, &buf_s, format, args); /* fill the buffer */
+
+  buf_s.buf[buf_s.buf_loc] = '\0'; /* terminate buffer */
+
+  return TOTAL(&buf_s);
+}
diff --git a/ircd/ircd_string.c b/ircd/ircd_string.c
new file mode 100644 (file)
index 0000000..b862a14
--- /dev/null
@@ -0,0 +1,655 @@
+/*
+ * IRC - Internet Relay Chat, ircd/ircd_string.c
+ * Copyright (C) 1999 Thomas Helvey
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+/** @file
+ * @brief Implementation of string operations.
+ * @version $Id: ircd_string.c 1872 2008-03-20 23:58:27Z entrope $
+ */
+#include "config.h"
+
+#include "ircd_string.h"
+#include "ircd_defs.h"
+#include "ircd_chattr.h"
+#include "ircd_log.h"
+#include "res.h"
+
+/* #include <assert.h> -- Now using assert in ircd_log.h */
+#include <string.h>
+#include <sys/types.h>
+#include <netinet/in.h>
+
+/*
+ * include the character attribute tables here
+ */
+#include "chattr.tab.c"
+
+/** Check whether \a str contains wildcard characters.
+ * @param[in] str String that might contain wildcards.
+ * @return Non-zero if \a str contains naked (non-escaped) wildcards,
+ * zero if there are none or if they are all escaped.
+ */
+int string_has_wildcards(const char* str)
+{
+  assert(0 != str);
+  for ( ; *str; ++str) {
+    if ('\\' == *str) {
+      if ('\0' == *++str)
+        break;
+    }
+    else if ('*' == *str || '?' == *str)
+      return 1;
+  }
+  return 0;
+}
+
+/** Split a string on certain delimiters.
+ * This is a reentrant version of normal strtok().  The first call for
+ * a particular input string must use a non-NULL \a str; *save will be
+ * initialized based on that.  Later calls must use a NULL \a str;
+ * *save will be updated.
+ * @param[in,out] save Pointer to a position indicator.
+ * @param[in] str Pointer to the input string, or NULL to continue.
+ * @param[in] fs String that lists token delimiters.
+ * @return Next token in input string, or NULL if no tokens remain.
+ */
+char* ircd_strtok(char **save, char *str, char *fs)
+{
+  char *pos = *save;            /* keep last position across calls */
+  char *tmp;
+
+  if (str)
+    pos = str;                  /* new string scan */
+
+  while (pos && *pos && strchr(fs, *pos) != NULL)
+    pos++;                      /* skip leading separators */
+
+  if (!pos || !*pos)
+    return (pos = *save = NULL);        /* string contains only sep's */
+
+  tmp = pos;                    /* now, keep position of the token */
+
+  while (*pos && strchr(fs, *pos) == NULL)
+    pos++;                      /* skip content of the token */
+
+  if (*pos)
+    *pos++ = '\0';              /* remove first sep after the token */
+  else
+    pos = NULL;                 /* end of string */
+
+  *save = pos;
+  return (tmp);
+}
+
+/** Rewrite a comma-delimited list of items to remove duplicates.
+ * @param[in,out] buffer Comma-delimited list.
+ * @return The input buffer \a buffer.
+ */
+char* canonize(char* buffer)
+{
+  static char cbuf[BUFSIZE];
+  char*       s;
+  char*       t;
+  char*       cp = cbuf;
+  int         l = 0;
+  char*       p = NULL;
+  char*       p2;
+
+  *cp = '\0';
+
+  for (s = ircd_strtok(&p, buffer, ","); s; s = ircd_strtok(&p, NULL, ","))
+  {
+    if (l)
+    {
+      p2 = NULL;
+      for (t = ircd_strtok(&p2, cbuf, ","); t; t = ircd_strtok(&p2, NULL, ","))
+        if (0 == ircd_strcmp(s, t))
+          break;
+        else if (p2)
+          p2[-1] = ',';
+    }
+    else
+      t = NULL;
+    if (!t)
+    {
+      if (l)
+        *(cp - 1) = ',';
+      else
+        l = 1;
+      strcpy(cp, s);
+      if (p)
+        cp += (p - s);
+    }
+    else if (p2)
+      p2[-1] = ',';
+  }
+  return cbuf;
+}
+
+/** Copy one string to another, not to exceed a certain length.
+ * @param[in] s1 Output buffer.
+ * @param[in] s2 Source buffer.
+ * @param[in] n Maximum number of bytes to write, plus one.
+ * @return The original input buffer \a s1.
+ */
+char* ircd_strncpy(char* s1, const char* s2, size_t n)
+{
+  char* endp = s1 + n;
+  char* s = s1;
+
+  assert(0 != s1);
+  assert(0 != s2);
+
+  while (s < endp && (*s++ = *s2++))
+    ;
+  if (s == endp)
+    *s = '\0';
+  return s1;
+}
+
+
+#ifndef FORCEINLINE
+NTL_HDR_strChattr { NTL_SRC_strChattr }
+NTL_HDR_strCasediff { NTL_SRC_strCasediff }
+#endif /* !FORCEINLINE */
+
+/*
+ * Other functions visible externally
+ */
+
+/** Case insensitive string comparison.
+ * @param[in] a First string to compare.
+ * @param[in] b Second string to compare.
+ * @return Less than, equal to, or greater than zero if \a a is lexicographically less than, equal to, or greater than \a b.
+ */
+int ircd_strcmp(const char *a, const char *b)
+{
+  const char* ra = a;
+  const char* rb = b;
+  while (ToLower(*ra) == ToLower(*rb)) {
+    if (!*ra++)
+      return 0;
+    else
+      ++rb;
+  }
+  return (ToLower(*ra) - ToLower(*rb));
+}
+
+/** Case insensitive comparison of the starts of two strings.
+ * @param[in] a First string to compare.
+ * @param[in] b Second string to compare.
+ * @param[in] n Maximum number of characters to compare.
+ * @return Less than, equal to, or greater than zero if \a a is
+ * lexicographically less than, equal to, or greater than \a b.
+ */
+int ircd_strncmp(const char *a, const char *b, size_t n)
+{
+  const char* ra = a;
+  const char* rb = b;
+  int left = n;
+  if (!left--)
+    return 0;
+  while (ToLower(*ra) == ToLower(*rb)) {
+    if (!*ra++ || !left--)
+      return 0;
+    else
+      ++rb;
+  }
+  return (ToLower(*ra) - ToLower(*rb));
+}
+
+/** Fill a vector of distinct names from a delimited input list.
+ * Empty tokens (when \a token occurs at the start or end of \a list,
+ * or when \a token occurs adjacent to itself) are ignored.  When
+ * \a size tokens have been written to \a vector, the rest of the
+ * string is ignored.
+ * Unlike token_vector(), if a token repeats an earlier token, it is
+ * skipped.
+ * @param[in,out] names Input buffer.
+ * @param[in] token Delimiter used to split \a list.
+ * @param[out] vector Output vector.
+ * @param[in] size Maximum number of elements to put in \a vector.
+ * @return Number of elements written to \a vector.
+ */
+int unique_name_vector(char* names, char token, char** vector, int size)
+{
+  int   i;
+  int   count = 0;
+  char* start = names;
+  char* end;
+
+  assert(0 != names);
+  assert(0 != vector);
+  assert(0 < size);
+
+  /*
+   * ignore spurious tokens
+   */
+  while (token == *start)
+    ++start;
+
+  for (end = strchr(start, token); end; end = strchr(start, token)) {
+    *end++ = '\0';
+    /*
+     * ignore spurious tokens
+     */
+    while (token == *end)
+      ++end;
+    for (i = 0; i < count; ++i) {
+      if (0 == ircd_strcmp(vector[i], start))
+        break;
+    }
+    if (i == count) {
+      vector[count++] = start;
+      if (count == size)
+        return count;
+    }
+    start = end;
+  }
+  if (*start) {
+    for (i = 0; i < count; ++i)
+      if (0 == ircd_strcmp(vector[i], start))
+        return count;
+    vector[count++] = start;
+  }
+  return count;
+}
+
+/** Fill a vector of tokens from a delimited input list.
+ * Empty tokens (when \a token occurs at the start or end of \a list,
+ * or when \a token occurs adjacent to itself) are ignored.  When
+ * \a size tokens have been written to \a vector, the rest of the
+ * string is ignored.
+ * @param[in,out] names Input buffer.
+ * @param[in] token Delimiter used to split \a list.
+ * @param[out] vector Output vector.
+ * @param[in] size Maximum number of elements to put in \a vector.
+ * @return Number of elements written to \a vector.
+ */
+int token_vector(char* names, char token, char** vector, int size)
+{
+  int   count = 0;
+  char* start = names;
+  char* end;
+
+  assert(0 != names);
+  assert(0 != vector);
+  assert(1 < size);
+
+  vector[count++] = start;
+  for (end = strchr(start, token); end; end = strchr(start, token)) {
+    *end++ = '\0';
+    start = end;
+    if (*start) {
+      vector[count++] = start;
+      if (count < size)
+        continue;
+    }
+    break;
+  }
+  return count;
+}
+
+/** Copy all or part of the hostname in a string to another string.
+ * If \a userhost contains an '\@', the remaining portion is used;
+ * otherwise, the whole \a userhost is used.
+ * @param[out] buf Output buffer.
+ * @param[in] userhost user\@hostname or hostname string.
+ * @param[in] len Maximum number of bytes to write to \a host.
+ * @return The output buffer \a buf.
+ */
+char* host_from_uh(char* buf, const char* userhost, size_t len)
+{
+  const char* s;
+
+  assert(0 != buf);
+  assert(0 != userhost);
+
+  if ((s = strchr(userhost, '@')))
+    ++s;
+  else
+    s = userhost;
+  ircd_strncpy(buf, s, len);
+  buf[len] = '\0';
+  return buf;
+}
+
+/*
+ * this new faster inet_ntoa was ripped from:
+ * From: Thomas Helvey <tomh@inxpress.net>
+ */
+/** Array of text strings for dotted quads. */
+static const char* IpQuadTab[] =
+{
+    "0",   "1",   "2",   "3",   "4",   "5",   "6",   "7",   "8",   "9",
+   "10",  "11",  "12",  "13",  "14",  "15",  "16",  "17",  "18",  "19",
+   "20",  "21",  "22",  "23",  "24",  "25",  "26",  "27",  "28",  "29",
+   "30",  "31",  "32",  "33",  "34",  "35",  "36",  "37",  "38",  "39",
+   "40",  "41",  "42",  "43",  "44",  "45",  "46",  "47",  "48",  "49",
+   "50",  "51",  "52",  "53",  "54",  "55",  "56",  "57",  "58",  "59",
+   "60",  "61",  "62",  "63",  "64",  "65",  "66",  "67",  "68",  "69",
+   "70",  "71",  "72",  "73",  "74",  "75",  "76",  "77",  "78",  "79",
+   "80",  "81",  "82",  "83",  "84",  "85",  "86",  "87",  "88",  "89",
+   "90",  "91",  "92",  "93",  "94",  "95",  "96",  "97",  "98",  "99",
+  "100", "101", "102", "103", "104", "105", "106", "107", "108", "109",
+  "110", "111", "112", "113", "114", "115", "116", "117", "118", "119",
+  "120", "121", "122", "123", "124", "125", "126", "127", "128", "129",
+  "130", "131", "132", "133", "134", "135", "136", "137", "138", "139",
+  "140", "141", "142", "143", "144", "145", "146", "147", "148", "149",
+  "150", "151", "152", "153", "154", "155", "156", "157", "158", "159",
+  "160", "161", "162", "163", "164", "165", "166", "167", "168", "169",
+  "170", "171", "172", "173", "174", "175", "176", "177", "178", "179",
+  "180", "181", "182", "183", "184", "185", "186", "187", "188", "189",
+  "190", "191", "192", "193", "194", "195", "196", "197", "198", "199",
+  "200", "201", "202", "203", "204", "205", "206", "207", "208", "209",
+  "210", "211", "212", "213", "214", "215", "216", "217", "218", "219",
+  "220", "221", "222", "223", "224", "225", "226", "227", "228", "229",
+  "230", "231", "232", "233", "234", "235", "236", "237", "238", "239",
+  "240", "241", "242", "243", "244", "245", "246", "247", "248", "249",
+  "250", "251", "252", "253", "254", "255"
+};
+
+/** Convert an IP address to printable ASCII form.
+ * This is generally deprecated in favor of ircd_ntoa_r().
+ * @param[in] in Address to convert.
+ * @return Pointer to a static buffer containing the readable form.
+ */
+const char* ircd_ntoa(const struct irc_in_addr* in)
+{
+  static char buf[SOCKIPLEN];
+  return ircd_ntoa_r(buf, in);
+}
+
+/** Convert an IP address to printable ASCII form.
+ * @param[out] buf Output buffer to write to.
+ * @param[in] in Address to format.
+ * @return Pointer to the output buffer \a buf.
+ */
+const char* ircd_ntoa_r(char* buf, const struct irc_in_addr* in)
+{
+    assert(buf != NULL);
+    assert(in != NULL);
+
+    if (irc_in_addr_is_ipv4(in)) {
+      unsigned int pos, len;
+      unsigned char *pch;
+
+      pch = (unsigned char*)&in->in6_16[6];
+      len = strlen(IpQuadTab[*pch]);
+      memcpy(buf, IpQuadTab[*pch++], len);
+      pos = len;
+      buf[pos++] = '.';
+      len = strlen(IpQuadTab[*pch]);
+      memcpy(buf+pos, IpQuadTab[*pch++], len);
+      pos += len;
+      buf[pos++] = '.';
+      len = strlen(IpQuadTab[*pch]);
+      memcpy(buf+pos, IpQuadTab[*pch++], len);
+      pos += len;
+      buf[pos++] = '.';
+      len = strlen(IpQuadTab[*pch]);
+      memcpy(buf+pos, IpQuadTab[*pch++], len);
+      buf[pos + len] = '\0';
+      return buf;
+    } else {
+      static const char hexdigits[] = "0123456789abcdef";
+      unsigned int pos, part, max_start, max_zeros, curr_zeros, ii;
+
+      /* Find longest run of zeros. */
+      for (max_start = ii = 1, max_zeros = curr_zeros = 0; ii < 8; ++ii) {
+        if (!in->in6_16[ii])
+          curr_zeros++;
+        else if (curr_zeros > max_zeros) {
+          max_start = ii - curr_zeros;
+          max_zeros = curr_zeros;
+          curr_zeros = 0;
+        }
+      }
+      if (curr_zeros > max_zeros) {
+        max_start = ii - curr_zeros;
+        max_zeros = curr_zeros;
+      }
+
+      /* Print out address. */
+/** Append \a CH to the output buffer. */
+#define APPEND(CH) do { buf[pos++] = (CH); } while (0)
+      for (pos = ii = 0; (ii < 8); ++ii) {
+        if ((max_zeros > 0) && (ii == max_start)) {
+          APPEND(':');
+          ii += max_zeros - 1;
+          continue;
+        }
+        part = ntohs(in->in6_16[ii]);
+        if (part >= 0x1000)
+          APPEND(hexdigits[part >> 12]);
+        if (part >= 0x100)
+          APPEND(hexdigits[(part >> 8) & 15]);
+        if (part >= 0x10)
+          APPEND(hexdigits[(part >> 4) & 15]);
+        APPEND(hexdigits[part & 15]);
+        if (ii < 7)
+          APPEND(':');
+      }
+#undef APPEND
+
+      /* Nul terminate and return number of characters used. */
+      buf[pos++] = '\0';
+      return buf;
+    }
+}
+
+/** Attempt to parse an IPv4 address into a network-endian form.
+ * @param[in] input Input string.
+ * @param[out] output Network-endian representation of the address.
+ * @param[out] pbits Number of bits found in pbits.
+ * @return Number of characters used from \a input, or 0 if the parse failed.
+ */
+static unsigned int
+ircd_aton_ip4(const char *input, unsigned int *output, unsigned char *pbits)
+{
+  unsigned int dots = 0, pos = 0, part = 0, ip = 0, bits;
+
+  /* Intentionally no support for bizarre IPv4 formats (plain
+   * integers, octal or hex components) -- only vanilla dotted
+   * decimal quads.
+   */
+  if (input[0] == '.')
+    return 0;
+  bits = 32;
+  while (1) switch (input[pos]) {
+  case '\0':
+    if (dots < 3)
+      return 0;
+  out:
+    ip |= part << (24 - 8 * dots);
+    *output = htonl(ip);
+    if (pbits)
+      *pbits = bits;
+    return pos;
+  case '.':
+    if (++dots > 3)
+      return 0;
+    if (input[++pos] == '.')
+      return 0;
+    ip |= part << (32 - 8 * dots);
+    part = 0;
+    if (input[pos] == '*') {
+      while (input[++pos] == '*' || input[pos] == '.') ;
+      if (input[pos] != '\0')
+        return 0;
+      if (pbits)
+        *pbits = dots * 8;
+      *output = htonl(ip);
+      return pos;
+    }
+    break;
+  case '/':
+    if (!pbits || !IsDigit(input[pos + 1]))
+      return 0;
+    for (bits = 0; IsDigit(input[++pos]); )
+      bits = bits * 10 + input[pos] - '0';
+    if (bits > 32)
+      return 0;
+    goto out;
+  case '0': case '1': case '2': case '3': case '4':
+  case '5': case '6': case '7': case '8': case '9':
+    part = part * 10 + input[pos++] - '0';
+    if (part > 255)
+      return 0;
+    break;
+  default:
+    return 0;
+  }
+}
+
+/** Parse a numeric IPv4 or IPv6 address into an irc_in_addr.
+ * @param[in] input Input buffer.
+ * @param[out] ip Receives parsed IP address.
+ * @param[out] pbits If non-NULL, receives number of bits specified in address mask.
+ * @return Number of characters used from \a input, or 0 if the
+ * address was unparseable or malformed.
+ */
+int
+ipmask_parse(const char *input, struct irc_in_addr *ip, unsigned char *pbits)
+{
+  char *colon;
+  char *dot;
+
+  assert(ip);
+  assert(input);
+  memset(ip, 0, sizeof(*ip));
+  colon = strchr(input, ':');
+  dot = strchr(input, '.');
+
+  if (colon && (!dot || (dot > colon))) {
+    unsigned int part = 0, pos = 0, ii = 0, colon = 8;
+    const char *part_start = NULL;
+
+    /* Parse IPv6, possibly like ::127.0.0.1.
+     * This is pretty straightforward; the only trick is borrowed
+     * from Paul Vixie (BIND): when it sees a "::" continue as if
+     * it were a single ":", but note where it happened, and fill
+     * with zeros afterward.
+     */
+    if (input[pos] == ':') {
+      if ((input[pos+1] != ':') || (input[pos+2] == ':'))
+        return 0;
+      colon = 0;
+      pos += 2;
+      part_start = input + pos;
+    }
+    while (ii < 8) switch (input[pos]) {
+      unsigned char chval;
+    case '0': case '1': case '2': case '3': case '4':
+    case '5': case '6': case '7': case '8': case '9':
+      chval = input[pos] - '0';
+    use_chval:
+      part = (part << 4) | chval;
+      if (part > 0xffff)
+        return 0;
+      pos++;
+      break;
+    case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
+      chval = input[pos] - 'A' + 10;
+      goto use_chval;
+    case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
+      chval = input[pos] - 'a' + 10;
+      goto use_chval;
+    case ':':
+      part_start = input + ++pos;
+      if (input[pos] == '.')
+        return 0;
+      ip->in6_16[ii++] = htons(part);
+      part = 0;
+      if (input[pos] == ':') {
+        if (colon < 8)
+          return 0;
+        colon = ii;
+        pos++;
+      }
+      break;
+    case '.': {
+      uint32_t ip4;
+      unsigned int len;
+      len = ircd_aton_ip4(part_start, &ip4, pbits);
+      if (!len || (ii > 6))
+        return 0;
+      ip->in6_16[ii++] = htons(ntohl(ip4) >> 16);
+      ip->in6_16[ii++] = htons(ntohl(ip4) & 65535);
+      if (pbits)
+        *pbits += 96;
+      pos = part_start + len - input;
+      goto finish;
+    }
+    case '/':
+      if (!pbits || !IsDigit(input[pos + 1]))
+        return 0;
+      ip->in6_16[ii++] = htons(part);
+      for (part = 0; IsDigit(input[++pos]); )
+        part = part * 10 + input[pos] - '0';
+      if (part > 128)
+        return 0;
+      *pbits = part;
+      goto finish;
+    case '*':
+      while (input[++pos] == '*' || input[pos] == ':') ;
+      if (input[pos] != '\0' || colon < 8)
+        return 0;
+      if (pbits)
+        *pbits = ii * 16;
+      return pos;
+    case '\0':
+      ip->in6_16[ii++] = htons(part);
+      if (colon == 8 && ii < 8)
+        return 0;
+      if (pbits)
+        *pbits = 128;
+      goto finish;
+    default:
+      return 0;
+    }
+  finish:
+    if (colon < 8) {
+      unsigned int jj;
+      /* Shift stuff after "::" up and fill middle with zeros. */
+      for (jj = 0; jj < ii - colon; jj++)
+        ip->in6_16[7 - jj] = ip->in6_16[ii - jj - 1];
+      for (jj = 0; jj < 8 - ii; jj++)
+        ip->in6_16[colon + jj] = 0;
+    }
+    return pos;
+  } else if (dot || strchr(input, '/')) {
+    unsigned int addr;
+    int len = ircd_aton_ip4(input, &addr, pbits);
+    if (len) {
+      ip->in6_16[5] = htons(65535);
+      ip->in6_16[6] = htons(ntohl(addr) >> 16);
+      ip->in6_16[7] = htons(ntohl(addr) & 65535);
+      if (pbits)
+        *pbits += 96;
+    }
+    return len;
+  } else if (input[0] == '*') {
+    unsigned int pos = 0;
+    while (input[++pos] == '*') ;
+    if (input[pos] != '\0')
+      return 0;
+    if (pbits)
+      *pbits = 0;
+    return pos;
+  } else return 0; /* parse failed */
+}
diff --git a/ircd/jupe.c b/ircd/jupe.c
new file mode 100644 (file)
index 0000000..245d504
--- /dev/null
@@ -0,0 +1,420 @@
+/*
+ * IRC - Internet Relay Chat, ircd/jupe.c
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ *                    University of Oulu, Finland
+ * Copyright (C) 2000 Kevin L. Mitchell <klmitch@mit.edu>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+/** @file
+ * @brief Implementation of juped server handling functions.
+ * @version $Id: jupe.c 1633 2006-03-25 03:46:56Z entrope $
+ */
+#include "config.h"
+
+#include "jupe.h"
+#include "client.h"
+#include "hash.h"
+#include "ircd.h"
+#include "ircd_alloc.h"
+#include "ircd_features.h"
+#include "ircd_log.h"
+#include "ircd_reply.h"
+#include "ircd_string.h"
+#include "match.h"
+#include "msg.h"
+#include "numeric.h"
+#include "numnicks.h"
+#include "s_bsd.h"
+#include "s_misc.h"
+#include "send.h"
+#include "struct.h"
+#include "sys.h"    /* FALSE bleah */
+
+/* #include <assert.h> -- Now using assert in ircd_log.h */
+#include <string.h>
+
+/** List of jupes. */
+static struct Jupe *GlobalJupeList = 0;
+
+/** Allocate a new jupe with the given parameters.
+ * @param[in] server Server name to jupe.
+ * @param[in] reason Reason for jupe.
+ * @param[in] expire Expiration time for jupe.
+ * @param[in] lastmod Last modification time for jupe.
+ * @param[in] flags Flags to set for the jupe.
+ */
+static struct Jupe *
+make_jupe(char *server, char *reason, time_t expire, time_t lastmod,
+         unsigned int flags)
+{
+  struct Jupe *ajupe;
+
+  ajupe = (struct Jupe*) MyMalloc(sizeof(struct Jupe)); /* alloc memory */
+  assert(0 != ajupe);
+
+  memset(ajupe, 0, sizeof(*ajupe));
+  DupString(ajupe->ju_server, server); /* copy vital information */
+  DupString(ajupe->ju_reason, reason);
+  ajupe->ju_expire = expire;
+  ajupe->ju_lastmod = lastmod;
+  ajupe->ju_flags = flags & JUPE_MASK; /* set jupe flags */
+
+  ajupe->ju_next = GlobalJupeList; /* link it into the list */
+  ajupe->ju_prev_p = &GlobalJupeList;
+  if (GlobalJupeList)
+    GlobalJupeList->ju_prev_p = &ajupe->ju_next;
+  GlobalJupeList = ajupe;
+
+  return ajupe;
+}
+
+/** Apply a jupe.
+ * @param[in] cptr Local client that sent us the jupe.
+ * @param[in] sptr Originator of the jupe.
+ * @param[in] jupe Jupe to check.
+ */
+static int
+do_jupe(struct Client *cptr, struct Client *sptr, struct Jupe *jupe)
+{
+  struct Client *acptr;
+
+  if (!JupeIsActive(jupe)) /* no action to be taken on inactive jupes */
+    return 0;
+
+  acptr = FindServer(jupe->ju_server);
+
+  /* server isn't online or isn't local or is me */
+  if (!acptr || !MyConnect(acptr) || IsMe(acptr))
+    return 0;
+
+  return exit_client_msg(cptr, acptr, &me, "Juped: %s", jupe->ju_reason);
+}
+
+/** Forward a jupe to another server.
+ * @param[in] cptr Local client that sent us the jupe.
+ * @param[in] sptr Originator of the jupe.
+ * @param[in] jupe Jupe to forward.
+ */
+static void
+propagate_jupe(struct Client *cptr, struct Client *sptr, struct Jupe *jupe)
+{
+  if (JupeIsLocal(jupe)) /* don't propagate local jupes */
+    return;
+
+  sendcmdto_serv_butone(sptr, CMD_JUPE, cptr, "* %c%s %Tu %Tu :%s",
+                       JupeIsRemActive(jupe) ? '+' : '-', jupe->ju_server,
+                       jupe->ju_expire - CurrentTime, jupe->ju_lastmod,
+                       jupe->ju_reason);
+}
+
+/** Add a new server jupe.
+ * @param[in] cptr Local client that sent us the jupe.
+ * @param[in] sptr Originator of the jupe.
+ * @param[in] server Server name to jupe.
+ * @param[in] reason Reason for the jupe.
+ * @param[in] expire Jupe duration in seconds.
+ * @param[in] lastmod Last modification timestamp (or NULL).
+ * @param[in] flags Flags to set on jupe.
+ * @return Zero, unless the jupe causes \a cptr to be SQUIT, in which
+ * case CPTR_KILLED.
+ */
+int
+jupe_add(struct Client *cptr, struct Client *sptr, char *server, char *reason,
+        time_t expire, time_t lastmod, unsigned int flags)
+{
+  struct Jupe *ajupe;
+
+  assert(0 != server);
+  assert(0 != reason);
+
+  /*
+   * You cannot set a negative (or zero) expire time, nor can you set an
+   * expiration time for greater than JUPE_MAX_EXPIRE.
+   */
+  if (expire <= 0 || expire > JUPE_MAX_EXPIRE) {
+    if (!IsServer(cptr) && MyConnect(cptr))
+      send_reply(cptr, ERR_BADEXPIRE, expire);
+    return 0;
+  }
+
+  expire += CurrentTime; /* convert from lifetime to timestamp */
+
+  /* Inform ops and log it */
+  sendto_opmask_butone(0, SNO_NETWORK, "%s adding %sJUPE for %s, expiring at "
+                       "%Tu: %s",
+                       (feature_bool(FEAT_HIS_SNOTICES) || IsServer(sptr)) ?
+                         cli_name(sptr) :
+                         cli_name((cli_user(sptr))->server),
+                      flags & JUPE_LOCAL ? "local " : "", server,
+                      expire + TSoffset, reason);
+
+  log_write(LS_JUPE, L_INFO, LOG_NOSNOTICE,
+           "%#C adding %sJUPE for %s, expiring at %Tu: %s", sptr,
+           flags & JUPE_LOCAL ? "local " : "", server, expire + TSoffset,
+           reason);
+
+  /* make the jupe */
+  ajupe = make_jupe(server, reason, expire, lastmod, flags);
+
+  propagate_jupe(cptr, sptr, ajupe);
+
+  return do_jupe(cptr, sptr, ajupe); /* remove server if necessary */
+}
+
+/** Activate a jupe, optionally changing its lastmod and flags.
+ * @param[in] cptr Local client that sent us the jupe.
+ * @param[in] sptr Originator of the jupe.
+ * @param[in] jupe Jupe to activate.
+ * @param[in] lastmod New timestamp for last modification of the jupe.
+ * @param[in] flags Flags to set on the jupe.
+ * @return Zero, unless the jupe causes \a cptr to be SQUIT, in which
+ * case CPTR_KILLED.
+ */
+int
+jupe_activate(struct Client *cptr, struct Client *sptr, struct Jupe *jupe,
+             time_t lastmod, unsigned int flags)
+{
+  unsigned int saveflags = 0;
+
+  assert(0 != jupe);
+
+  saveflags = jupe->ju_flags;
+
+  if (flags & JUPE_LOCAL)
+    jupe->ju_flags &= ~JUPE_LDEACT;
+  else {
+    jupe->ju_flags |= JUPE_ACTIVE;
+
+    if (jupe->ju_lastmod >= lastmod) /* force lastmod to increase */
+      jupe->ju_lastmod++;
+    else
+      jupe->ju_lastmod = lastmod;
+  }
+
+  if ((saveflags & JUPE_ACTMASK) == JUPE_ACTIVE)
+    return 0; /* was active to begin with */
+
+  /* Inform ops and log it */
+  sendto_opmask_butone(0, SNO_NETWORK, "%s activating JUPE for %s, expiring "
+                      "at %Tu: %s",
+                       (feature_bool(FEAT_HIS_SNOTICES) || IsServer(sptr)) ?
+                         cli_name(sptr) :
+                         cli_name((cli_user(sptr))->server),
+                      jupe->ju_server, jupe->ju_expire + TSoffset,
+                      jupe->ju_reason);
+
+  log_write(LS_JUPE, L_INFO, LOG_NOSNOTICE,
+           "%#C activating JUPE for %s, expiring at %Tu: %s",sptr,
+           jupe->ju_server, jupe->ju_expire + TSoffset, jupe->ju_reason);
+
+  if (!(flags & JUPE_LOCAL)) /* don't propagate local changes */
+    propagate_jupe(cptr, sptr, jupe);
+
+  return do_jupe(cptr, sptr, jupe);
+}
+
+/** Deactivate a jupe.
+ * @param[in] cptr Local client that sent us the jupe.
+ * @param[in] sptr Originator of the jupe.
+ * @param[in] jupe Jupe to deactivate.
+ * @param[in] lastmod New timestamp for last modification of the jupe.
+ * @param[in] flags Flags to set on the jupe.
+ * @return Zero.
+ */
+int
+jupe_deactivate(struct Client *cptr, struct Client *sptr, struct Jupe *jupe,
+               time_t lastmod, unsigned int flags)
+{
+  unsigned int saveflags = 0;
+
+  assert(0 != jupe);
+
+  saveflags = jupe->ju_flags;
+
+  if (!JupeIsLocal(jupe)) {
+    if (flags & JUPE_LOCAL)
+      jupe->ju_flags |= JUPE_LDEACT;
+    else {
+      jupe->ju_flags &= ~JUPE_ACTIVE;
+
+      if (jupe->ju_lastmod >= lastmod) /* force lastmod to increase */
+       jupe->ju_lastmod++;
+      else
+       jupe->ju_lastmod = lastmod;
+    }
+
+    if ((saveflags & JUPE_ACTMASK) != JUPE_ACTIVE)
+      return 0; /* was inactive to begin with */
+  }
+
+  /* Inform ops and log it */
+  sendto_opmask_butone(0, SNO_NETWORK, "%s %s JUPE for %s, expiring at %Tu: "
+                      "%s",
+                       (feature_bool(FEAT_HIS_SNOTICES) || IsServer(sptr)) ?
+                         cli_name(sptr) :
+                         cli_name((cli_user(sptr))->server),
+                      JupeIsLocal(jupe) ? "removing local" : "deactivating",
+                      jupe->ju_server, jupe->ju_expire + TSoffset,
+                      jupe->ju_reason);
+
+  log_write(LS_JUPE, L_INFO, LOG_NOSNOTICE,
+           "%#C %s JUPE for %s, expiring at %Tu: %s", sptr,
+           JupeIsLocal(jupe) ? "removing local" : "deactivating",
+           jupe->ju_server, jupe->ju_expire + TSoffset, jupe->ju_reason);
+
+  if (JupeIsLocal(jupe))
+    jupe_free(jupe);
+  else if (!(flags & JUPE_LOCAL)) /* don't propagate local changes */
+    propagate_jupe(cptr, sptr, jupe);
+
+  return 0;
+}
+
+/** Find a jupe by name.
+ * @param[in] server %Jupe name to search for.
+ * @return Matching jupe (or NULL if none match).
+ */
+struct Jupe *
+jupe_find(char *server)
+{
+  struct Jupe* jupe;
+  struct Jupe* sjupe;
+
+  for (jupe = GlobalJupeList; jupe; jupe = sjupe) { /* go through jupes */
+    sjupe = jupe->ju_next;
+
+    if (jupe->ju_expire <= CurrentTime) /* expire any that need expiring */
+      jupe_free(jupe);
+    else if (0 == ircd_strcmp(server, jupe->ju_server)) /* found it yet? */
+      return jupe;
+  }
+
+  return 0;
+}
+
+/** Unlink and free an unused jupe.
+ * @param[in] jupe Server jupe to free.
+ */
+void
+jupe_free(struct Jupe* jupe)
+{
+  assert(0 != jupe);
+
+  *jupe->ju_prev_p = jupe->ju_next; /* squeeze this jupe out */
+  if (jupe->ju_next)
+    jupe->ju_next->ju_prev_p = jupe->ju_prev_p;
+
+  MyFree(jupe->ju_server);  /* and free up the memory */
+  MyFree(jupe->ju_reason);
+  MyFree(jupe);
+}
+
+/** Send the full list of active global jupes to \a cptr.
+ * @param[in] cptr Local server to send jupes to.
+ */
+void
+jupe_burst(struct Client *cptr)
+{
+  struct Jupe *jupe;
+  struct Jupe *sjupe;
+
+  for (jupe = GlobalJupeList; jupe; jupe = sjupe) { /* go through jupes */
+    sjupe = jupe->ju_next;
+
+    if (jupe->ju_expire <= CurrentTime) /* expire any that need expiring */
+      jupe_free(jupe);
+    else if (!JupeIsLocal(jupe)) /* forward global jupes */
+      sendcmdto_one(&me, CMD_JUPE, cptr, "* %c%s %Tu %Tu :%s",
+                   JupeIsRemActive(jupe) ? '+' : '-', jupe->ju_server,
+                   jupe->ju_expire - CurrentTime, jupe->ju_lastmod,
+                   jupe->ju_reason);
+  }
+}
+
+/** Forward a jupe to another server.
+ * @param[in] cptr %Server to send jupe to.
+ * @param[in] jupe Jupe to forward.
+ */
+int
+jupe_resend(struct Client *cptr, struct Jupe *jupe)
+{
+  if (JupeIsLocal(jupe)) /* don't propagate local jupes */
+    return 0;
+
+  sendcmdto_one(&me, CMD_JUPE, cptr, "* %c%s %Tu %Tu :%s",
+               JupeIsRemActive(jupe) ? '+' : '-', jupe->ju_server,
+               jupe->ju_expire - CurrentTime, jupe->ju_lastmod,
+               jupe->ju_reason);
+
+  return 0;
+}
+
+/** Send a jupe (or a list of jupes) to a server.
+ * @param[in] sptr Client searching for jupes.
+ * @param[in] server Name of jupe to search for (if NULL, list all).
+ * @return Zero.
+ */
+int
+jupe_list(struct Client *sptr, char *server)
+{
+  struct Jupe *jupe;
+  struct Jupe *sjupe;
+
+  if (server) {
+    if (!(jupe = jupe_find(server))) /* no such jupe */
+      return send_reply(sptr, ERR_NOSUCHJUPE, server);
+
+    /* send jupe information along */
+    send_reply(sptr, RPL_JUPELIST, jupe->ju_server, jupe->ju_expire + TSoffset,
+              JupeIsLocal(jupe) ? cli_name(&me) : "*",
+              JupeIsActive(jupe) ? '+' : '-', jupe->ju_reason);
+  } else {
+    for (jupe = GlobalJupeList; jupe; jupe = sjupe) { /* go through jupes */
+      sjupe = jupe->ju_next;
+
+      if (jupe->ju_expire <= CurrentTime) /* expire any that need expiring */
+       jupe_free(jupe);
+      else /* send jupe information along */
+       send_reply(sptr, RPL_JUPELIST, jupe->ju_server,
+                  jupe->ju_expire + TSoffset,
+                  JupeIsLocal(jupe) ? cli_name(&me) : "*",
+                  JupeIsActive(jupe) ? '+' : '-', jupe->ju_reason);
+    }
+  }
+
+  /* end of jupe information */
+  return send_reply(sptr, RPL_ENDOFJUPELIST);
+}
+
+/** Count jupes and memory used by them.
+ * @param[out] ju_size Receives total number of bytes allocated for jupes.
+ * @return Number of jupes currently allocated.
+ */
+int
+jupe_memory_count(size_t *ju_size)
+{
+  struct Jupe *jupe;
+  unsigned int ju = 0;
+
+  for (jupe = GlobalJupeList; jupe; jupe = jupe->ju_next)
+  {
+    ju++;
+    *ju_size += sizeof(struct Jupe);
+    *ju_size += jupe->ju_server ? (strlen(jupe->ju_server) + 1) : 0;
+    *ju_size += jupe->ju_reason ? (strlen(jupe->ju_reason) + 1) : 0;
+  }
+  return ju;
+}
diff --git a/ircd/lex.yy.c b/ircd/lex.yy.c
new file mode 100644 (file)
index 0000000..89b8e9d
--- /dev/null
@@ -0,0 +1,2027 @@
+
+#line 3 "lex.yy.c"
+
+#define  YY_INT_ALIGNED short int
+
+/* A lexical scanner generated by flex */
+
+#define FLEX_SCANNER
+#define YY_FLEX_MAJOR_VERSION 2
+#define YY_FLEX_MINOR_VERSION 5
+#define YY_FLEX_SUBMINOR_VERSION 35
+#if YY_FLEX_SUBMINOR_VERSION > 0
+#define FLEX_BETA
+#endif
+
+/* First, we deal with  platform-specific or compiler-specific issues. */
+
+/* begin standard C headers. */
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <stdlib.h>
+
+/* end standard C headers. */
+
+/* flex integer type definitions */
+
+#ifndef FLEXINT_H
+#define FLEXINT_H
+
+/* C99 systems have <inttypes.h>. Non-C99 systems may or may not. */
+
+#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
+
+/* C99 says to define __STDC_LIMIT_MACROS before including stdint.h,
+ * if you want the limit (max/min) macros for int types. 
+ */
+#ifndef __STDC_LIMIT_MACROS
+#define __STDC_LIMIT_MACROS 1
+#endif
+
+#include <inttypes.h>
+typedef int8_t flex_int8_t;
+typedef uint8_t flex_uint8_t;
+typedef int16_t flex_int16_t;
+typedef uint16_t flex_uint16_t;
+typedef int32_t flex_int32_t;
+typedef uint32_t flex_uint32_t;
+#else
+typedef signed char flex_int8_t;
+typedef short int flex_int16_t;
+typedef int flex_int32_t;
+typedef unsigned char flex_uint8_t; 
+typedef unsigned short int flex_uint16_t;
+typedef unsigned int flex_uint32_t;
+
+/* Limits of integral types. */
+#ifndef INT8_MIN
+#define INT8_MIN               (-128)
+#endif
+#ifndef INT16_MIN
+#define INT16_MIN              (-32767-1)
+#endif
+#ifndef INT32_MIN
+#define INT32_MIN              (-2147483647-1)
+#endif
+#ifndef INT8_MAX
+#define INT8_MAX               (127)
+#endif
+#ifndef INT16_MAX
+#define INT16_MAX              (32767)
+#endif
+#ifndef INT32_MAX
+#define INT32_MAX              (2147483647)
+#endif
+#ifndef UINT8_MAX
+#define UINT8_MAX              (255U)
+#endif
+#ifndef UINT16_MAX
+#define UINT16_MAX             (65535U)
+#endif
+#ifndef UINT32_MAX
+#define UINT32_MAX             (4294967295U)
+#endif
+
+#endif /* ! C99 */
+
+#endif /* ! FLEXINT_H */
+
+#ifdef __cplusplus
+
+/* The "const" storage-class-modifier is valid. */
+#define YY_USE_CONST
+
+#else  /* ! __cplusplus */
+
+/* C99 requires __STDC__ to be defined as 1. */
+#if defined (__STDC__)
+
+#define YY_USE_CONST
+
+#endif /* defined (__STDC__) */
+#endif /* ! __cplusplus */
+
+#ifdef YY_USE_CONST
+#define yyconst const
+#else
+#define yyconst
+#endif
+
+/* Returned upon end-of-file. */
+#define YY_NULL 0
+
+/* Promotes a possibly negative, possibly signed char to an unsigned
+ * integer for use as an array index.  If the signed char is negative,
+ * we want to instead treat it as an 8-bit unsigned char, hence the
+ * double cast.
+ */
+#define YY_SC_TO_UI(c) ((unsigned int) (unsigned char) c)
+
+/* Enter a start condition.  This macro really ought to take a parameter,
+ * but we do it the disgusting crufty way forced on us by the ()-less
+ * definition of BEGIN.
+ */
+#define BEGIN (yy_start) = 1 + 2 *
+
+/* Translate the current start state into a value that can be later handed
+ * to BEGIN to return to the state.  The YYSTATE alias is for lex
+ * compatibility.
+ */
+#define YY_START (((yy_start) - 1) / 2)
+#define YYSTATE YY_START
+
+/* Action number for EOF rule of a given start state. */
+#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1)
+
+/* Special action meaning "start processing a new file". */
+#define YY_NEW_FILE yyrestart(yyin  )
+
+#define YY_END_OF_BUFFER_CHAR 0
+
+/* Size of default input buffer. */
+#ifndef YY_BUF_SIZE
+#ifdef __ia64__
+/* On IA-64, the buffer size is 16k, not 8k.
+ * Moreover, YY_BUF_SIZE is 2*YY_READ_BUF_SIZE in the general case.
+ * Ditto for the __ia64__ case accordingly.
+ */
+#define YY_BUF_SIZE 32768
+#else
+#define YY_BUF_SIZE 16384
+#endif /* __ia64__ */
+#endif
+
+/* The state buf must be large enough to hold one state per character in the main buffer.
+ */
+#define YY_STATE_BUF_SIZE   ((YY_BUF_SIZE + 2) * sizeof(yy_state_type))
+
+#ifndef YY_TYPEDEF_YY_BUFFER_STATE
+#define YY_TYPEDEF_YY_BUFFER_STATE
+typedef struct yy_buffer_state *YY_BUFFER_STATE;
+#endif
+
+extern int yyleng;
+
+extern FILE *yyin, *yyout;
+
+#define EOB_ACT_CONTINUE_SCAN 0
+#define EOB_ACT_END_OF_FILE 1
+#define EOB_ACT_LAST_MATCH 2
+
+    #define YY_LESS_LINENO(n)
+    
+/* Return all but the first "n" matched characters back to the input stream. */
+#define yyless(n) \
+       do \
+               { \
+               /* Undo effects of setting up yytext. */ \
+        int yyless_macro_arg = (n); \
+        YY_LESS_LINENO(yyless_macro_arg);\
+               *yy_cp = (yy_hold_char); \
+               YY_RESTORE_YY_MORE_OFFSET \
+               (yy_c_buf_p) = yy_cp = yy_bp + yyless_macro_arg - YY_MORE_ADJ; \
+               YY_DO_BEFORE_ACTION; /* set up yytext again */ \
+               } \
+       while ( 0 )
+
+#define unput(c) yyunput( c, (yytext_ptr)  )
+
+#ifndef YY_TYPEDEF_YY_SIZE_T
+#define YY_TYPEDEF_YY_SIZE_T
+typedef size_t yy_size_t;
+#endif
+
+#ifndef YY_STRUCT_YY_BUFFER_STATE
+#define YY_STRUCT_YY_BUFFER_STATE
+struct yy_buffer_state
+       {
+       FILE *yy_input_file;
+
+       char *yy_ch_buf;                /* input buffer */
+       char *yy_buf_pos;               /* current position in input buffer */
+
+       /* Size of input buffer in bytes, not including room for EOB
+        * characters.
+        */
+       yy_size_t yy_buf_size;
+
+       /* Number of characters read into yy_ch_buf, not including EOB
+        * characters.
+        */
+       int yy_n_chars;
+
+       /* Whether we "own" the buffer - i.e., we know we created it,
+        * and can realloc() it to grow it, and should free() it to
+        * delete it.
+        */
+       int yy_is_our_buffer;
+
+       /* Whether this is an "interactive" input source; if so, and
+        * if we're using stdio for input, then we want to use getc()
+        * instead of fread(), to make sure we stop fetching input after
+        * each newline.
+        */
+       int yy_is_interactive;
+
+       /* Whether we're considered to be at the beginning of a line.
+        * If so, '^' rules will be active on the next match, otherwise
+        * not.
+        */
+       int yy_at_bol;
+
+    int yy_bs_lineno; /**< The line count. */
+    int yy_bs_column; /**< The column count. */
+    
+       /* Whether to try to fill the input buffer when we reach the
+        * end of it.
+        */
+       int yy_fill_buffer;
+
+       int yy_buffer_status;
+
+#define YY_BUFFER_NEW 0
+#define YY_BUFFER_NORMAL 1
+       /* When an EOF's been seen but there's still some text to process
+        * then we mark the buffer as YY_EOF_PENDING, to indicate that we
+        * shouldn't try reading from the input source any more.  We might
+        * still have a bunch of tokens to match, though, because of
+        * possible backing-up.
+        *
+        * When we actually see the EOF, we change the status to "new"
+        * (via yyrestart()), so that the user can continue scanning by
+        * just pointing yyin at a new input file.
+        */
+#define YY_BUFFER_EOF_PENDING 2
+
+       };
+#endif /* !YY_STRUCT_YY_BUFFER_STATE */
+
+/* Stack of input buffers. */
+static size_t yy_buffer_stack_top = 0; /**< index of top of stack. */
+static size_t yy_buffer_stack_max = 0; /**< capacity of stack. */
+static YY_BUFFER_STATE * yy_buffer_stack = 0; /**< Stack as an array. */
+
+/* We provide macros for accessing buffer states in case in the
+ * future we want to put the buffer states in a more general
+ * "scanner state".
+ *
+ * Returns the top of the stack, or NULL.
+ */
+#define YY_CURRENT_BUFFER ( (yy_buffer_stack) \
+                          ? (yy_buffer_stack)[(yy_buffer_stack_top)] \
+                          : NULL)
+
+/* Same as previous macro, but useful when we know that the buffer stack is not
+ * NULL or when we need an lvalue. For internal use only.
+ */
+#define YY_CURRENT_BUFFER_LVALUE (yy_buffer_stack)[(yy_buffer_stack_top)]
+
+/* yy_hold_char holds the character lost when yytext is formed. */
+static char yy_hold_char;
+static int yy_n_chars;         /* number of characters read into yy_ch_buf */
+int yyleng;
+
+/* Points to current character in buffer. */
+static char *yy_c_buf_p = (char *) 0;
+static int yy_init = 0;                /* whether we need to initialize */
+static int yy_start = 0;       /* start state number */
+
+/* Flag which is used to allow yywrap()'s to do buffer switches
+ * instead of setting up a fresh yyin.  A bit of a hack ...
+ */
+static int yy_did_buffer_switch_on_eof;
+
+void yyrestart (FILE *input_file  );
+void yy_switch_to_buffer (YY_BUFFER_STATE new_buffer  );
+YY_BUFFER_STATE yy_create_buffer (FILE *file,int size  );
+void yy_delete_buffer (YY_BUFFER_STATE b  );
+void yy_flush_buffer (YY_BUFFER_STATE b  );
+void yypush_buffer_state (YY_BUFFER_STATE new_buffer  );
+void yypop_buffer_state (void );
+
+static void yyensure_buffer_stack (void );
+static void yy_load_buffer_state (void );
+static void yy_init_buffer (YY_BUFFER_STATE b,FILE *file  );
+
+#define YY_FLUSH_BUFFER yy_flush_buffer(YY_CURRENT_BUFFER )
+
+YY_BUFFER_STATE yy_scan_buffer (char *base,yy_size_t size  );
+YY_BUFFER_STATE yy_scan_string (yyconst char *yy_str  );
+YY_BUFFER_STATE yy_scan_bytes (yyconst char *bytes,int len  );
+
+void *yyalloc (yy_size_t  );
+void *yyrealloc (void *,yy_size_t  );
+void yyfree (void *  );
+
+#define yy_new_buffer yy_create_buffer
+
+#define yy_set_interactive(is_interactive) \
+       { \
+       if ( ! YY_CURRENT_BUFFER ){ \
+        yyensure_buffer_stack (); \
+               YY_CURRENT_BUFFER_LVALUE =    \
+            yy_create_buffer(yyin,YY_BUF_SIZE ); \
+       } \
+       YY_CURRENT_BUFFER_LVALUE->yy_is_interactive = is_interactive; \
+       }
+
+#define yy_set_bol(at_bol) \
+       { \
+       if ( ! YY_CURRENT_BUFFER ){\
+        yyensure_buffer_stack (); \
+               YY_CURRENT_BUFFER_LVALUE =    \
+            yy_create_buffer(yyin,YY_BUF_SIZE ); \
+       } \
+       YY_CURRENT_BUFFER_LVALUE->yy_at_bol = at_bol; \
+       }
+
+#define YY_AT_BOL() (YY_CURRENT_BUFFER_LVALUE->yy_at_bol)
+
+typedef unsigned char YY_CHAR;
+
+FILE *yyin = (FILE *) 0, *yyout = (FILE *) 0;
+
+typedef int yy_state_type;
+
+extern int yylineno;
+
+int yylineno = 1;
+
+extern char *yytext;
+#define yytext_ptr yytext
+
+static yy_state_type yy_get_previous_state (void );
+static yy_state_type yy_try_NUL_trans (yy_state_type current_state  );
+static int yy_get_next_buffer (void );
+static void yy_fatal_error (yyconst char msg[]  );
+
+/* Done after the current pattern has been matched and before the
+ * corresponding action - sets up yytext.
+ */
+#define YY_DO_BEFORE_ACTION \
+       (yytext_ptr) = yy_bp; \
+       yyleng = (size_t) (yy_cp - yy_bp); \
+       (yy_hold_char) = *yy_cp; \
+       *yy_cp = '\0'; \
+       (yy_c_buf_p) = yy_cp;
+
+#define YY_NUM_RULES 8
+#define YY_END_OF_BUFFER 9
+/* This struct is not used in this scanner,
+   but its presence is necessary. */
+struct yy_trans_info
+       {
+       flex_int32_t yy_verify;
+       flex_int32_t yy_nxt;
+       };
+static yyconst flex_int16_t yy_acclist[25] =
+    {   0,
+        9,    7,    8,    3,    7,    8,    6,    8,    7,    8,
+        4,    7,    8,    2,    7,    8,    5,    7,    8,    3,
+        4,    2,    5,    1
+    } ;
+
+static yyconst flex_int16_t yy_accept[19] =
+    {   0,
+        1,    1,    1,    2,    4,    7,    9,   11,   14,   17,
+       20,   21,   21,   22,   23,   24,   25,   25
+    } ;
+
+static yyconst flex_int32_t yy_ec[256] =
+    {   0,
+        1,    1,    1,    1,    1,    1,    1,    1,    2,    3,
+        1,    1,    2,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    2,    1,    4,    5,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    6,    6,    6,
+        6,    6,    6,    6,    6,    6,    6,    1,    1,    1,
+        1,    1,    1,    1,    7,    7,    7,    7,    7,    7,
+        7,    7,    7,    7,    7,    7,    7,    7,    7,    7,
+        7,    7,    7,    7,    7,    7,    7,    7,    7,    7,
+        1,    1,    1,    1,    7,    1,    7,    7,    7,    7,
+
+        7,    7,    7,    7,    7,    7,    7,    7,    7,    7,
+        7,    7,    7,    7,    7,    7,    7,    7,    7,    7,
+        7,    7,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1
+    } ;
+
+static yyconst flex_int32_t yy_meta[8] =
+    {   0,
+        1,    1,    2,    3,    1,    4,    4
+    } ;
+
+static yyconst flex_int16_t yy_base[21] =
+    {   0,
+        0,    0,   20,   21,   17,   21,    0,    0,   12,    0,
+       13,    5,    0,    6,    0,   21,   21,    9,   13,    7
+    } ;
+
+static yyconst flex_int16_t yy_def[21] =
+    {   0,
+       17,    1,   17,   17,   17,   17,   18,   19,   17,   20,
+       17,   18,   19,   17,   20,   17,    0,   17,   17,   17
+    } ;
+
+static yyconst flex_int16_t yy_nxt[29] =
+    {   0,
+        4,    5,    6,    7,    8,    9,   10,   16,   16,   12,
+       15,   14,   12,   13,   11,   13,   13,   14,   11,   17,
+        3,   17,   17,   17,   17,   17,   17,   17
+    } ;
+
+static yyconst flex_int16_t yy_chk[29] =
+    {   0,
+        1,    1,    1,    1,    1,    1,    1,   12,   12,   18,
+       20,   14,   18,   19,   11,   19,   19,    9,    5,    3,
+       17,   17,   17,   17,   17,   17,   17,   17
+    } ;
+
+extern int yy_flex_debug;
+int yy_flex_debug = 0;
+
+static yy_state_type *yy_state_buf=0, *yy_state_ptr=0;
+static char *yy_full_match;
+static int yy_lp;
+#define REJECT \
+{ \
+*yy_cp = (yy_hold_char); /* undo effects of setting up yytext */ \
+yy_cp = (yy_full_match); /* restore poss. backed-over text */ \
+++(yy_lp); \
+goto find_rule; \
+}
+
+#define yymore() yymore_used_but_not_detected
+#define YY_MORE_ADJ 0
+#define YY_RESTORE_YY_MORE_OFFSET
+char *yytext;
+#line 1 "./ircd_lexer.l"
+/*
+ * ircd_lexer.l: A lexical scanner for ircd config files.
+ * This is part of ircu, an Internet Relay Chat server.
+ * The contents of this file are Copyright(C) 2001 by Andrew Miller, the
+ * ircd-hybrid team and the ircu team.
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ *  USA.
+ * $Id: ircd_lexer.l 1851 2007-11-30 22:10:04Z klmitch $
+ */
+#line 24 "./ircd_lexer.l"
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "config.h"
+#include "fileio.h"
+#include "ircd.h"
+#include "ircd_alloc.h"
+#include "ircd_string.h"
+#include "s_debug.h"
+#include "y.tab.h"
+
+extern int lineno;
+
+static struct lexer_token {
+  const char *string;
+  int value;
+} tokens[] = {
+#define TOKEN(NAME) { #NAME, NAME }
+  TOKEN(ADMIN),
+  TOKEN(GENERAL),
+  TOKEN(LOCATION),
+  TOKEN(CONTACT),
+  TOKEN(CLASS),
+  TOKEN(PINGFREQ),
+  TOKEN(CONNECT),
+  TOKEN(CONNECTFREQ),
+  TOKEN(MAXLINKS),
+  TOKEN(MAXHOPS),
+  TOKEN(SENDQ),
+  TOKEN(NAME),
+  TOKEN(HOST),
+  TOKEN(IP),
+  TOKEN(USERNAME),
+  TOKEN(PASS),
+  TOKEN(SECONDS),
+  TOKEN(MINUTES),
+  TOKEN(HOURS),
+  TOKEN(DAYS),
+  TOKEN(WEEKS),
+  TOKEN(MONTHS),
+  TOKEN(YEARS),
+  TOKEN(DECADES),
+  TOKEN(BYTES),
+  TOKEN(KBYTES),
+  TOKEN(MBYTES),
+  TOKEN(GBYTES),
+  TOKEN(TBYTES),
+  TOKEN(PORT),
+  TOKEN(SERVER),
+  TOKEN(YES),
+  TOKEN(NO),
+  TOKEN(HUB),
+  TOKEN(LEAF),
+  TOKEN(UWORLD),
+  TOKEN(OPER),
+  TOKEN(LOCAL),
+  TOKEN(VHOST),
+  TOKEN(MASK),
+  TOKEN(HIDDEN),
+  TOKEN(MOTD),
+  TOKEN(NUMERIC),
+  TOKEN(NICK),
+  TOKEN(JUPE),
+  TOKEN(DESCRIPTION),
+  TOKEN(CLIENT),
+  TOKEN(REAL),
+  TOKEN(REASON),
+  TOKEN(RULE),
+  TOKEN(ALL),
+  TOKEN(CRULE),
+  TOKEN(KILL),
+  TOKEN(QUARANTINE),
+  TOKEN(IAUTH),
+  TOKEN(TIMEOUT),
+  TOKEN(FEATURES),
+  TOKEN(CHANNEL),
+  TOKEN(PSEUDO),
+  TOKEN(PREPEND),
+  TOKEN(USERMODE),
+  TOKEN(FAST),
+  TOKEN(AUTOCONNECT),
+  TOKEN(PROGRAM),
+  TOKEN(DNS),
+  TOKEN(FORWARDS),
+  TOKEN(SECURE),
+  TOKEN(WEBIRC),
+  TOKEN(SPOOF),
+  TOKEN(REQUIRED),
+  TOKEN(SSL),
+  TOKEN(CERT),
+  TOKEN(CACERT),
+#undef TOKEN
+  { "administrator", ADMIN },
+  { "apass_opmode", TPRIV_APASS_OPMODE },
+  { "auto", AUTOCONNECT },
+  { "b", BYTES },
+  { "badchan", TPRIV_BADCHAN },
+  { "chan_limit", TPRIV_CHAN_LIMIT },
+  { "deop_lchan", TPRIV_DEOP_LCHAN },
+  { "die", TPRIV_DIE },
+  { "display", TPRIV_DISPLAY },
+  { "file", TFILE },
+  { "force_local_opmode", TPRIV_FORCE_LOCAL_OPMODE },
+  { "force_opmode", TPRIV_FORCE_OPMODE },
+  { "gb", GBYTES },
+  { "gigabytes", GBYTES },
+  { "gline", TPRIV_GLINE },
+#ifdef OLD_OGN_IRCU_COMPAT
+  { "hide_channels", TPRIV_UMODE_NOCHAN },
+  { "hide_idletime", TPRIV_UMODE_NOIDLE },
+#endif
+  { "umode_nochan", TPRIV_UMODE_NOCHAN },
+  { "umode_noidle", TPRIV_UMODE_NOIDLE },
+  { "extra_hide_idletime", TPRIV_HIDE_IDLETIME },
+#ifndef OLD_OGN_IRCU_COMPAT
+  { "hide_idletime", TPRIV_HIDE_IDLETIME },
+#endif
+  { "ipv4", TOK_IPV4 },
+  { "ipv6", TOK_IPV6 },
+  { "kb", KBYTES },
+  { "kilobytes", KBYTES },
+  { "list_chan", TPRIV_LIST_CHAN },
+  { "local_badchan", TPRIV_LOCAL_BADCHAN },
+  { "local_gline", TPRIV_LOCAL_GLINE },
+  { "local_jupe", TPRIV_LOCAL_JUPE },
+  { "local_kill", TPRIV_LOCAL_KILL },
+  { "local_opmode", TPRIV_LOCAL_OPMODE },
+  { "maxchans", MAXCHANS },
+  { "mb", MBYTES },
+  { "megabytes", MBYTES },
+  { "mode_lchan", TPRIV_MODE_LCHAN },
+  { "more_flood", TPRIV_HALFFLOOD },
+  { "noamsg_override", TPRIV_NOAMSG_OVERRIDE },
+  { "operator", OPER },
+  { "opmode", TPRIV_OPMODE },
+  { "password", PASS },
+  { "propagate", TPRIV_PROPAGATE },
+  { "realname", REAL },
+  { "rehash", TPRIV_REHASH },
+  { "restart", TPRIV_RESTART },
+  { "see_chan", TPRIV_SEE_CHAN },
+  { "see_idletime", TPRIV_SEE_IDLETIME },
+  { "see_opers", TPRIV_SEE_OPERS },
+  { "set", TPRIV_SET },
+  { "show_all_invis", TPRIV_SHOW_ALL_INVIS },
+  { "show_invis", TPRIV_SHOW_INVIS },
+#ifdef OLD_OGN_IRCU_COMPAT
+  { "targetchange", TPRIV_UNLIMITED_TARGET },
+#endif
+  { "unlimited_targets", TPRIV_UNLIMITED_TARGET },
+  { "tb", TBYTES },
+  { "terabytes", TBYTES },
+  { "umode_chserv", TPRIV_UMODE_CHSERV },
+  { "umode_xtraop", TPRIV_UMODE_XTRAOP },
+  { "umode_netserv", TPRIV_UMODE_NETSERV },
+  { "umode_overridecc", TPRIV_UMODE_OVERRIDECC },
+  { "unlimit_query", TPRIV_UNLIMIT_QUERY },
+  { "unlimited_flood", TPRIV_FLOOD },
+  { "walk_lchan", TPRIV_WALK_LCHAN },
+  { "wide_gline", TPRIV_WIDE_GLINE },
+  { "whox", TPRIV_WHOX },
+  { NULL, 0 }
+};
+static int ntokens;
+
+static int
+token_compare(const void *pa, const void *pb)
+{
+  const struct lexer_token *ta = pa;
+  const struct lexer_token *tb = pb;
+  unsigned int ii = 0;
+  int res;
+  while (ta->string[ii] && (ToLower(ta->string[ii]) == ToLower(tb->string[ii])))
+    ii++;
+  res = ToLower(tb->string[ii]) - ToLower(ta->string[ii]);
+  return res;
+}
+
+static void
+init_ntokens(void)
+{
+  for (ntokens = 0; tokens[ntokens].string; ++ntokens) ;
+  qsort(tokens, ntokens, sizeof(tokens[0]), token_compare);
+}
+
+static int
+find_token(char *token)
+{
+  struct lexer_token *tok;
+  if (!ntokens)
+    init_ntokens();
+  tok = bsearch(&token, tokens, ntokens, sizeof(tokens[0]), token_compare);
+  return tok ? tok->value : 0;
+}
+
+static FBFILE *lexer_input;
+
+#undef YY_INPUT
+#define YY_INPUT(buf, res, size) res = (fbgets(buf, size, lexer_input) ? strlen(buf) : 0)
+
+int
+init_lexer(void)
+{
+  lexer_input = fbopen(configfile, "r");
+  if (lexer_input == NULL)
+  {
+#ifdef YY_FATAL_ERROR
+    YY_FATAL_ERROR("Could not open the configuration file.");
+#else
+    fprintf(stderr, "Could not open the configuration file.");
+#endif
+    return 0;
+  }
+#ifdef YY_NEW_FILE
+  YY_NEW_FILE;
+#endif
+  lineno = 1;
+  return 1;
+}
+
+void deinit_lexer(void)
+{
+  if (lexer_input != NULL)
+  {
+    fbclose(lexer_input);
+    lexer_input = NULL;
+  }
+}
+
+int
+yywrap(void)
+{
+  return 1;
+}
+
+#line 732 "lex.yy.c"
+
+#define INITIAL 0
+
+#ifndef YY_NO_UNISTD_H
+/* Special case for "unistd.h", since it is non-ANSI. We include it way
+ * down here because we want the user's section 1 to have been scanned first.
+ * The user has a chance to override it with an option.
+ */
+#include <unistd.h>
+#endif
+
+#ifndef YY_EXTRA_TYPE
+#define YY_EXTRA_TYPE void *
+#endif
+
+static int yy_init_globals (void );
+
+/* Accessor methods to globals.
+   These are made visible to non-reentrant scanners for convenience. */
+
+int yylex_destroy (void );
+
+int yyget_debug (void );
+
+void yyset_debug (int debug_flag  );
+
+YY_EXTRA_TYPE yyget_extra (void );
+
+void yyset_extra (YY_EXTRA_TYPE user_defined  );
+
+FILE *yyget_in (void );
+
+void yyset_in  (FILE * in_str  );
+
+FILE *yyget_out (void );
+
+void yyset_out  (FILE * out_str  );
+
+int yyget_leng (void );
+
+char *yyget_text (void );
+
+int yyget_lineno (void );
+
+void yyset_lineno (int line_number  );
+
+/* Macros after this point can all be overridden by user definitions in
+ * section 1.
+ */
+
+#ifndef YY_SKIP_YYWRAP
+#ifdef __cplusplus
+extern "C" int yywrap (void );
+#else
+extern int yywrap (void );
+#endif
+#endif
+
+    static void yyunput (int c,char *buf_ptr  );
+    
+#ifndef yytext_ptr
+static void yy_flex_strncpy (char *,yyconst char *,int );
+#endif
+
+#ifdef YY_NEED_STRLEN
+static int yy_flex_strlen (yyconst char * );
+#endif
+
+#ifndef YY_NO_INPUT
+
+#ifdef __cplusplus
+static int yyinput (void );
+#else
+static int input (void );
+#endif
+
+#endif
+
+/* Amount of stuff to slurp up with each read. */
+#ifndef YY_READ_BUF_SIZE
+#ifdef __ia64__
+/* On IA-64, the buffer size is 16k, not 8k */
+#define YY_READ_BUF_SIZE 16384
+#else
+#define YY_READ_BUF_SIZE 8192
+#endif /* __ia64__ */
+#endif
+
+/* Copy whatever the last rule matched to the standard output. */
+#ifndef ECHO
+/* This used to be an fputs(), but since the string might contain NUL's,
+ * we now use fwrite().
+ */
+#define ECHO do { if (fwrite( yytext, yyleng, 1, yyout )) {} } while (0)
+#endif
+
+/* Gets input and stuffs it into "buf".  number of characters read, or YY_NULL,
+ * is returned in "result".
+ */
+#ifndef YY_INPUT
+#define YY_INPUT(buf,result,max_size) \
+       if ( YY_CURRENT_BUFFER_LVALUE->yy_is_interactive ) \
+               { \
+               int c = '*'; \
+               size_t n; \
+               for ( n = 0; n < max_size && \
+                            (c = getc( yyin )) != EOF && c != '\n'; ++n ) \
+                       buf[n] = (char) c; \
+               if ( c == '\n' ) \
+                       buf[n++] = (char) c; \
+               if ( c == EOF && ferror( yyin ) ) \
+                       YY_FATAL_ERROR( "input in flex scanner failed" ); \
+               result = n; \
+               } \
+       else \
+               { \
+               errno=0; \
+               while ( (result = fread(buf, 1, max_size, yyin))==0 && ferror(yyin)) \
+                       { \
+                       if( errno != EINTR) \
+                               { \
+                               YY_FATAL_ERROR( "input in flex scanner failed" ); \
+                               break; \
+                               } \
+                       errno=0; \
+                       clearerr(yyin); \
+                       } \
+               }\
+\
+
+#endif
+
+/* No semi-colon after return; correct usage is to write "yyterminate();" -
+ * we don't want an extra ';' after the "return" because that will cause
+ * some compilers to complain about unreachable statements.
+ */
+#ifndef yyterminate
+#define yyterminate() return YY_NULL
+#endif
+
+/* Number of entries by which start-condition stack grows. */
+#ifndef YY_START_STACK_INCR
+#define YY_START_STACK_INCR 25
+#endif
+
+/* Report a fatal error. */
+#ifndef YY_FATAL_ERROR
+#define YY_FATAL_ERROR(msg) yy_fatal_error( msg )
+#endif
+
+/* end tables serialization structures and prototypes */
+
+/* Default declaration of generated scanner - a define so the user can
+ * easily add parameters.
+ */
+#ifndef YY_DECL
+#define YY_DECL_IS_OURS 1
+
+extern int yylex (void);
+
+#define YY_DECL int yylex (void)
+#endif /* !YY_DECL */
+
+/* Code executed at the beginning of each rule, after yytext and yyleng
+ * have been set up.
+ */
+#ifndef YY_USER_ACTION
+#define YY_USER_ACTION
+#endif
+
+/* Code executed at the end of each rule. */
+#ifndef YY_BREAK
+#define YY_BREAK break;
+#endif
+
+#define YY_RULE_SETUP \
+       YY_USER_ACTION
+
+/** The main scanner function which does all the work.
+ */
+YY_DECL
+{
+       register yy_state_type yy_current_state;
+       register char *yy_cp, *yy_bp;
+       register int yy_act;
+    
+#line 266 "./ircd_lexer.l"
+
+
+#line 922 "lex.yy.c"
+
+       if ( !(yy_init) )
+               {
+               (yy_init) = 1;
+
+#ifdef YY_USER_INIT
+               YY_USER_INIT;
+#endif
+
+        /* Create the reject buffer large enough to save one state per allowed character. */
+        if ( ! (yy_state_buf) )
+            (yy_state_buf) = (yy_state_type *)yyalloc(YY_STATE_BUF_SIZE  );
+            if ( ! (yy_state_buf) )
+                YY_FATAL_ERROR( "out of dynamic memory in yylex()" );
+
+               if ( ! (yy_start) )
+                       (yy_start) = 1; /* first start state */
+
+               if ( ! yyin )
+                       yyin = stdin;
+
+               if ( ! yyout )
+                       yyout = stdout;
+
+               if ( ! YY_CURRENT_BUFFER ) {
+                       yyensure_buffer_stack ();
+                       YY_CURRENT_BUFFER_LVALUE =
+                               yy_create_buffer(yyin,YY_BUF_SIZE );
+               }
+
+               yy_load_buffer_state( );
+               }
+
+       while ( 1 )             /* loops until end-of-file is reached */
+               {
+               yy_cp = (yy_c_buf_p);
+
+               /* Support of yytext. */
+               *yy_cp = (yy_hold_char);
+
+               /* yy_bp points to the position in yy_ch_buf of the start of
+                * the current run.
+                */
+               yy_bp = yy_cp;
+
+               yy_current_state = (yy_start);
+
+               (yy_state_ptr) = (yy_state_buf);
+               *(yy_state_ptr)++ = yy_current_state;
+
+yy_match:
+               do
+                       {
+                       register YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)];
+                       while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+                               {
+                               yy_current_state = (int) yy_def[yy_current_state];
+                               if ( yy_current_state >= 18 )
+                                       yy_c = yy_meta[(unsigned int) yy_c];
+                               }
+                       yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+                       *(yy_state_ptr)++ = yy_current_state;
+                       ++yy_cp;
+                       }
+               while ( yy_base[yy_current_state] != 21 );
+
+yy_find_action:
+               yy_current_state = *--(yy_state_ptr);
+               (yy_lp) = yy_accept[yy_current_state];
+find_rule: /* we branch to this label when backing up */
+               for ( ; ; ) /* until we find what rule we matched */
+                       {
+                       if ( (yy_lp) && (yy_lp) < yy_accept[yy_current_state + 1] )
+                               {
+                               yy_act = yy_acclist[(yy_lp)];
+                                       {
+                                       (yy_full_match) = yy_cp;
+                                       break;
+                                       }
+                               }
+                       --yy_cp;
+                       yy_current_state = *--(yy_state_ptr);
+                       (yy_lp) = yy_accept[yy_current_state];
+                       }
+
+               YY_DO_BEFORE_ACTION;
+
+do_action:     /* This label is used only to access EOF actions. */
+
+               switch ( yy_act )
+       { /* beginning of action switch */
+case 1:
+/* rule 1 can match eol */
+YY_RULE_SETUP
+#line 268 "./ircd_lexer.l"
+{yytext[yyleng-1] = 0; DupString(yylval.text, yytext+1); return QSTRING;}
+       YY_BREAK
+case 2:
+YY_RULE_SETUP
+#line 269 "./ircd_lexer.l"
+{yylval.num = strtoul(yytext, NULL, 10); return NUMBER;}
+       YY_BREAK
+case 3:
+YY_RULE_SETUP
+#line 270 "./ircd_lexer.l"
+;
+       YY_BREAK
+case 4:
+YY_RULE_SETUP
+#line 271 "./ircd_lexer.l"
+;
+       YY_BREAK
+case 5:
+YY_RULE_SETUP
+#line 273 "./ircd_lexer.l"
+{ int res = find_token(yytext); if (res) return res; else REJECT; }
+       YY_BREAK
+case 6:
+/* rule 6 can match eol */
+YY_RULE_SETUP
+#line 274 "./ircd_lexer.l"
+lineno++;
+       YY_BREAK
+case 7:
+YY_RULE_SETUP
+#line 275 "./ircd_lexer.l"
+return yytext[0];
+       YY_BREAK
+case 8:
+YY_RULE_SETUP
+#line 276 "./ircd_lexer.l"
+ECHO;
+       YY_BREAK
+#line 1056 "lex.yy.c"
+                       case YY_STATE_EOF(INITIAL):
+                               yyterminate();
+
+       case YY_END_OF_BUFFER:
+               {
+               /* Amount of text matched not including the EOB char. */
+               int yy_amount_of_matched_text = (int) (yy_cp - (yytext_ptr)) - 1;
+
+               /* Undo the effects of YY_DO_BEFORE_ACTION. */
+               *yy_cp = (yy_hold_char);
+               YY_RESTORE_YY_MORE_OFFSET
+
+               if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_NEW )
+                       {
+                       /* We're scanning a new file or input source.  It's
+                        * possible that this happened because the user
+                        * just pointed yyin at a new source and called
+                        * yylex().  If so, then we have to assure
+                        * consistency between YY_CURRENT_BUFFER and our
+                        * globals.  Here is the right place to do so, because
+                        * this is the first action (other than possibly a
+                        * back-up) that will match for the new input source.
+                        */
+                       (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars;
+                       YY_CURRENT_BUFFER_LVALUE->yy_input_file = yyin;
+                       YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_NORMAL;
+                       }
+
+               /* Note that here we test for yy_c_buf_p "<=" to the position
+                * of the first EOB in the buffer, since yy_c_buf_p will
+                * already have been incremented past the NUL character
+                * (since all states make transitions on EOB to the
+                * end-of-buffer state).  Contrast this with the test
+                * in input().
+                */
+               if ( (yy_c_buf_p) <= &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] )
+                       { /* This was really a NUL. */
+                       yy_state_type yy_next_state;
+
+                       (yy_c_buf_p) = (yytext_ptr) + yy_amount_of_matched_text;
+
+                       yy_current_state = yy_get_previous_state(  );
+
+                       /* Okay, we're now positioned to make the NUL
+                        * transition.  We couldn't have
+                        * yy_get_previous_state() go ahead and do it
+                        * for us because it doesn't know how to deal
+                        * with the possibility of jamming (and we don't
+                        * want to build jamming into it because then it
+                        * will run more slowly).
+                        */
+
+                       yy_next_state = yy_try_NUL_trans( yy_current_state );
+
+                       yy_bp = (yytext_ptr) + YY_MORE_ADJ;
+
+                       if ( yy_next_state )
+                               {
+                               /* Consume the NUL. */
+                               yy_cp = ++(yy_c_buf_p);
+                               yy_current_state = yy_next_state;
+                               goto yy_match;
+                               }
+
+                       else
+                               {
+                               yy_cp = (yy_c_buf_p);
+                               goto yy_find_action;
+                               }
+                       }
+
+               else switch ( yy_get_next_buffer(  ) )
+                       {
+                       case EOB_ACT_END_OF_FILE:
+                               {
+                               (yy_did_buffer_switch_on_eof) = 0;
+
+                               if ( yywrap( ) )
+                                       {
+                                       /* Note: because we've taken care in
+                                        * yy_get_next_buffer() to have set up
+                                        * yytext, we can now set up
+                                        * yy_c_buf_p so that if some total
+                                        * hoser (like flex itself) wants to
+                                        * call the scanner after we return the
+                                        * YY_NULL, it'll still work - another
+                                        * YY_NULL will get returned.
+                                        */
+                                       (yy_c_buf_p) = (yytext_ptr) + YY_MORE_ADJ;
+
+                                       yy_act = YY_STATE_EOF(YY_START);
+                                       goto do_action;
+                                       }
+
+                               else
+                                       {
+                                       if ( ! (yy_did_buffer_switch_on_eof) )
+                                               YY_NEW_FILE;
+                                       }
+                               break;
+                               }
+
+                       case EOB_ACT_CONTINUE_SCAN:
+                               (yy_c_buf_p) =
+                                       (yytext_ptr) + yy_amount_of_matched_text;
+
+                               yy_current_state = yy_get_previous_state(  );
+
+                               yy_cp = (yy_c_buf_p);
+                               yy_bp = (yytext_ptr) + YY_MORE_ADJ;
+                               goto yy_match;
+
+                       case EOB_ACT_LAST_MATCH:
+                               (yy_c_buf_p) =
+                               &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)];
+
+                               yy_current_state = yy_get_previous_state(  );
+
+                               yy_cp = (yy_c_buf_p);
+                               yy_bp = (yytext_ptr) + YY_MORE_ADJ;
+                               goto yy_find_action;
+                       }
+               break;
+               }
+
+       default:
+               YY_FATAL_ERROR(
+                       "fatal flex scanner internal error--no action found" );
+       } /* end of action switch */
+               } /* end of scanning one token */
+} /* end of yylex */
+
+/* yy_get_next_buffer - try to read in a new buffer
+ *
+ * Returns a code representing an action:
+ *     EOB_ACT_LAST_MATCH -
+ *     EOB_ACT_CONTINUE_SCAN - continue scanning from current position
+ *     EOB_ACT_END_OF_FILE - end of file
+ */
+static int yy_get_next_buffer (void)
+{
+       register char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf;
+       register char *source = (yytext_ptr);
+       register int number_to_move, i;
+       int ret_val;
+
+       if ( (yy_c_buf_p) > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] )
+               YY_FATAL_ERROR(
+               "fatal flex scanner internal error--end of buffer missed" );
+
+       if ( YY_CURRENT_BUFFER_LVALUE->yy_fill_buffer == 0 )
+               { /* Don't try to fill the buffer, so this is an EOF. */
+               if ( (yy_c_buf_p) - (yytext_ptr) - YY_MORE_ADJ == 1 )
+                       {
+                       /* We matched a single character, the EOB, so
+                        * treat this as a final EOF.
+                        */
+                       return EOB_ACT_END_OF_FILE;
+                       }
+
+               else
+                       {
+                       /* We matched some text prior to the EOB, first
+                        * process it.
+                        */
+                       return EOB_ACT_LAST_MATCH;
+                       }
+               }
+
+       /* Try to read more data. */
+
+       /* First move last chars to start of buffer. */
+       number_to_move = (int) ((yy_c_buf_p) - (yytext_ptr)) - 1;
+
+       for ( i = 0; i < number_to_move; ++i )
+               *(dest++) = *(source++);
+
+       if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_EOF_PENDING )
+               /* don't do the read, it's not guaranteed to return an EOF,
+                * just force an EOF
+                */
+               YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars) = 0;
+
+       else
+               {
+                       int num_to_read =
+                       YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1;
+
+               while ( num_to_read <= 0 )
+                       { /* Not enough room in the buffer - grow it. */
+
+                       YY_FATAL_ERROR(
+"input buffer overflow, can't enlarge buffer because scanner uses REJECT" );
+
+                       }
+
+               if ( num_to_read > YY_READ_BUF_SIZE )
+                       num_to_read = YY_READ_BUF_SIZE;
+
+               /* Read in more data. */
+               YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]),
+                       (yy_n_chars), (size_t) num_to_read );
+
+               YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars);
+               }
+
+       if ( (yy_n_chars) == 0 )
+               {
+               if ( number_to_move == YY_MORE_ADJ )
+                       {
+                       ret_val = EOB_ACT_END_OF_FILE;
+                       yyrestart(yyin  );
+                       }
+
+               else
+                       {
+                       ret_val = EOB_ACT_LAST_MATCH;
+                       YY_CURRENT_BUFFER_LVALUE->yy_buffer_status =
+                               YY_BUFFER_EOF_PENDING;
+                       }
+               }
+
+       else
+               ret_val = EOB_ACT_CONTINUE_SCAN;
+
+       if ((yy_size_t) ((yy_n_chars) + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) {
+               /* Extend the array by 50%, plus the number we really need. */
+               yy_size_t new_size = (yy_n_chars) + number_to_move + ((yy_n_chars) >> 1);
+               YY_CURRENT_BUFFER_LVALUE->yy_ch_buf = (char *) yyrealloc((void *) YY_CURRENT_BUFFER_LVALUE->yy_ch_buf,new_size  );
+               if ( ! YY_CURRENT_BUFFER_LVALUE->yy_ch_buf )
+                       YY_FATAL_ERROR( "out of dynamic memory in yy_get_next_buffer()" );
+       }
+
+       (yy_n_chars) += number_to_move;
+       YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] = YY_END_OF_BUFFER_CHAR;
+       YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] = YY_END_OF_BUFFER_CHAR;
+
+       (yytext_ptr) = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[0];
+
+       return ret_val;
+}
+
+/* yy_get_previous_state - get the state just before the EOB char was reached */
+
+    static yy_state_type yy_get_previous_state (void)
+{
+       register yy_state_type yy_current_state;
+       register char *yy_cp;
+    
+       yy_current_state = (yy_start);
+
+       (yy_state_ptr) = (yy_state_buf);
+       *(yy_state_ptr)++ = yy_current_state;
+
+       for ( yy_cp = (yytext_ptr) + YY_MORE_ADJ; yy_cp < (yy_c_buf_p); ++yy_cp )
+               {
+               register YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1);
+               while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+                       {
+                       yy_current_state = (int) yy_def[yy_current_state];
+                       if ( yy_current_state >= 18 )
+                               yy_c = yy_meta[(unsigned int) yy_c];
+                       }
+               yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+               *(yy_state_ptr)++ = yy_current_state;
+               }
+
+       return yy_current_state;
+}
+
+/* yy_try_NUL_trans - try to make a transition on the NUL character
+ *
+ * synopsis
+ *     next_state = yy_try_NUL_trans( current_state );
+ */
+    static yy_state_type yy_try_NUL_trans  (yy_state_type yy_current_state )
+{
+       register int yy_is_jam;
+    
+       register YY_CHAR yy_c = 1;
+       while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+               {
+               yy_current_state = (int) yy_def[yy_current_state];
+               if ( yy_current_state >= 18 )
+                       yy_c = yy_meta[(unsigned int) yy_c];
+               }
+       yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+       yy_is_jam = (yy_current_state == 17);
+       if ( ! yy_is_jam )
+               *(yy_state_ptr)++ = yy_current_state;
+
+       return yy_is_jam ? 0 : yy_current_state;
+}
+
+    static void yyunput (int c, register char * yy_bp )
+{
+       register char *yy_cp;
+    
+    yy_cp = (yy_c_buf_p);
+
+       /* undo effects of setting up yytext */
+       *yy_cp = (yy_hold_char);
+
+       if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 )
+               { /* need to shift things up to make room */
+               /* +2 for EOB chars. */
+               register int number_to_move = (yy_n_chars) + 2;
+               register char *dest = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[
+                                       YY_CURRENT_BUFFER_LVALUE->yy_buf_size + 2];
+               register char *source =
+                               &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move];
+
+               while ( source > YY_CURRENT_BUFFER_LVALUE->yy_ch_buf )
+                       *--dest = *--source;
+
+               yy_cp += (int) (dest - source);
+               yy_bp += (int) (dest - source);
+               YY_CURRENT_BUFFER_LVALUE->yy_n_chars =
+                       (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_buf_size;
+
+               if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 )
+                       YY_FATAL_ERROR( "flex scanner push-back overflow" );
+               }
+
+       *--yy_cp = (char) c;
+
+       (yytext_ptr) = yy_bp;
+       (yy_hold_char) = *yy_cp;
+       (yy_c_buf_p) = yy_cp;
+}
+
+#ifndef YY_NO_INPUT
+#ifdef __cplusplus
+    static int yyinput (void)
+#else
+    static int input  (void)
+#endif
+
+{
+       int c;
+    
+       *(yy_c_buf_p) = (yy_hold_char);
+
+       if ( *(yy_c_buf_p) == YY_END_OF_BUFFER_CHAR )
+               {
+               /* yy_c_buf_p now points to the character we want to return.
+                * If this occurs *before* the EOB characters, then it's a
+                * valid NUL; if not, then we've hit the end of the buffer.
+                */
+               if ( (yy_c_buf_p) < &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] )
+                       /* This was really a NUL. */
+                       *(yy_c_buf_p) = '\0';
+
+               else
+                       { /* need more input */
+                       int offset = (yy_c_buf_p) - (yytext_ptr);
+                       ++(yy_c_buf_p);
+
+                       switch ( yy_get_next_buffer(  ) )
+                               {
+                               case EOB_ACT_LAST_MATCH:
+                                       /* This happens because yy_g_n_b()
+                                        * sees that we've accumulated a
+                                        * token and flags that we need to
+                                        * try matching the token before
+                                        * proceeding.  But for input(),
+                                        * there's no matching to consider.
+                                        * So convert the EOB_ACT_LAST_MATCH
+                                        * to EOB_ACT_END_OF_FILE.
+                                        */
+
+                                       /* Reset buffer status. */
+                                       yyrestart(yyin );
+
+                                       /*FALLTHROUGH*/
+
+                               case EOB_ACT_END_OF_FILE:
+                                       {
+                                       if ( yywrap( ) )
+                                               return EOF;
+
+                                       if ( ! (yy_did_buffer_switch_on_eof) )
+                                               YY_NEW_FILE;
+#ifdef __cplusplus
+                                       return yyinput();
+#else
+                                       return input();
+#endif
+                                       }
+
+                               case EOB_ACT_CONTINUE_SCAN:
+                                       (yy_c_buf_p) = (yytext_ptr) + offset;
+                                       break;
+                               }
+                       }
+               }
+
+       c = *(unsigned char *) (yy_c_buf_p);    /* cast for 8-bit char's */
+       *(yy_c_buf_p) = '\0';   /* preserve yytext */
+       (yy_hold_char) = *++(yy_c_buf_p);
+
+       return c;
+}
+#endif /* ifndef YY_NO_INPUT */
+
+/** Immediately switch to a different input stream.
+ * @param input_file A readable stream.
+ * 
+ * @note This function does not reset the start condition to @c INITIAL .
+ */
+    void yyrestart  (FILE * input_file )
+{
+    
+       if ( ! YY_CURRENT_BUFFER ){
+        yyensure_buffer_stack ();
+               YY_CURRENT_BUFFER_LVALUE =
+            yy_create_buffer(yyin,YY_BUF_SIZE );
+       }
+
+       yy_init_buffer(YY_CURRENT_BUFFER,input_file );
+       yy_load_buffer_state( );
+}
+
+/** Switch to a different input buffer.
+ * @param new_buffer The new input buffer.
+ * 
+ */
+    void yy_switch_to_buffer  (YY_BUFFER_STATE  new_buffer )
+{
+    
+       /* TODO. We should be able to replace this entire function body
+        * with
+        *              yypop_buffer_state();
+        *              yypush_buffer_state(new_buffer);
+     */
+       yyensure_buffer_stack ();
+       if ( YY_CURRENT_BUFFER == new_buffer )
+               return;
+
+       if ( YY_CURRENT_BUFFER )
+               {
+               /* Flush out information for old buffer. */
+               *(yy_c_buf_p) = (yy_hold_char);
+               YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p);
+               YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars);
+               }
+
+       YY_CURRENT_BUFFER_LVALUE = new_buffer;
+       yy_load_buffer_state( );
+
+       /* We don't actually know whether we did this switch during
+        * EOF (yywrap()) processing, but the only time this flag
+        * is looked at is after yywrap() is called, so it's safe
+        * to go ahead and always set it.
+        */
+       (yy_did_buffer_switch_on_eof) = 1;
+}
+
+static void yy_load_buffer_state  (void)
+{
+       (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars;
+       (yytext_ptr) = (yy_c_buf_p) = YY_CURRENT_BUFFER_LVALUE->yy_buf_pos;
+       yyin = YY_CURRENT_BUFFER_LVALUE->yy_input_file;
+       (yy_hold_char) = *(yy_c_buf_p);
+}
+
+/** Allocate and initialize an input buffer state.
+ * @param file A readable stream.
+ * @param size The character buffer size in bytes. When in doubt, use @c YY_BUF_SIZE.
+ * 
+ * @return the allocated buffer state.
+ */
+    YY_BUFFER_STATE yy_create_buffer  (FILE * file, int  size )
+{
+       YY_BUFFER_STATE b;
+    
+       b = (YY_BUFFER_STATE) yyalloc(sizeof( struct yy_buffer_state )  );
+       if ( ! b )
+               YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" );
+
+       b->yy_buf_size = size;
+
+       /* yy_ch_buf has to be 2 characters longer than the size given because
+        * we need to put in 2 end-of-buffer characters.
+        */
+       b->yy_ch_buf = (char *) yyalloc(b->yy_buf_size + 2  );
+       if ( ! b->yy_ch_buf )
+               YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" );
+
+       b->yy_is_our_buffer = 1;
+
+       yy_init_buffer(b,file );
+
+       return b;
+}
+
+/** Destroy the buffer.
+ * @param b a buffer created with yy_create_buffer()
+ * 
+ */
+    void yy_delete_buffer (YY_BUFFER_STATE  b )
+{
+    
+       if ( ! b )
+               return;
+
+       if ( b == YY_CURRENT_BUFFER ) /* Not sure if we should pop here. */
+               YY_CURRENT_BUFFER_LVALUE = (YY_BUFFER_STATE) 0;
+
+       if ( b->yy_is_our_buffer )
+               yyfree((void *) b->yy_ch_buf  );
+
+       yyfree((void *) b  );
+}
+
+#ifndef __cplusplus
+extern int isatty (int );
+#endif /* __cplusplus */
+    
+/* Initializes or reinitializes a buffer.
+ * This function is sometimes called more than once on the same buffer,
+ * such as during a yyrestart() or at EOF.
+ */
+    static void yy_init_buffer  (YY_BUFFER_STATE  b, FILE * file )
+
+{
+       int oerrno = errno;
+    
+       yy_flush_buffer(b );
+
+       b->yy_input_file = file;
+       b->yy_fill_buffer = 1;
+
+    /* If b is the current buffer, then yy_init_buffer was _probably_
+     * called from yyrestart() or through yy_get_next_buffer.
+     * In that case, we don't want to reset the lineno or column.
+     */
+    if (b != YY_CURRENT_BUFFER){
+        b->yy_bs_lineno = 1;
+        b->yy_bs_column = 0;
+    }
+
+        b->yy_is_interactive = file ? (isatty( fileno(file) ) > 0) : 0;
+    
+       errno = oerrno;
+}
+
+/** Discard all buffered characters. On the next scan, YY_INPUT will be called.
+ * @param b the buffer state to be flushed, usually @c YY_CURRENT_BUFFER.
+ * 
+ */
+    void yy_flush_buffer (YY_BUFFER_STATE  b )
+{
+       if ( ! b )
+               return;
+
+       b->yy_n_chars = 0;
+
+       /* We always need two end-of-buffer characters.  The first causes
+        * a transition to the end-of-buffer state.  The second causes
+        * a jam in that state.
+        */
+       b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR;
+       b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR;
+
+       b->yy_buf_pos = &b->yy_ch_buf[0];
+
+       b->yy_at_bol = 1;
+       b->yy_buffer_status = YY_BUFFER_NEW;
+
+       if ( b == YY_CURRENT_BUFFER )
+               yy_load_buffer_state( );
+}
+
+/** Pushes the new state onto the stack. The new state becomes
+ *  the current state. This function will allocate the stack
+ *  if necessary.
+ *  @param new_buffer The new state.
+ *  
+ */
+void yypush_buffer_state (YY_BUFFER_STATE new_buffer )
+{
+       if (new_buffer == NULL)
+               return;
+
+       yyensure_buffer_stack();
+
+       /* This block is copied from yy_switch_to_buffer. */
+       if ( YY_CURRENT_BUFFER )
+               {
+               /* Flush out information for old buffer. */
+               *(yy_c_buf_p) = (yy_hold_char);
+               YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p);
+               YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars);
+               }
+
+       /* Only push if top exists. Otherwise, replace top. */
+       if (YY_CURRENT_BUFFER)
+               (yy_buffer_stack_top)++;
+       YY_CURRENT_BUFFER_LVALUE = new_buffer;
+
+       /* copied from yy_switch_to_buffer. */
+       yy_load_buffer_state( );
+       (yy_did_buffer_switch_on_eof) = 1;
+}
+
+/** Removes and deletes the top of the stack, if present.
+ *  The next element becomes the new top.
+ *  
+ */
+void yypop_buffer_state (void)
+{
+       if (!YY_CURRENT_BUFFER)
+               return;
+
+       yy_delete_buffer(YY_CURRENT_BUFFER );
+       YY_CURRENT_BUFFER_LVALUE = NULL;
+       if ((yy_buffer_stack_top) > 0)
+               --(yy_buffer_stack_top);
+
+       if (YY_CURRENT_BUFFER) {
+               yy_load_buffer_state( );
+               (yy_did_buffer_switch_on_eof) = 1;
+       }
+}
+
+/* Allocates the stack if it does not exist.
+ *  Guarantees space for at least one push.
+ */
+static void yyensure_buffer_stack (void)
+{
+       int num_to_alloc;
+    
+       if (!(yy_buffer_stack)) {
+
+               /* First allocation is just for 2 elements, since we don't know if this
+                * scanner will even need a stack. We use 2 instead of 1 to avoid an
+                * immediate realloc on the next call.
+         */
+               num_to_alloc = 1;
+               (yy_buffer_stack) = (struct yy_buffer_state**)yyalloc
+                                                               (num_to_alloc * sizeof(struct yy_buffer_state*)
+                                                               );
+               if ( ! (yy_buffer_stack) )
+                       YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" );
+                                                                 
+               memset((yy_buffer_stack), 0, num_to_alloc * sizeof(struct yy_buffer_state*));
+                               
+               (yy_buffer_stack_max) = num_to_alloc;
+               (yy_buffer_stack_top) = 0;
+               return;
+       }
+
+       if ((yy_buffer_stack_top) >= ((yy_buffer_stack_max)) - 1){
+
+               /* Increase the buffer to prepare for a possible push. */
+               int grow_size = 8 /* arbitrary grow size */;
+
+               num_to_alloc = (yy_buffer_stack_max) + grow_size;
+               (yy_buffer_stack) = (struct yy_buffer_state**)yyrealloc
+                                                               ((yy_buffer_stack),
+                                                               num_to_alloc * sizeof(struct yy_buffer_state*)
+                                                               );
+               if ( ! (yy_buffer_stack) )
+                       YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" );
+
+               /* zero only the new slots.*/
+               memset((yy_buffer_stack) + (yy_buffer_stack_max), 0, grow_size * sizeof(struct yy_buffer_state*));
+               (yy_buffer_stack_max) = num_to_alloc;
+       }
+}
+
+/** Setup the input buffer state to scan directly from a user-specified character buffer.
+ * @param base the character buffer
+ * @param size the size in bytes of the character buffer
+ * 
+ * @return the newly allocated buffer state object. 
+ */
+YY_BUFFER_STATE yy_scan_buffer  (char * base, yy_size_t  size )
+{
+       YY_BUFFER_STATE b;
+    
+       if ( size < 2 ||
+            base[size-2] != YY_END_OF_BUFFER_CHAR ||
+            base[size-1] != YY_END_OF_BUFFER_CHAR )
+               /* They forgot to leave room for the EOB's. */
+               return 0;
+
+       b = (YY_BUFFER_STATE) yyalloc(sizeof( struct yy_buffer_state )  );
+       if ( ! b )
+               YY_FATAL_ERROR( "out of dynamic memory in yy_scan_buffer()" );
+
+       b->yy_buf_size = size - 2;      /* "- 2" to take care of EOB's */
+       b->yy_buf_pos = b->yy_ch_buf = base;
+       b->yy_is_our_buffer = 0;
+       b->yy_input_file = 0;
+       b->yy_n_chars = b->yy_buf_size;
+       b->yy_is_interactive = 0;
+       b->yy_at_bol = 1;
+       b->yy_fill_buffer = 0;
+       b->yy_buffer_status = YY_BUFFER_NEW;
+
+       yy_switch_to_buffer(b  );
+
+       return b;
+}
+
+/** Setup the input buffer state to scan a string. The next call to yylex() will
+ * scan from a @e copy of @a str.
+ * @param yystr a NUL-terminated string to scan
+ * 
+ * @return the newly allocated buffer state object.
+ * @note If you want to scan bytes that may contain NUL values, then use
+ *       yy_scan_bytes() instead.
+ */
+YY_BUFFER_STATE yy_scan_string (yyconst char * yystr )
+{
+    
+       return yy_scan_bytes(yystr,strlen(yystr) );
+}
+
+/** Setup the input buffer state to scan the given bytes. The next call to yylex() will
+ * scan from a @e copy of @a bytes.
+ * @param yybytes the byte buffer to scan
+ * @param _yybytes_len the number of bytes in the buffer pointed to by @a bytes.
+ * 
+ * @return the newly allocated buffer state object.
+ */
+YY_BUFFER_STATE yy_scan_bytes  (yyconst char * yybytes, int  _yybytes_len )
+{
+       YY_BUFFER_STATE b;
+       char *buf;
+       yy_size_t n;
+       int i;
+    
+       /* Get memory for full buffer, including space for trailing EOB's. */
+       n = _yybytes_len + 2;
+       buf = (char *) yyalloc(n  );
+       if ( ! buf )
+               YY_FATAL_ERROR( "out of dynamic memory in yy_scan_bytes()" );
+
+       for ( i = 0; i < _yybytes_len; ++i )
+               buf[i] = yybytes[i];
+
+       buf[_yybytes_len] = buf[_yybytes_len+1] = YY_END_OF_BUFFER_CHAR;
+
+       b = yy_scan_buffer(buf,n );
+       if ( ! b )
+               YY_FATAL_ERROR( "bad buffer in yy_scan_bytes()" );
+
+       /* It's okay to grow etc. this buffer, and we should throw it
+        * away when we're done.
+        */
+       b->yy_is_our_buffer = 1;
+
+       return b;
+}
+
+#ifndef YY_EXIT_FAILURE
+#define YY_EXIT_FAILURE 2
+#endif
+
+static void yy_fatal_error (yyconst char* msg )
+{
+       (void) fprintf( stderr, "%s\n", msg );
+       exit( YY_EXIT_FAILURE );
+}
+
+/* Redefine yyless() so it works in section 3 code. */
+
+#undef yyless
+#define yyless(n) \
+       do \
+               { \
+               /* Undo effects of setting up yytext. */ \
+        int yyless_macro_arg = (n); \
+        YY_LESS_LINENO(yyless_macro_arg);\
+               yytext[yyleng] = (yy_hold_char); \
+               (yy_c_buf_p) = yytext + yyless_macro_arg; \
+               (yy_hold_char) = *(yy_c_buf_p); \
+               *(yy_c_buf_p) = '\0'; \
+               yyleng = yyless_macro_arg; \
+               } \
+       while ( 0 )
+
+/* Accessor  methods (get/set functions) to struct members. */
+
+/** Get the current line number.
+ * 
+ */
+int yyget_lineno  (void)
+{
+        
+    return yylineno;
+}
+
+/** Get the input stream.
+ * 
+ */
+FILE *yyget_in  (void)
+{
+        return yyin;
+}
+
+/** Get the output stream.
+ * 
+ */
+FILE *yyget_out  (void)
+{
+        return yyout;
+}
+
+/** Get the length of the current token.
+ * 
+ */
+int yyget_leng  (void)
+{
+        return yyleng;
+}
+
+/** Get the current token.
+ * 
+ */
+
+char *yyget_text  (void)
+{
+        return yytext;
+}
+
+/** Set the current line number.
+ * @param line_number
+ * 
+ */
+void yyset_lineno (int  line_number )
+{
+    
+    yylineno = line_number;
+}
+
+/** Set the input stream. This does not discard the current
+ * input buffer.
+ * @param in_str A readable stream.
+ * 
+ * @see yy_switch_to_buffer
+ */
+void yyset_in (FILE *  in_str )
+{
+        yyin = in_str ;
+}
+
+void yyset_out (FILE *  out_str )
+{
+        yyout = out_str ;
+}
+
+int yyget_debug  (void)
+{
+        return yy_flex_debug;
+}
+
+void yyset_debug (int  bdebug )
+{
+        yy_flex_debug = bdebug ;
+}
+
+static int yy_init_globals (void)
+{
+        /* Initialization is the same as for the non-reentrant scanner.
+     * This function is called from yylex_destroy(), so don't allocate here.
+     */
+
+    (yy_buffer_stack) = 0;
+    (yy_buffer_stack_top) = 0;
+    (yy_buffer_stack_max) = 0;
+    (yy_c_buf_p) = (char *) 0;
+    (yy_init) = 0;
+    (yy_start) = 0;
+
+    (yy_state_buf) = 0;
+    (yy_state_ptr) = 0;
+    (yy_full_match) = 0;
+    (yy_lp) = 0;
+
+/* Defined in main.c */
+#ifdef YY_STDINIT
+    yyin = stdin;
+    yyout = stdout;
+#else
+    yyin = (FILE *) 0;
+    yyout = (FILE *) 0;
+#endif
+
+    /* For future reference: Set errno on error, since we are called by
+     * yylex_init()
+     */
+    return 0;
+}
+
+/* yylex_destroy is for both reentrant and non-reentrant scanners. */
+int yylex_destroy  (void)
+{
+    
+    /* Pop the buffer stack, destroying each element. */
+       while(YY_CURRENT_BUFFER){
+               yy_delete_buffer(YY_CURRENT_BUFFER  );
+               YY_CURRENT_BUFFER_LVALUE = NULL;
+               yypop_buffer_state();
+       }
+
+       /* Destroy the stack itself. */
+       yyfree((yy_buffer_stack) );
+       (yy_buffer_stack) = NULL;
+
+    yyfree ( (yy_state_buf) );
+    (yy_state_buf)  = NULL;
+
+    /* Reset the globals. This is important in a non-reentrant scanner so the next time
+     * yylex() is called, initialization will occur. */
+    yy_init_globals( );
+
+    return 0;
+}
+
+/*
+ * Internal utility routines.
+ */
+
+#ifndef yytext_ptr
+static void yy_flex_strncpy (char* s1, yyconst char * s2, int n )
+{
+       register int i;
+       for ( i = 0; i < n; ++i )
+               s1[i] = s2[i];
+}
+#endif
+
+#ifdef YY_NEED_STRLEN
+static int yy_flex_strlen (yyconst char * s )
+{
+       register int n;
+       for ( n = 0; s[n]; ++n )
+               ;
+
+       return n;
+}
+#endif
+
+void *yyalloc (yy_size_t  size )
+{
+       return (void *) malloc( size );
+}
+
+void *yyrealloc  (void * ptr, yy_size_t  size )
+{
+       /* The cast to (char *) in the following accommodates both
+        * implementations that use char* generic pointers, and those
+        * that use void* generic pointers.  It works with the latter
+        * because both ANSI C and C++ allow castless assignment from
+        * any pointer type to void*, and deal with argument conversions
+        * as though doing an assignment.
+        */
+       return (void *) realloc( (char *) ptr, size );
+}
+
+void yyfree (void * ptr )
+{
+       free( (char *) ptr );   /* see yyrealloc() for (char *) cast */
+}
+
+#define YYTABLES_NAME "yytables"
+
+#line 276 "./ircd_lexer.l"
diff --git a/ircd/list.c b/ircd/list.c
new file mode 100644 (file)
index 0000000..6b0bc52
--- /dev/null
@@ -0,0 +1,543 @@
+/*
+ * IRC - Internet Relay Chat, ircd/list.c
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ *                    University of Oulu, Finland
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+/** @file
+ * @brief Singly and doubly linked list manipulation implementation.
+ * @version $Id: list.c 1781 2007-03-18 01:33:02Z entrope $
+ */
+#include "config.h"
+
+#include "list.h"
+#include "client.h"
+#include "ircd.h"
+#include "ircd_alloc.h"
+#include "ircd_events.h"
+#include "ircd_log.h"
+#include "ircd_reply.h"
+#include "ircd_string.h"
+#include "listener.h"
+#include "match.h"
+#include "numeric.h"
+#include "res.h"
+#include "s_auth.h"
+#include "s_bsd.h"
+#include "s_conf.h"
+#include "s_debug.h"
+#include "s_misc.h"
+#include "s_user.h"
+#include "send.h"
+#include "struct.h"
+#include "whowas.h"
+
+/* #include <assert.h> -- Now using assert in ircd_log.h */
+#include <stddef.h>  /* offsetof */
+#include <unistd.h>  /* close */
+#include <string.h>
+
+/** Stores linked list statistics for various types of lists. */
+static struct liststats {
+  size_t alloc; /**< Number of structures ever allocated. */
+  size_t inuse; /**< Number of structures currently in use. */
+  size_t mem;   /**< Memory used by in-use structures. */
+} clients, connections, servs, links;
+
+/** Linked list of currently unused Client structures. */
+static struct Client* clientFreeList;
+
+/** Linked list of currently unused Connection structures. */
+static struct Connection* connectionFreeList;
+
+/** Linked list of currently unused SLink structures. */
+static struct SLink* slinkFreeList;
+
+/** Initialize the list manipulation support system.
+ * Pre-allocate MAXCONNECTIONS Client and Connection structures.
+ */
+void init_list(void)
+{
+  struct Client* cptr;
+  struct Connection* con;
+  int i;
+  /*
+   * pre-allocate MAXCONNECTIONS clients and connections
+   */
+  for (i = 0; i < MAXCONNECTIONS; ++i) {
+    cptr = (struct Client*) MyMalloc(sizeof(struct Client));
+    cli_next(cptr) = clientFreeList;
+    clientFreeList = cptr;
+    clients.alloc++;
+
+    con = (struct Connection*) MyMalloc(sizeof(struct Connection));
+    con_next(con) = connectionFreeList;
+    connectionFreeList = con;
+    connections.alloc++;
+  }
+}
+
+/** Allocate a new Client structure.
+ * If #clientFreeList != NULL, use the head of that list.
+ * Otherwise, allocate a new structure.
+ * @return Newly allocated Client.
+ */
+static struct Client* alloc_client(void)
+{
+  struct Client* cptr = clientFreeList;
+
+  if (!cptr) {
+    cptr = (struct Client*) MyMalloc(sizeof(struct Client));
+    clients.alloc++;
+  } else
+    clientFreeList = cli_next(cptr);
+
+  clients.inuse++;
+
+  memset(cptr, 0, sizeof(struct Client));
+
+  return cptr;
+}
+
+/** Release a Client structure by prepending it to #clientFreeList.
+ * @param[in] cptr Client that is no longer being used.
+ */
+static void dealloc_client(struct Client* cptr)
+{
+  assert(cli_verify(cptr));
+  assert(0 == cli_connect(cptr));
+
+  --clients.inuse;
+
+  cli_next(cptr) = clientFreeList;
+  clientFreeList = cptr;
+
+  cli_magic(cptr) = 0;
+}
+
+/** Allocate a new Connection structure.
+ * If #connectionFreeList != NULL, use the head of that list.
+ * Otherwise, allocate a new structure.
+ * @return Newly allocated Connection.
+ */
+static struct Connection* alloc_connection(void)
+{
+  struct Connection* con = connectionFreeList;
+
+  if (!con) {
+    con = (struct Connection*) MyMalloc(sizeof(struct Connection));
+    connections.alloc++;
+  } else
+    connectionFreeList = con_next(con);
+
+  connections.inuse++;
+
+  memset(con, 0, sizeof(struct Connection));
+  timer_init(&(con_proc(con)));
+
+  return con;
+}
+
+/** Release a Connection and all memory associated with it.
+ * The connection's DNS reply field is freed, its file descriptor is
+ * closed, its msgq and sendq are cleared, and its associated Listener
+ * is dereferenced.  Then it is prepended to #connectionFreeList.
+ * @param[in] con Connection to free.
+ */
+static void dealloc_connection(struct Connection* con)
+{
+  assert(con_verify(con));
+  assert(!t_active(&(con_proc(con))));
+  assert(!t_onqueue(&(con_proc(con))));
+
+  Debug((DEBUG_LIST, "Deallocating connection %p", con));
+
+  if (-1 < con_fd(con))
+    close(con_fd(con));
+  MsgQClear(&(con_sendQ(con)));
+  client_drop_sendq(con);
+  DBufClear(&(con_recvQ(con)));
+  if (con_listener(con))
+    release_listener(con_listener(con));
+
+  --connections.inuse;
+
+  con_next(con) = connectionFreeList;
+  connectionFreeList = con;
+
+  con_magic(con) = 0;
+}
+
+/** Allocate a new client and initialize it.
+ * If \a from == NULL, initialize the fields for a local client,
+ * including allocating a Connection for him; otherwise initialize the
+ * fields for a remote client..
+ * @param[in] from Server connection that introduced the client (or
+ * NULL).
+ * @param[in] status Initial Client::cli_status value.
+ * @return Newly allocated and initialized Client.
+ */
+struct Client* make_client(struct Client *from, int status)
+{
+  struct Client* cptr = 0;
+
+  assert(!from || cli_verify(from));
+
+  cptr = alloc_client();
+
+  assert(0 != cptr);
+  assert(!cli_magic(cptr));
+  assert(0 == from || 0 != cli_connect(from));
+
+  if (!from) { /* local client, allocate a struct Connection */
+    struct Connection *con = alloc_connection();
+
+    assert(0 != con);
+    assert(!con_magic(con));
+
+    con_magic(con) = CONNECTION_MAGIC;
+    con_fd(con) = -1; /* initialize struct Connection */
+    con_freeflag(con) = 0;
+    con_nextnick(con) = CurrentTime - NICK_DELAY;
+    con_nexttarget(con) = CurrentTime - (TARGET_DELAY * (STARTTARGETS - 1));
+    con_handler(con) = UNREGISTERED_HANDLER;
+    con_client(con) = cptr;
+
+    cli_connect(cptr) = con; /* set the connection and other fields */
+    cli_since(cptr) = cli_lasttime(cptr) = cli_firsttime(cptr) = CurrentTime;
+    cli_lastnick(cptr) = TStime();
+  } else
+    cli_connect(cptr) = cli_connect(from); /* use 'from's connection */
+
+  assert(con_verify(cli_connect(cptr)));
+
+  cli_magic(cptr) = CLIENT_MAGIC;
+  cli_status(cptr) = status;
+  cli_hnext(cptr) = cptr;
+  strcpy(cli_username(cptr), "unknown");
+
+  return cptr;
+}
+
+/** Release a Connection.
+ * @param[in] con Connection to free.
+ */
+void free_connection(struct Connection* con)
+{
+  if (!con)
+    return;
+
+  assert(con_verify(con));
+  assert(0 == con_client(con));
+
+  dealloc_connection(con); /* deallocate the connection */
+}
+
+/** Release a Client.
+ * In addition to the cleanup done by dealloc_client(), this will free
+ * any pending auth request, free the connection for local clients,
+ * and delete the processing timer for the client.
+ * @param[in] cptr Client to free.
+ */
+void free_client(struct Client* cptr)
+{
+  if (!cptr)
+    return;
+  /*
+   * forget to remove the client from the hash table?
+   */
+  assert(cli_verify(cptr));
+  assert(cli_hnext(cptr) == cptr);
+  /* or from linked list? */
+  assert(cli_next(cptr) == 0);
+  assert(cli_prev(cptr) == 0);
+
+  Debug((DEBUG_LIST, "Freeing client %s [%p], connection %p", cli_name(cptr),
+        cptr, cli_connect(cptr)));
+
+  if (cli_auth(cptr))
+    destroy_auth_request(cli_auth(cptr));
+
+  /* Make sure we didn't magically get re-added to the list */
+  assert(cli_next(cptr) == 0);
+  assert(cli_prev(cptr) == 0);
+
+  if (cli_from(cptr) == cptr) { /* in other words, we're local */
+    cli_from(cptr) = 0;
+    /* timer must be marked as not active */
+    if (!cli_freeflag(cptr) && !t_active(&(cli_proc(cptr))))
+      dealloc_connection(cli_connect(cptr)); /* connection not open anymore */
+    else {
+      if (-1 < cli_fd(cptr) && cli_freeflag(cptr) & FREEFLAG_SOCKET)
+       socket_del(&(cli_socket(cptr))); /* queue a socket delete */
+      if (cli_freeflag(cptr) & FREEFLAG_TIMER)
+       timer_del(&(cli_proc(cptr))); /* queue a timer delete */
+    }
+  }
+
+  cli_connect(cptr) = 0;
+
+  dealloc_client(cptr); /* actually destroy the client */
+}
+
+/** Allocate a new Server object for a client.
+ * If Client::cli_serv == NULL, allocate a Server structure for it and
+ * initialize it.
+ * @param[in] cptr %Client to make into a server.
+ * @return The value of cli_serv(\a cptr).
+ */
+struct Server *make_server(struct Client *cptr)
+{
+  struct Server *serv = cli_serv(cptr);
+
+  assert(cli_verify(cptr));
+
+  if (!serv)
+  {
+    serv = (struct Server*) MyMalloc(sizeof(struct Server));
+    assert(0 != serv);
+    memset(serv, 0, sizeof(struct Server)); /* All variables are 0 by default */
+    servs.inuse++;
+    servs.alloc++;
+    cli_serv(cptr) = serv;
+    cli_serv(cptr)->lag = 60000;
+    *serv->by = '\0';
+    DupString(serv->last_error_msg, "<>");      /* String must be non-empty */
+  }
+  return cli_serv(cptr);
+}
+
+/** Remove \a cptr from lists that it is a member of.
+ * Specifically, this delinks \a cptr from #GlobalClientList, updates
+ * the whowas history list, frees its Client::cli_user and
+ * Client::cli_serv fields, and finally calls free_client() on it.
+ * @param[in] cptr Client to remove from lists and free.
+ */
+void remove_client_from_list(struct Client *cptr)
+{
+  assert(cli_verify(cptr));
+  assert(con_verify(cli_connect(cptr)));
+  assert(!cli_prev(cptr) || cli_verify(cli_prev(cptr)));
+  assert(!cli_next(cptr) || cli_verify(cli_next(cptr)));
+  assert(!IsMe(cptr));
+
+  /* Only try remove cptr from the list if it IS in the list.
+   * cli_next(cptr) cannot be NULL here, as &me is always the end
+   * the list, and we never remove &me.    -GW 
+   */
+  if(cli_next(cptr))
+  {
+    if (cli_prev(cptr))
+      cli_next(cli_prev(cptr)) = cli_next(cptr);
+    else {
+      GlobalClientList = cli_next(cptr);
+      cli_prev(GlobalClientList) = 0;
+    }
+    cli_prev(cli_next(cptr)) = cli_prev(cptr);
+  }
+  cli_next(cptr) = cli_prev(cptr) = 0;
+
+  if (IsUser(cptr) && cli_user(cptr)) {
+    add_history(cptr, 0);
+    off_history(cptr);
+  }
+  if (cli_user(cptr)) {
+    free_user(cli_user(cptr));
+    cli_user(cptr) = 0;
+  }
+
+  if (cli_serv(cptr)) {
+    if (cli_serv(cptr)->user) {
+      free_user(cli_serv(cptr)->user);
+      cli_serv(cptr)->user = 0;
+    }
+    if (cli_serv(cptr)->client_list)
+      MyFree(cli_serv(cptr)->client_list);
+    MyFree(cli_serv(cptr)->last_error_msg);
+    MyFree(cli_serv(cptr));
+    --servs.inuse;
+    --servs.alloc;
+  }
+  free_client(cptr);
+}
+
+/** Link \a cptr into #GlobalClientList.
+ * @param[in] cptr Client to link into the global list.
+ */
+void add_client_to_list(struct Client *cptr)
+{
+  assert(cli_verify(cptr));
+  assert(cli_next(cptr) == 0);
+  assert(cli_prev(cptr) == 0);
+
+  /*
+   * Since we always insert new clients to the top of the list,
+   * this should mean the "me" is the bottom most item in the list.
+   * XXX - don't always count on the above, things change
+   */
+  cli_prev(cptr) = 0;
+  cli_next(cptr) = GlobalClientList;
+  GlobalClientList = cptr;
+  if (cli_next(cptr))
+    cli_prev(cli_next(cptr)) = cptr;
+}
+
+#if 0
+/** Perform a very CPU-intensive verification of %GlobalClientList.
+ * This checks the Client::cli_magic and Client::cli_prev field for
+ * each element in the list, and also checks that there are no loops.
+ * Any detected error will lead to an assertion failure.
+ */
+void verify_client_list(void)
+{
+  struct Client *client, *prev = 0;
+  unsigned int visited = 0;
+
+  for (client = GlobalClientList; client; client = cli_next(client), ++visited) {
+    /* Verify that this is a valid client, not a free'd one */
+    assert(cli_verify(client));
+    /* Verify that the list hasn't suddenly jumped around */
+    assert(cli_prev(client) == prev);
+    /* Verify that the list hasn't become circular */
+    assert(cli_next(client) != GlobalClientList);
+    assert(visited <= clients.alloc);
+    /* Remember what should precede us */
+    prev = client;
+  }
+}
+#endif /* DEBUGMODE */
+
+/** Allocate a new SLink element.
+ * Pulls from #slinkFreeList if it contains anything, else it
+ * allocates a new one from the heap.
+ * @return Newly allocated list element.
+ */
+struct SLink* make_link(void)
+{
+  struct SLink* lp = slinkFreeList;
+  if (lp)
+    slinkFreeList = lp->next;
+  else {
+    lp = (struct SLink*) MyMalloc(sizeof(struct SLink));
+    links.alloc++;
+  }
+  assert(0 != lp);
+  links.inuse++;
+  memset(lp, 0, sizeof(*lp));
+  return lp;
+}
+
+/** Release a singly linked list element.
+ * @param[in] lp List element to mark as unused.
+ */
+void free_link(struct SLink* lp)
+{
+  if (lp) {
+    lp->next = slinkFreeList;
+    slinkFreeList = lp;
+    links.inuse--;
+  }
+}
+
+/** Add an element to a doubly linked list.
+ * If \a lpp points to a non-NULL pointer, its DLink::prev field is
+ * updated to point to the newly allocated element.  Regardless,
+ * \a lpp is overwritten with the pointer to the new link.
+ * @param[in,out] lpp Pointer to insertion location.
+ * @param[in] cp %Client to put in newly allocated element.
+ * @return Allocated link structure (same as \a lpp on output).
+ */
+struct DLink *add_dlink(struct DLink **lpp, struct Client *cp)
+{
+  struct DLink* lp = (struct DLink*) MyMalloc(sizeof(struct DLink));
+  assert(0 != lp);
+  lp->value.cptr = cp;
+  lp->prev = 0;
+  if ((lp->next = *lpp))
+    lp->next->prev = lp;
+  *lpp = lp;
+  return lp;
+}
+
+/** Remove a node from a doubly linked list.
+ * @param[out] lpp Pointer to next list element.
+ * @param[in] lp List node to unlink.
+ */
+void remove_dlink(struct DLink **lpp, struct DLink *lp)
+{
+  assert(0 != lpp);
+  assert(0 != lp);
+
+  if (lp->prev) {
+    if ((lp->prev->next = lp->next))
+      lp->next->prev = lp->prev;
+  }
+  else if ((*lpp = lp->next))
+    lp->next->prev = NULL;
+  MyFree(lp);
+}
+
+/** Report memory usage of a list to \a cptr.
+ * @param[in] cptr Client requesting information.
+ * @param[in] lstats List statistics descriptor.
+ * @param[in] itemname Plural name of item type.
+ * @param[in,out] totals If non-null, accumulates item counts and memory usage.
+ */
+void send_liststats(struct Client *cptr, const struct liststats *lstats,
+                    const char *itemname, struct liststats *totals)
+{
+  send_reply(cptr, SND_EXPLICIT | RPL_STATSDEBUG, ":%s: inuse %zu(%zu) alloc %zu",
+            itemname, lstats->inuse, lstats->mem, lstats->alloc);
+  if (totals)
+  {
+    totals->inuse += lstats->inuse;
+    totals->alloc += lstats->alloc;
+    totals->mem += lstats->mem;
+  }
+}
+
+/** Report memory usage of list elements to \a cptr.
+ * @param[in] cptr Client requesting information.
+ * @param[in] name Unused pointer.
+ */
+void send_listinfo(struct Client *cptr, char *name)
+{
+  struct liststats total;
+  struct liststats confs;
+  struct ConfItem *conf;
+
+  memset(&total, 0, sizeof(total));
+
+  clients.mem = clients.inuse * sizeof(struct Client);
+  send_liststats(cptr, &clients, "Clients", &total);
+
+  connections.mem = connections.inuse * sizeof(struct Connection);
+  send_liststats(cptr, &connections, "Connections", &total);
+
+  servs.mem = servs.inuse * sizeof(struct Server);
+  send_liststats(cptr, &servs, "Servers", &total);
+
+  links.mem = links.inuse * sizeof(struct SLink);
+  send_liststats(cptr, &links, "Links", &total);
+
+  confs.alloc = GlobalConfCount;
+  confs.mem = confs.alloc * sizeof(GlobalConfCount);
+  for (confs.inuse = 0, conf = GlobalConfList; conf; conf = conf->next)
+    confs.inuse++;
+  send_liststats(cptr, &confs, "Confs", &total);
+
+  send_liststats(cptr, &total, "Totals", NULL);
+}
diff --git a/ircd/listener.c b/ircd/listener.c
new file mode 100644 (file)
index 0000000..f5c2753
--- /dev/null
@@ -0,0 +1,531 @@
+/************************************************************************
+ *   IRC - Internet Relay Chat, src/listener.c
+ *   Copyright (C) 1999 Thomas Helvey <tomh@inxpress.net>
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 1, or (at your option)
+ *   any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+/** @file
+ * @brief Implementation for handling listening sockets.
+ * @version $Id: listener.c 1809 2007-05-20 14:10:30Z entrope $
+ */
+#include "config.h"
+
+#include "listener.h"
+#include "client.h"
+#include "ircd.h"
+#include "ircd_alloc.h"
+#include "ircd_events.h"
+#include "ircd_features.h"
+#include "ircd_log.h"
+#include "ircd_osdep.h"
+#include "ircd_reply.h"
+#include "ircd_snprintf.h"
+#include "ircd_string.h"
+#include "match.h"
+#include "numeric.h"
+#include "s_bsd.h"
+#include "s_conf.h"
+#include "s_misc.h"
+#include "s_stats.h"
+#include "send.h"
+#include "sys.h"         /* MAXCLIENTS */
+
+/* #include <assert.h> -- Now using assert in ircd_log.h */
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <netdb.h>
+#include <sys/socket.h>
+
+/** List of listening sockets. */
+struct Listener* ListenerPollList = 0;
+
+static void accept_connection(struct Event* ev);
+
+/** Allocate and initialize a new Listener structure for a particular
+ * socket address.
+ * @param[in] port Port number to listen on.
+ * @param[in] addr Local address to listen on.
+ * @return Newly allocated and initialized Listener.
+ */
+static struct Listener* make_listener(int port, const struct irc_in_addr *addr)
+{
+  struct Listener* listener =
+    (struct Listener*) MyMalloc(sizeof(struct Listener));
+  assert(0 != listener);
+
+  memset(listener, 0, sizeof(struct Listener));
+
+  listener->fd_v4       = -1;
+  listener->fd_v6       = -1;
+  listener->addr.port   = port;
+  memcpy(&listener->addr.addr, addr, sizeof(listener->addr.addr));
+
+#ifdef NULL_POINTER_NOT_ZERO
+  listener->next = NULL;
+  listener->conf = NULL;
+#endif
+  return listener;
+}
+
+/** Deallocate a Listener structure.
+ * @param[in] listener Listener to be freed.
+ */
+static void free_listener(struct Listener* listener)
+{
+  assert(0 != listener);
+  MyFree(listener);
+}
+
+/** Maximum length for a port number. */
+#define PORTNAMELEN 10  /* ":31337" */
+
+/** Return displayable listener name and port.
+ * @param[in] listener %Listener to format as a text string.
+ * @return Pointer to a static buffer that contains "server.name:6667".
+ */
+const char* get_listener_name(const struct Listener* listener)
+{
+  static char buf[HOSTLEN + PORTNAMELEN + 4];
+  assert(0 != listener);
+  ircd_snprintf(0, buf, sizeof(buf), "%s:%u", cli_name(&me), listener->addr.port);
+  return buf;
+}
+
+/** Count allocated listeners and the memory they use.
+ * @param[out] count_out Receives number of allocated listeners.
+ * @param[out] size_out Receives bytes used by listeners.
+ */
+void count_listener_memory(int* count_out, size_t* size_out)
+{
+  struct Listener* l;
+  int              count = 0;
+  assert(0 != count_out);
+  assert(0 != size_out);
+  for (l = ListenerPollList; l; l = l->next)
+    ++count;
+  *count_out = count;
+  *size_out  = count * sizeof(struct Listener);
+}
+
+/** Report listening ports to a client.
+ * @param[in] sptr Client requesting statistics.
+ * @param[in] sd Stats descriptor for request (ignored).
+ * @param[in] param Extra parameter from user (port number to search for).
+ */
+void show_ports(struct Client* sptr, const struct StatDesc* sd,
+                char* param)
+{
+  struct Listener *listener = 0;
+  char flags[8];
+  int show_hidden = IsOper(sptr);
+  int count = (IsOper(sptr) || MyUser(sptr)) ? 100 : 8;
+  int port = 0;
+  int len;
+
+  assert(0 != sptr);
+
+  if (param)
+    port = atoi(param);
+
+  for (listener = ListenerPollList; listener; listener = listener->next) {
+    if (port && port != listener->addr.port)
+      continue;
+    len = 0;
+    flags[len++] = listener_server(listener) ? (listener_secure(listener) ? 'T' : 'S') : (listener_secure(listener) ? 'E' : 'C');
+    if (FlagHas(&listener->flags, LISTEN_HIDDEN))
+    {
+      if (!show_hidden)
+        continue;
+      flags[len++] = 'H';
+    }
+    if (FlagHas(&listener->flags, LISTEN_IPV4))
+    {
+      flags[len++] = '4';
+      if (listener->fd_v4 < 0)
+        flags[len++] = '-';
+    }
+    if (FlagHas(&listener->flags, LISTEN_IPV6))
+    {
+      flags[len++] = '6';
+      if (listener->fd_v6 < 0)
+        flags[len++] = '-';
+    }
+    flags[len] = '\0';
+
+    send_reply(sptr, RPL_STATSPLINE, listener->addr.port, listener->ref_count,
+              flags, listener_active(listener) ? "active" : "disabled");
+    if (--count == 0)
+      break;
+  }
+}
+
+/*
+ * inetport - create a listener socket in the AF_INET domain, 
+ * bind it to the port given in 'port' and listen to it  
+ * returns true (1) if successful false (0) on error.
+ *
+ * If the operating system has a define for SOMAXCONN, use it, otherwise
+ * use HYBRID_SOMAXCONN -Dianora
+ * NOTE: Do this in os_xxxx.c files
+ */
+#ifdef SOMAXCONN
+#define HYBRID_SOMAXCONN SOMAXCONN
+#else
+/** Maximum length of socket connection backlog. */
+#define HYBRID_SOMAXCONN 64
+#endif
+
+/** Set or update socket options for \a listener.
+ * @param[in] listener Listener to determine socket option values.
+ * @param[in] fd File descriptor being updated.
+ * @return Non-zero on success, zero on failure.
+ */
+static int set_listener_options(struct Listener *listener, int fd)
+{
+  int is_server;
+
+  is_server = listener_server(listener);
+  /*
+   * Set the buffer sizes for the listener. Accepted connections
+   * inherit the accepting sockets settings for SO_RCVBUF S_SNDBUF
+   * The window size is set during the SYN ACK so setting it anywhere
+   * else has no effect whatsoever on the connection.
+   * NOTE: this must be set before listen is called
+   */
+  if (!os_set_sockbufs(fd,
+                       is_server ? feature_int(FEAT_SOCKSENDBUF) : CLIENT_TCP_WINDOW,
+                       is_server ? feature_int(FEAT_SOCKRECVBUF) : CLIENT_TCP_WINDOW)) {
+    report_error(SETBUFS_ERROR_MSG, get_listener_name(listener), errno);
+    close(fd);
+    return 0;
+  }
+
+  /*
+   * Set the TOS bits - this is nonfatal if it doesn't stick.
+   */
+  if (!os_set_tos(fd,feature_int(is_server ? FEAT_TOS_SERVER : FEAT_TOS_CLIENT))) {
+    report_error(TOS_ERROR_MSG, get_listener_name(listener), errno);
+  }
+
+  return 1;
+}
+
+/** Open listening socket for \a listener.
+ * @param[in,out] listener Listener to make a socket for.
+ * @param[in] family Socket address family to use.
+ * @return Negative on failure, file descriptor on success.
+ */
+static int inetport(struct Listener* listener, int family)
+{
+  struct Socket *sock;
+  int fd;
+
+  /*
+   * At first, open a new socket
+   */
+  fd = os_socket(&listener->addr, SOCK_STREAM, get_listener_name(listener), family);
+  if (fd < 0)
+    return -1;
+  if (!os_set_listen(fd, HYBRID_SOMAXCONN)) {
+    report_error(LISTEN_ERROR_MSG, get_listener_name(listener), errno);
+    close(fd);
+    return -1;
+  }
+  if (!set_listener_options(listener, fd))
+    return -1;
+  sock = (family == AF_INET) ? &listener->socket_v4 : &listener->socket_v6;
+  if (!socket_add(sock, accept_connection, (void*) listener,
+                 SS_LISTENING, 0, fd)) {
+    /* Error should already have been reported to the logs */
+    close(fd);
+    return -1;
+  }
+
+  return fd;
+}
+
+/** Find the listener (if any) for a particular port and address.
+ * @param[in] port Port number to search for.
+ * @param[in] addr Local address to search for.
+ * @return Listener that matches (or NULL if none match).
+ */
+static struct Listener* find_listener(int port, const struct irc_in_addr *addr)
+{
+  struct Listener* listener;
+  for (listener = ListenerPollList; listener; listener = listener->next) {
+    if (port == listener->addr.port && !memcmp(addr, &listener->addr.addr, sizeof(*addr)))
+      return listener;
+  }
+  return 0;
+}
+
+/** Make sure we have a listener for \a port on \a vhost_ip.
+ * If one does not exist, create it.  Then mark it as active and set
+ * the peer mask, server, and hidden flags according to the other
+ * arguments.
+ * @param[in] port Port number to listen on.
+ * @param[in] vhost_ip Local address to listen on.
+ * @param[in] mask Address mask to accept connections from.
+ * @param[in] flags Flags describing listener options.
+ */
+void add_listener(int port, const char* vhost_ip, const char* mask,
+                  const struct ListenerFlags *flags)
+{
+  struct Listener* listener;
+  struct irc_in_addr vaddr;
+  int okay = 0;
+  int new_listener = 0;
+  int fd;
+
+  /*
+   * if no port in conf line, don't bother
+   */
+  if (0 == port)
+    return;
+
+  memset(&vaddr, 0, sizeof(vaddr));
+
+  if (!EmptyString(vhost_ip)
+      && strcmp(vhost_ip, "*")
+      && !ircd_aton(&vaddr, vhost_ip))
+      return;
+
+  listener = find_listener(port, &vaddr);
+  if (!listener)
+  {
+    new_listener = 1;
+    listener = make_listener(port, &vaddr);
+  }
+  memcpy(&listener->flags, flags, sizeof(listener->flags));
+  FlagSet(&listener->flags, LISTEN_ACTIVE);
+  if (mask)
+    ipmask_parse(mask, &listener->mask, &listener->mask_bits);
+  else
+    listener->mask_bits = 0;
+
+#ifdef IPV6
+  if (FlagHas(&listener->flags, LISTEN_IPV6)
+      && (irc_in_addr_unspec(&vaddr) || !irc_in_addr_is_ipv4(&vaddr))) {
+    if (listener->fd_v6 >= 0) {
+      set_listener_options(listener, listener->fd_v6);
+      okay = 1;
+    } else if ((fd = inetport(listener, AF_INET6)) >= 0) {
+      listener->fd_v6 = fd;
+      okay = 1;
+    }
+  } else if (-1 < listener->fd_v6) {
+    close(listener->fd_v6);
+    socket_del(&listener->socket_v6);
+    listener->fd_v6 = -1;
+  }
+#endif
+
+  if (FlagHas(&listener->flags, LISTEN_IPV4)
+      && (irc_in_addr_unspec(&vaddr) || irc_in_addr_is_ipv4(&vaddr))) {
+    if (listener->fd_v4 >= 0) {
+      set_listener_options(listener, listener->fd_v4);
+      okay = 1;
+    } else if ((fd = inetport(listener, AF_INET)) >= 0) {
+      listener->fd_v4 = fd;
+      okay = 1;
+    }
+  } else if (-1 < listener->fd_v4) {
+    close(listener->fd_v4);
+    socket_del(&listener->socket_v4);
+    listener->fd_v4 = -1;
+  }
+
+  if (!okay)
+    free_listener(listener);
+  else if (new_listener) {
+    listener->next   = ListenerPollList;
+    ListenerPollList = listener;
+  }
+}
+
+/** Mark all listeners as closing (inactive).
+ * This is done so unused listeners are closed after a rehash.
+ */
+void mark_listeners_closing(void)
+{
+  struct Listener* listener;
+  for (listener = ListenerPollList; listener; listener = listener->next)
+    FlagClr(&listener->flags, LISTEN_ACTIVE);
+}
+
+/** Close a single listener.
+ * @param[in] listener Listener to close.
+ */
+void close_listener(struct Listener* listener)
+{
+  assert(0 != listener);
+  /*
+   * remove from listener list
+   */
+  if (listener == ListenerPollList)
+    ListenerPollList = listener->next;
+  else {
+    struct Listener* prev = ListenerPollList;
+    for ( ; prev; prev = prev->next) {
+      if (listener == prev->next) {
+        prev->next = listener->next;
+        break; 
+      }
+    }
+  }
+  if (-1 < listener->fd_v4) {
+    close(listener->fd_v4);
+    socket_del(&listener->socket_v4);
+    listener->fd_v4 = -1;
+  }
+  if (-1 < listener->fd_v6) {
+    close(listener->fd_v6);
+    socket_del(&listener->socket_v6);
+    listener->fd_v6 = -1;
+  }
+  free_listener(listener);
+}
+
+/** Close all inactive listeners. */
+void close_listeners(void)
+{
+  struct Listener* listener;
+  struct Listener* listener_next = 0;
+  /*
+   * close all 'extra' listening ports we have
+   */
+  for (listener = ListenerPollList; listener; listener = listener_next) {
+    listener_next = listener->next;
+    if (!listener_active(listener) && 0 == listener->ref_count)
+      close_listener(listener);
+  }
+}
+
+/** Dereference the listener previously associated with a client.
+ * @param[in] listener Listener to dereference.
+ */
+void release_listener(struct Listener* listener)
+{
+  assert(0 != listener);
+  assert(0 < listener->ref_count);
+  if (0 == --listener->ref_count && !listener_active(listener))
+    close_listener(listener);
+}
+
+/** Accept a connection on a listener.
+ * @param[in] ev Socket callback structure.
+ */
+static void accept_connection(struct Event* ev)
+{
+  struct Listener*    listener;
+  struct irc_sockaddr addr;
+  int                 fd;
+
+  assert(0 != ev_socket(ev));
+  assert(0 != s_data(ev_socket(ev)));
+
+  listener = (struct Listener*) s_data(ev_socket(ev));
+
+  if (ev_type(ev) == ET_DESTROY) /* being destroyed */
+    return;
+  else {
+    assert(ev_type(ev) == ET_ACCEPT || ev_type(ev) == ET_ERROR);
+
+    listener->last_accept = CurrentTime;
+    /*
+     * There may be many reasons for error return, but
+     * in otherwise correctly working environment the
+     * probable cause is running out of file descriptors
+     * (EMFILE, ENFILE or others?). The man pages for
+     * accept don't seem to list these as possible,
+     * although it's obvious that it may happen here.
+     * Thus no specific errors are tested at this
+     * point, just assume that connections cannot
+     * be accepted until some old is closed first.
+     *
+     * This piece of code implements multi-accept, based
+     * on the idea that poll/select can only be efficient,
+     * if we succeed in handling all available events,
+     * i.e. accept all pending connections.
+     *
+     * http://www.hpl.hp.com/techreports/2000/HPL-2000-174.html
+     */
+    while (1)
+    {
+      if ((fd = os_accept(s_fd(ev_socket(ev)), &addr)) == -1)
+      {
+        if (errno == EAGAIN ||
+#ifdef EWOULDBLOCK
+            errno == EWOULDBLOCK)
+#endif
+          return;
+      /* Lotsa admins seem to have problems with not giving enough file
+       * descriptors to their server so we'll add a generic warning mechanism
+       * here.  If it turns out too many messages are generated for
+       * meaningless reasons we can filter them back.
+       */
+      sendto_opmask_butone(0, SNO_TCPCOMMON,
+                          "Unable to accept connection: %m");
+      return;
+      }
+      /*
+       * check for connection limit. If this fd exceeds the limit,
+       * all further accept()ed connections will also exceed it.
+       * Enable the server to clear out other connections before
+       * continuing to accept() new connections.
+       */
+      if (fd > MAXCLIENTS - 1)
+      {
+        ++ServerStats->is_ref;
+        send(fd, "ERROR :All connections in use\r\n", 32, 0);
+        close(fd);
+        return;
+      }
+      /*
+       * check to see if listener is shutting down. Continue
+       * to accept(), because it makes sense to clear our the
+       * socket's queue as fast as possible.
+       */
+      if (!listener_active(listener))
+      {
+        ++ServerStats->is_ref;
+        send(fd, "ERROR :Use another port\r\n", 25, 0);
+        close(fd);
+        continue;
+      }
+      /*
+       * check to see if connection is allowed for this address mask
+       */
+      if (!ipmask_check(&addr.addr, &listener->mask, listener->mask_bits))
+      {
+        ++ServerStats->is_ref;
+        send(fd, "ERROR :Use another port\r\n", 25, 0);
+        close(fd);
+        continue;
+      }
+      ++ServerStats->is_ac;
+      /* nextping = CurrentTime; */
+      if(listener_secure(listener)) {
+        ssl_accept(listener, fd);
+      }
+      else {
+        add_connection(listener, fd, NULL);
+      }
+    }
+  }
+}
diff --git a/ircd/m_account.c b/ircd/m_account.c
new file mode 100644 (file)
index 0000000..b7aa229
--- /dev/null
@@ -0,0 +1,160 @@
+/*
+ * IRC - Internet Relay Chat, ircd/m_account.c
+ * Copyright (C) 2002 Kevin L. Mitchell <klmitch@mit.edu>
+ *
+ * See file AUTHORS in IRC package for additional names of
+ * the programmers.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id: m_account.c 1271 2004-12-11 05:14:07Z klmitch $
+ */
+
+/*
+ * m_functions execute protocol messages on this server:
+ *
+ *    cptr    is always NON-NULL, pointing to a *LOCAL* client
+ *            structure (with an open socket connected!). This
+ *            identifies the physical socket where the message
+ *            originated (or which caused the m_function to be
+ *            executed--some m_functions may call others...).
+ *
+ *    sptr    is the source of the message, defined by the
+ *            prefix part of the message if present. If not
+ *            or prefix not found, then sptr==cptr.
+ *
+ *            (!IsServer(cptr)) => (cptr == sptr), because
+ *            prefixes are taken *only* from servers...
+ *
+ *            (IsServer(cptr))
+ *                    (sptr == cptr) => the message didn't
+ *                    have the prefix.
+ *
+ *                    (sptr != cptr && IsServer(sptr) means
+ *                    the prefix specified servername. (?)
+ *
+ *                    (sptr != cptr && !IsServer(sptr) means
+ *                    that message originated from a remote
+ *                    user (not local).
+ *
+ *            combining
+ *
+ *            (!IsServer(sptr)) means that, sptr can safely
+ *            taken as defining the target structure of the
+ *            message in this server.
+ *
+ *    *Always* true (if 'parse' and others are working correct):
+ *
+ *    1)      sptr->from == cptr  (note: cptr->from == cptr)
+ *
+ *    2)      MyConnect(sptr) <=> sptr == cptr (e.g. sptr
+ *            *cannot* be a local connection, unless it's
+ *            actually cptr!). [MyConnect(x) should probably
+ *            be defined as (x == x->from) --msa ]
+ *
+ *    parc    number of variable parameter strings (if zero,
+ *            parv is allowed to be NULL)
+ *
+ *    parv    a NULL terminated list of parameter pointers,
+ *
+ *                    parv[0], sender (prefix string), if not present
+ *                            this points to an empty string.
+ *                    parv[1]...parv[parc-1]
+ *                            pointers to additional parameters
+ *                    parv[parc] == NULL, *always*
+ *
+ *            note:   it is guaranteed that parv[0]..parv[parc-1] are all
+ *                    non-NULL pointers.
+ */
+#include "config.h"
+
+#include "channel.h"
+#include "client.h"
+#include "ircd.h"
+#include "ircd_log.h"
+#include "ircd_reply.h"
+#include "ircd_string.h"
+#include "msg.h"
+#include "numnicks.h"
+#include "s_debug.h"
+#include "s_user.h"
+#include "send.h"
+
+/* #include <assert.h> -- Now using assert in ircd_log.h */
+#include <stdlib.h>
+#include <string.h>
+
+/*
+ * ms_account - server message handler
+ *
+ * parv[0] = sender prefix
+ * parv[1] = numeric of client to act on
+ * parv[2] = account name (12 characters or less)
+ */
+int ms_account(struct Client* cptr, struct Client* sptr, int parc,
+              char* parv[])
+{
+  struct Client *acptr;
+  struct Membership *chan;
+  signed int has_fakehost;
+
+  if (parc < 3)
+    return need_more_params(sptr, "ACCOUNT");
+
+  if (!IsServer(sptr))
+    return protocol_violation(cptr, "ACCOUNT from non-server %s",
+                             cli_name(sptr));
+
+  if (!(acptr = findNUser(parv[1])))
+    return 0; /* Ignore ACCOUNT for a user that QUIT; probably crossed */
+
+  /*if (IsAccount(acptr))
+    return protocol_violation(cptr, "ACCOUNT for already registered user %s "
+                             "(%s -> %s)", cli_name(acptr),
+                             cli_user(acptr)->account, parv[2]);*/
+
+  assert(0 == cli_user(acptr)->account[0]);
+
+  if (strlen(parv[2]) > ACCOUNTLEN)
+    return protocol_violation(cptr,
+                              "Received account (%s) longer than %d for %s; "
+                              "ignoring.",
+                              parv[2], ACCOUNTLEN, cli_name(acptr));
+
+  if (parc > 3) {
+    cli_user(acptr)->acc_create = atoi(parv[3]);
+    Debug((DEBUG_DEBUG, "Received timestamped account: account \"%s\", "
+           "timestamp %Tu", parv[2], cli_user(acptr)->acc_create));
+  }
+
+  /* If the user already has an hidden hostmask, it must be a fakehost, because it's
+     not possible to override a former account. Because fakehosts override account
+     hostmasks, we prevent a host updating here in such situations. */
+  has_fakehost = HasHiddenHost(acptr);
+  ircd_strncpy(cli_user(acptr)->account, parv[2], ACCOUNTLEN);
+  if(has_fakehost) SetAccount(acptr);
+  else hide_hostmask(acptr, FLAG_ACCOUNT);
+
+  for(chan = (cli_user(acptr))->channel; chan; chan = chan->next_channel) {
+    ClearBanValid(chan);
+  }
+
+  sendcmdto_serv_butone(sptr, CMD_ACCOUNT, cptr,
+                        cli_user(acptr)->acc_create ? "%C %s %Tu" : "%C %s",
+                        acptr, cli_user(acptr)->account,
+                        cli_user(acptr)->acc_create);
+
+  return 0;
+}
diff --git a/ircd/m_admin.c b/ircd/m_admin.c
new file mode 100644 (file)
index 0000000..b7fea07
--- /dev/null
@@ -0,0 +1,165 @@
+/*
+ * IRC - Internet Relay Chat, ircd/m_admin.c
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ *                    University of Oulu, Computing Center
+ *
+ * See file AUTHORS in IRC package for additional names of
+ * the programmers.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id: m_admin.c 1803 2007-05-20 13:02:51Z entrope $
+ */
+
+/*
+ * m_functions execute protocol messages on this server:
+ *
+ *    cptr    is always NON-NULL, pointing to a *LOCAL* client
+ *            structure (with an open socket connected!). This
+ *            identifies the physical socket where the message
+ *            originated (or which caused the m_function to be
+ *            executed--some m_functions may call others...).
+ *
+ *    sptr    is the source of the message, defined by the
+ *            prefix part of the message if present. If not
+ *            or prefix not found, then sptr==cptr.
+ *
+ *            (!IsServer(cptr)) => (cptr == sptr), because
+ *            prefixes are taken *only* from servers...
+ *
+ *            (IsServer(cptr))
+ *                    (sptr == cptr) => the message didn't
+ *                    have the prefix.
+ *
+ *                    (sptr != cptr && IsServer(sptr) means
+ *                    the prefix specified servername. (?)
+ *
+ *                    (sptr != cptr && !IsServer(sptr) means
+ *                    that message originated from a remote
+ *                    user (not local).
+ *
+ *            combining
+ *
+ *            (!IsServer(sptr)) means that, sptr can safely
+ *            taken as defining the target structure of the
+ *            message in this server.
+ *
+ *    *Always* true (if 'parse' and others are working correct):
+ *
+ *    1)      sptr->from == cptr  (note: cptr->from == cptr)
+ *
+ *    2)      MyConnect(sptr) <=> sptr == cptr (e.g. sptr
+ *            *cannot* be a local connection, unless it's
+ *            actually cptr!). [MyConnect(x) should probably
+ *            be defined as (x == x->from) --msa ]
+ *
+ *    parc    number of variable parameter strings (if zero,
+ *            parv is allowed to be NULL)
+ *
+ *    parv    a NULL terminated list of parameter pointers,
+ *
+ *                    parv[0], sender (prefix string), if not present
+ *                            this points to an empty string.
+ *                    parv[1]...parv[parc-1]
+ *                            pointers to additional parameters
+ *                    parv[parc] == NULL, *always*
+ *
+ *            note:   it is guaranteed that parv[0]..parv[parc-1] are all
+ *                    non-NULL pointers.
+ */
+#include "config.h"
+
+#include "client.h"
+#include "hash.h"
+#include "ircd.h"
+#include "ircd_features.h"
+#include "ircd_log.h"
+#include "ircd_reply.h"
+#include "match.h"
+#include "msg.h"
+#include "numeric.h"
+#include "numnicks.h"
+#include "s_conf.h"
+#include "s_user.h"
+
+/* #include <assert.h> -- Now using assert in ircd_log.h */
+
+static int send_admin_info(struct Client* sptr)
+{
+  const struct LocalConf* admin = conf_get_local();
+  assert(0 != sptr);
+
+  send_reply(sptr, RPL_ADMINME,    cli_name(&me));
+  send_reply(sptr, RPL_ADMINLOC1,  admin->location1);
+  send_reply(sptr, RPL_ADMINLOC2,  admin->location2);
+  send_reply(sptr, RPL_ADMINEMAIL, admin->contact);
+  return 0;
+}
+
+
+/*
+ * m_admin - generic message handler
+ *
+ * parv[0] = sender prefix
+ * parv[1] = servername
+ */
+int m_admin(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  assert(0 != cptr);
+  assert(cptr == sptr);
+
+  if (parc > 1  && match(parv[1], cli_name(&me)))
+    return send_reply(sptr, ERR_NOPRIVILEGES);
+
+  return send_admin_info(sptr);
+}
+
+/*
+ * mo_admin - oper message handler
+ *
+ * parv[0] = sender prefix
+ * parv[1] = servername
+ */
+int mo_admin(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  assert(0 != cptr);
+  assert(cptr == sptr);
+
+  if (hunt_server_cmd(sptr, CMD_ADMIN, cptr, feature_int(FEAT_HIS_REMOTE), 
+                      ":%C", 1, parc, parv) != HUNTED_ISME)
+    return 0;
+  return send_admin_info(sptr);
+}
+
+/*
+ * ms_admin - server message handler
+ *
+ * parv[0] = sender prefix
+ * parv[1] = servername
+ */
+int ms_admin(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  assert(0 != cptr);
+  assert(0 != sptr);
+
+  if (parc < 2)
+    return 0;
+
+  if (hunt_server_cmd(sptr, CMD_ADMIN, cptr, 0, ":%C", 1, parc, parv) != HUNTED_ISME)
+    return 0;
+
+  return send_admin_info(sptr);
+}
+
diff --git a/ircd/m_asll.c b/ircd/m_asll.c
new file mode 100644 (file)
index 0000000..68464bd
--- /dev/null
@@ -0,0 +1,182 @@
+/*
+ * IRC - Internet Relay Chat, ircd/m_asll.c
+ * Copyright (C) 2002 Alex Badea <vampire@p16.pub.ro>
+ *
+ * See file AUTHORS in IRC package for additional names of
+ * the programmers.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id: m_asll.c 1793 2007-03-28 04:04:32Z entrope $
+ */
+
+/*
+ * m_functions execute protocol messages on this server:
+ *
+ *    cptr    is always NON-NULL, pointing to a *LOCAL* client
+ *            structure (with an open socket connected!). This
+ *            identifies the physical socket where the message
+ *            originated (or which caused the m_function to be
+ *            executed--some m_functions may call others...).
+ *
+ *    sptr    is the source of the message, defined by the
+ *            prefix part of the message if present. If not
+ *            or prefix not found, then sptr==cptr.
+ *
+ *            (!IsServer(cptr)) => (cptr == sptr), because
+ *            prefixes are taken *only* from servers...
+ *
+ *            (IsServer(cptr))
+ *                    (sptr == cptr) => the message didn't
+ *                    have the prefix.
+ *
+ *                    (sptr != cptr && IsServer(sptr) means
+ *                    the prefix specified servername. (?)
+ *
+ *                    (sptr != cptr && !IsServer(sptr) means
+ *                    that message originated from a remote
+ *                    user (not local).
+ *
+ *            combining
+ *
+ *            (!IsServer(sptr)) means that, sptr can safely
+ *            taken as defining the target structure of the
+ *            message in this server.
+ *
+ *    *Always* true (if 'parse' and others are working correct):
+ *
+ *    1)      sptr->from == cptr  (note: cptr->from == cptr)
+ *
+ *    2)      MyConnect(sptr) <=> sptr == cptr (e.g. sptr
+ *            *cannot* be a local connection, unless it's
+ *            actually cptr!). [MyConnect(x) should probably
+ *            be defined as (x == x->from) --msa ]
+ *
+ *    parc    number of variable parameter strings (if zero,
+ *            parv is allowed to be NULL)
+ *
+ *    parv    a NULL terminated list of parameter pointers,
+ *
+ *                    parv[0], sender (prefix string), if not present
+ *                            this points to an empty string.
+ *                    parv[1]...parv[parc-1]
+ *                            pointers to additional parameters
+ *                    parv[parc] == NULL, *always*
+ *
+ *            note:   it is guaranteed that parv[0]..parv[parc-1] are all
+ *                    non-NULL pointers.
+ */
+#include "config.h"
+
+#include "client.h"
+#include "hash.h"
+#include "ircd.h"
+#include "ircd_log.h"
+#include "ircd_reply.h"
+#include "ircd_string.h"
+#include "numeric.h"
+#include "numnicks.h"
+#include "match.h"
+#include "msg.h"
+#include "send.h"
+#include "s_bsd.h"
+#include "s_user.h"
+
+/* #include <assert.h> -- Now using assert in ircd_log.h */
+#include <stdlib.h>
+
+static int send_asll_reply(struct Client *from, struct Client *to, char *server,
+                          int rtt, int up, int down)
+{
+  sendcmdto_one(from, CMD_NOTICE, to,
+    (up || down) ? "%C :AsLL for %s -- RTT: %ims Upstream: %ims Downstream: %ims" :
+    rtt ? "%C :AsLL for %s -- RTT: %ims [no asymm info]" :
+    "%C :AsLL for %s -- [unknown]",
+    to, server, rtt, up, down);
+  return 0;
+}
+
+/*
+ * ms_asll - server message handler
+ */
+int ms_asll(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  char *mask;
+  struct Client *acptr;
+  int hits;
+  int i;
+
+  if (parc < 2)
+    return need_more_params(sptr, "ASLL");
+
+  if (parc > 5) {
+    if (!(acptr = findNUser(parv[1])))
+      return 0;
+    if (MyUser(acptr))
+      send_asll_reply(sptr, acptr, parv[2], atoi(parv[3]), atoi(parv[4]), atoi(parv[5]));
+    else
+      sendcmdto_prio_one(sptr, CMD_ASLL, acptr, "%C %s %s %s %s",
+        acptr, parv[2], parv[3], parv[4], parv[5]);
+    return 0;
+  }
+
+  if (hunt_server_prio_cmd(sptr, CMD_ASLL, cptr, 1, "%s %C", 2, parc, parv) != HUNTED_ISME)
+    return 0;
+  mask = parv[1];
+
+  for (i = hits = 0; i <= HighestFd; i++) {
+    acptr = LocalClientArray[i];
+    if (!acptr || !IsServer(acptr) || !MyConnect(acptr) || match(mask, cli_name(acptr)))
+      continue;
+    sendcmdto_prio_one(&me, CMD_ASLL, sptr, "%C %s %i %i %i", sptr,
+      cli_name(acptr), cli_serv(acptr)->asll_rtt,
+      cli_serv(acptr)->asll_to, cli_serv(acptr)->asll_from);
+    hits++;
+  }
+  sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :AsLL for %s: %d local servers matched", sptr, mask, hits);
+  return 0;
+}
+
+/*
+ * mo_asll - oper message handler
+ */
+int mo_asll(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  char *mask;
+  struct Client *acptr;
+  int hits;
+  int i;
+
+  if (parc < 2)
+    return need_more_params(sptr, "ASLL");
+
+  if (parc == 2 && MyUser(sptr))
+    parv[parc++] = cli_name(&me);
+
+  if (hunt_server_prio_cmd(sptr, CMD_ASLL, cptr, 1, "%s %C", 2, parc, parv) != HUNTED_ISME)
+    return 0;
+  mask = parv[1];
+
+  for (i = hits = 0; i <= HighestFd; i++) {
+    acptr = LocalClientArray[i];
+    if (!acptr || !IsServer(acptr) || !MyConnect(acptr) || match(mask, cli_name(acptr)))
+      continue;
+    send_asll_reply(&me, sptr, cli_name(acptr), cli_serv(acptr)->asll_rtt,
+      cli_serv(acptr)->asll_to, cli_serv(acptr)->asll_from);
+    hits++;
+  }
+  sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :AsLL for %s: %d local servers matched", sptr, mask, hits);
+  return 0;
+}
diff --git a/ircd/m_away.c b/ircd/m_away.c
new file mode 100644 (file)
index 0000000..f9e5074
--- /dev/null
@@ -0,0 +1,201 @@
+/*
+ * IRC - Internet Relay Chat, ircd/m_away.c
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ *                    University of Oulu, Computing Center
+ *
+ * See file AUTHORS in IRC package for additional names of
+ * the programmers.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id: m_away.c 1271 2004-12-11 05:14:07Z klmitch $
+ */
+
+/*
+ * m_functions execute protocol messages on this server:
+ *
+ *    cptr    is always NON-NULL, pointing to a *LOCAL* client
+ *            structure (with an open socket connected!). This
+ *            identifies the physical socket where the message
+ *            originated (or which caused the m_function to be
+ *            executed--some m_functions may call others...).
+ *
+ *    sptr    is the source of the message, defined by the
+ *            prefix part of the message if present. If not
+ *            or prefix not found, then sptr==cptr.
+ *
+ *            (!IsServer(cptr)) => (cptr == sptr), because
+ *            prefixes are taken *only* from servers...
+ *
+ *            (IsServer(cptr))
+ *                    (sptr == cptr) => the message didn't
+ *                    have the prefix.
+ *
+ *                    (sptr != cptr && IsServer(sptr) means
+ *                    the prefix specified servername. (?)
+ *
+ *                    (sptr != cptr && !IsServer(sptr) means
+ *                    that message originated from a remote
+ *                    user (not local).
+ *
+ *            combining
+ *
+ *            (!IsServer(sptr)) means that, sptr can safely
+ *            taken as defining the target structure of the
+ *            message in this server.
+ *
+ *    *Always* true (if 'parse' and others are working correct):
+ *
+ *    1)      sptr->from == cptr  (note: cptr->from == cptr)
+ *
+ *    2)      MyConnect(sptr) <=> sptr == cptr (e.g. sptr
+ *            *cannot* be a local connection, unless it's
+ *            actually cptr!). [MyConnect(x) should probably
+ *            be defined as (x == x->from) --msa ]
+ *
+ *    parc    number of variable parameter strings (if zero,
+ *            parv is allowed to be NULL)
+ *
+ *    parv    a NULL terminated list of parameter pointers,
+ *
+ *                    parv[0], sender (prefix string), if not present
+ *                            this points to an empty string.
+ *                    parv[1]...parv[parc-1]
+ *                            pointers to additional parameters
+ *                    parv[parc] == NULL, *always*
+ *
+ *            note:   it is guaranteed that parv[0]..parv[parc-1] are all
+ *                    non-NULL pointers.
+ */
+#include "config.h"
+
+#include "client.h"
+#include "ircd.h"
+#include "ircd_alloc.h"
+#include "ircd_log.h"
+#include "ircd_reply.h"
+#include "ircd_string.h"
+#include "msg.h"
+#include "numeric.h"
+#include "numnicks.h"
+#include "s_user.h"
+#include "send.h"
+
+/* #include <assert.h> -- Now using assert in ircd_log.h */
+#include <string.h>
+
+/*
+ * user_set_away - set user away state
+ * returns 1 if client is away or changed away message, 0 if 
+ * client is removing away status.
+ * NOTE: this function may modify user and message, so they
+ * must be mutable.
+ */
+static int user_set_away(struct User* user, char* message)
+{
+  char* away;
+  assert(0 != user);
+
+  away = user->away;
+
+  if (EmptyString(message)) {
+    /*
+     * Marking as not away
+     */
+    if (away) {
+      MyFree(away);
+      user->away = 0;
+    }
+  }
+  else {
+    /*
+     * Marking as away
+     */
+    unsigned int len = strlen(message);
+
+    if (len > AWAYLEN) {
+      message[AWAYLEN] = '\0';
+      len = AWAYLEN;
+    }
+    if (away)
+      MyFree(away);
+    away = (char*) MyMalloc(len + 1);
+    assert(0 != away);
+
+    user->away = away;
+    strcpy(away, message);
+  }
+  return (user->away != 0);
+}
+
+
+/*
+ * m_away - generic message handler
+ * - Added 14 Dec 1988 by jto.
+ *
+ * parv[0] = sender prefix
+ * parv[1] = away message
+ *
+ * TODO: Throttle aways - many people have a script which resets the away
+ *       message every 10 seconds which really chews the bandwidth.
+ */
+int m_away(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  char* away_message = parv[1];
+  int was_away = cli_user(sptr)->away != 0;
+
+  assert(0 != cptr);
+  assert(cptr == sptr);
+
+  if (user_set_away(cli_user(sptr), away_message))
+  {
+    if (!was_away)    
+      sendcmdto_serv_butone(sptr, CMD_AWAY, cptr, ":%s", away_message);
+    send_reply(sptr, RPL_NOWAWAY);
+  }
+  else {
+    sendcmdto_serv_butone(sptr, CMD_AWAY, cptr, "");
+    send_reply(sptr, RPL_UNAWAY);
+  }
+  return 0;
+}
+
+/*
+ * ms_away - server message handler
+ * - Added 14 Dec 1988 by jto.
+ *
+ * parv[0] = sender prefix
+ * parv[1] = away message
+ */
+int ms_away(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  char* away_message = parv[1];
+
+  assert(0 != cptr);
+  assert(0 != sptr);
+  /*
+   * servers can't set away
+   */
+  if (IsServer(sptr))
+    return protocol_violation(sptr,"Server trying to set itself away");
+
+  if (user_set_away(cli_user(sptr), away_message))
+    sendcmdto_serv_butone(sptr, CMD_AWAY, cptr, ":%s", away_message);
+  else
+    sendcmdto_serv_butone(sptr, CMD_AWAY, cptr, "");
+  return 0;
+}
+
+
diff --git a/ircd/m_burst.c b/ircd/m_burst.c
new file mode 100644 (file)
index 0000000..15d7034
--- /dev/null
@@ -0,0 +1,653 @@
+/*
+ * IRC - Internet Relay Chat, ircd/m_burst.c
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ *                    University of Oulu, Computing Center
+ *
+ * See file AUTHORS in IRC package for additional names of
+ * the programmers.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id: m_burst.c 1861 2008-01-03 00:07:21Z klmitch $
+ */
+
+/*
+ * m_functions execute protocol messages on this server:
+ *
+ *    cptr    is always NON-NULL, pointing to a *LOCAL* client
+ *            structure (with an open socket connected!). This
+ *            identifies the physical socket where the message
+ *            originated (or which caused the m_function to be
+ *            executed--some m_functions may call others...).
+ *
+ *    sptr    is the source of the message, defined by the
+ *            prefix part of the message if present. If not
+ *            or prefix not found, then sptr==cptr.
+ *
+ *            (!IsServer(cptr)) => (cptr == sptr), because
+ *            prefixes are taken *only* from servers...
+ *
+ *            (IsServer(cptr))
+ *                    (sptr == cptr) => the message didn't
+ *                    have the prefix.
+ *
+ *                    (sptr != cptr && IsServer(sptr) means
+ *                    the prefix specified servername. (?)
+ *
+ *                    (sptr != cptr && !IsServer(sptr) means
+ *                    that message originated from a remote
+ *                    user (not local).
+ *
+ *            combining
+ *
+ *            (!IsServer(sptr)) means that, sptr can safely
+ *            taken as defining the target structure of the
+ *            message in this server.
+ *
+ *    *Always* true (if 'parse' and others are working correct):
+ *
+ *    1)      sptr->from == cptr  (note: cptr->from == cptr)
+ *
+ *    2)      MyConnect(sptr) <=> sptr == cptr (e.g. sptr
+ *            *cannot* be a local connection, unless it's
+ *            actually cptr!). [MyConnect(x) should probably
+ *            be defined as (x == x->from) --msa ]
+ *
+ *    parc    number of variable parameter strings (if zero,
+ *            parv is allowed to be NULL)
+ *
+ *    parv    a NULL terminated list of parameter pointers,
+ *
+ *                    parv[0], sender (prefix string), if not present
+ *                            this points to an empty string.
+ *                    parv[1]...parv[parc-1]
+ *                            pointers to additional parameters
+ *                    parv[parc] == NULL, *always*
+ *
+ *            note:   it is guaranteed that parv[0]..parv[parc-1] are all
+ *                    non-NULL pointers.
+ */
+#include "config.h"
+
+#include "channel.h"
+#include "client.h"
+#include "hash.h"
+#include "ircd.h"
+#include "ircd_alloc.h"
+#include "ircd_features.h"
+#include "ircd_log.h"
+#include "ircd_reply.h"
+#include "ircd_string.h"
+#include "list.h"
+#include "match.h"
+#include "msg.h"
+#include "numeric.h"
+#include "numnicks.h"
+#include "s_conf.h"
+#include "s_misc.h"
+#include "send.h"
+#include "struct.h"
+#include "ircd_snprintf.h"
+
+/* #include <assert.h> -- Now using assert in ircd_log.h */
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+static int
+netride_modes(int parc, char **parv, const char *curr_key)
+{
+  char *modes = parv[0];
+  int result = 0;
+
+  assert(modes && modes[0] == '+');
+  while (*modes) {
+    switch (*modes++) {
+    case '-':
+      return -1;
+    case 'i':
+      result |= MODE_INVITEONLY;
+      break;
+    case 'k':
+      if (strcmp(curr_key, *++parv))
+        result |= MODE_KEY;
+      break;
+    case 'l':
+      ++parv;
+      break;
+    case 'r':
+      result |= MODE_REGONLY;
+      break;
+    }
+  }
+  return result;
+}
+
+/*
+ * ms_burst - server message handler
+ *
+ * --  by Run carlo@runaway.xs4all.nl  december 1995 till march 1997
+ *
+ * parv[0] = sender prefix
+ * parv[1] = channel name
+ * parv[2] = channel timestamp
+ * The meaning of the following parv[]'s depend on their first character:
+ * If parv[n] starts with a '+':
+ * Net burst, additive modes
+ *   parv[n] = <mode>
+ *   parv[n+1] = <param> (optional)
+ *   parv[n+2] = <param> (optional)
+ * If parv[n] starts with a '%', then n will be parc-1:
+ *   parv[n] = %<ban> <ban> <ban> ...
+ * If parv[n] starts with another character:
+ *   parv[n] = <nick>[:<mode>],<nick>[:<mode>],...
+ *   where <mode> defines the mode and op-level
+ *   for nick and all following nicks until the
+ *   next <mode> field.
+ *   Digits in the <mode> field have of two meanings:
+ *   1) if it is the first field in this BURST message
+ *      that contains digits, and/or when a 'v' is
+ *      present in the <mode>:
+ *      The absolute value of the op-level.
+ *   2) if there are only digits in this field and
+ *      it is not the first field with digits:
+ *      An op-level increment relative to the previous
+ *      op-level.
+ *   First all modeless nicks must be emmitted,
+ *   then all combinations of modes without ops
+ *   (currently that is only 'v') followed by the same
+ *   series but then with ops (currently 'o','ov').
+ *
+ * Example:
+ * "A8 B #test 87654321 +ntkAl key secret 123 A8AAG,A8AAC:v,A8AAA:0,A8AAF:2,A8AAD,A8AAB:v1,A8AAE:1 :%ban1 ban2"
+ *
+ * <mode> list example:
+ *
+ * "xxx,sss:v,ttt,aaa:123,bbb,ccc:2,ddd,kkk:v2,lll:2,mmm"
+ *
+ * means
+ *
+ *  xxx                // first modeless nicks
+ *  sss +v     // then opless nicks
+ *  ttt +v     // no ":<mode>": everything stays the same
+ *  aaa -123   // first field with digit: absolute value
+ *  bbb -123
+ *  ccc -125   // only digits, not first field: increment
+ *  ddd -125
+ *  kkk -2 +v  // field with a 'v': absolute value
+ *  lll -4 +v  // only digits: increment
+ *  mmm -4 +v
+ *
+ * Anti net.ride code.
+ *
+ * When the channel already exist, and its TS is larger than
+ * the TS in the BURST message, then we cancel all existing modes.
+ * If its is smaller then the received BURST message is ignored.
+ * If it's equal, then the received modes are just added.
+ *
+ * BURST is also accepted outside a netburst now because it
+ * is sent upstream as reaction to a DESTRUCT message.  For
+ * these BURST messages it is possible that the listed channel
+ * members are already joined.
+ */
+int ms_burst(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
+{
+  struct ModeBuf modebuf, *mbuf = 0;
+  struct Channel *chptr;
+  time_t timestamp;
+  struct Membership *member, *nmember;
+  struct Ban *lp, **lp_p;
+  unsigned int parse_flags = (MODE_PARSE_FORCE | MODE_PARSE_BURST);
+  int param, nickpos = 0, banpos = 0;
+  char modestr[BUFSIZE], nickstr[BUFSIZE], banstr[BUFSIZE];
+
+  if (parc < 3)
+    return protocol_violation(sptr,"Too few parameters for BURST");
+
+  if (!(chptr = get_channel(sptr, parv[1], CGT_CREATE)))
+    return 0; /* can't create the channel? */
+
+  timestamp = atoi(parv[2]);
+
+  if (chptr->creationtime)     /* 0 for new (empty) channels,
+                                   i.e. when this server just restarted. */
+  {
+    if (parc == 3)             /* Zannel BURST? */
+    {
+      /* An empty channel without +A set, will cause a BURST message
+        with exactly 3 parameters (because all modes have been reset).
+        If the timestamp on such channels is only a few seconds older
+        from our own, then we ignore this burst: we do not deop our
+        own side.
+        Likewise, we expect the other (empty) side to copy our timestamp
+        from our own BURST message, even though it is slightly larger.
+
+        The reason for this is to allow people to join an empty
+        non-A channel (a zannel) during a net.split, and not be
+        deopped when the net reconnects (with another zannel). When
+        someone joins a split zannel, their side increments the TS by one.
+        If they cycle a few times then we still don't have a reason to
+        deop them. Theoretically I see no reason not to accept ANY timestamp,
+        but to be sure, we only accept timestamps that are just a few
+        seconds off (one second for each time they cycled the channel). */
+
+      /* Don't even deop users who cycled four times during the net.break. */
+      if (timestamp < chptr->creationtime &&
+          chptr->creationtime <= timestamp + 4 &&
+         chptr->users != 0)    /* Only do this when WE have users, so that
+                                  if we do this the BURST that we sent has
+                                  parc > 3 and the other side will use the
+                                  test below: */
+       timestamp = chptr->creationtime; /* Do not deop our side. */
+    }
+    else if (chptr->creationtime < timestamp &&
+             timestamp <= chptr->creationtime + 4 &&
+            chptr->users == 0)
+    {
+      /* If one side of the net.junction does the above
+         timestamp = chptr->creationtime, then the other
+        side must do this: */
+      chptr->creationtime = timestamp; /* Use the same TS on both sides. */
+    }
+    /* In more complex cases, we might still end up with a
+       creationtime desync of a few seconds, but that should
+       be synced automatically rather quickly (every JOIN
+       caries a timestamp and will sync it; modes by users do
+       not carry timestamps and are accepted regardless).
+       Only when nobody joins the channel on the side with
+       the oldest timestamp before a new net.break occurs
+       precisely inbetween the desync, an unexpected bounce
+       might happen on reconnect. */
+  }
+
+  if (!chptr->creationtime || chptr->creationtime > timestamp) {
+    /*
+     * Kick local members if channel is +i or +k and our TS was larger
+     * than the burst TS (anti net.ride). The modes hack is here because
+     * we have to do this before mode_parse, as chptr may go away.
+     */
+    for (param = 3; param < parc; param++)
+    {
+      int check_modes;
+      if (parv[param][0] != '+')
+        continue;
+      check_modes = netride_modes(parc - param, parv + param, chptr->mode.key);
+      if (check_modes < 0)
+      {
+        if (chptr->users == 0)
+          sub1_from_channel(chptr);
+        return protocol_violation(sptr, "Invalid mode string in BURST");
+      }
+      else if (check_modes)
+      {
+        /* Clear any outstanding rogue invites */
+        mode_invite_clear(chptr);
+        for (member = chptr->members; member; member = nmember)
+        {
+          nmember = member->next_member;
+          if (!MyUser(member->user) || IsZombie(member))
+            continue;
+          /* Kick as netrider if key mismatch *or* remote channel is
+           * +i (unless user is an oper) *or* remote channel is +r
+           * (unless user has an account).
+           */
+          if (!(check_modes & MODE_KEY)
+              && (!(check_modes & MODE_INVITEONLY) || IsAnOper(member->user))
+              && (!(check_modes & MODE_REGONLY) || IsAccount(member->user)))
+            continue;
+          sendcmdto_serv_butone(&me, CMD_KICK, NULL, "%H %C :Net Rider", chptr, member->user);
+          sendcmdto_channel_butserv_butone(&his, CMD_KICK, chptr, NULL, 0, "%H %C :Net Rider", chptr, member->user);
+          make_zombie(member, member->user, &me, &me, chptr);
+        }
+      }
+      break;
+    }
+
+    /* If the channel had only locals, it went away by now. */
+    if (!(chptr = get_channel(sptr, parv[1], CGT_CREATE)))
+      return 0; /* can't create the channel? */
+  }
+
+  /* turn off burst joined flag */
+  for (member = chptr->members; member; member = member->next_member)
+    member->status &= ~(CHFL_BURST_JOINED|CHFL_BURST_ALREADY_OPPED|CHFL_BURST_ALREADY_VOICED);
+
+  if (!chptr->creationtime) /* mark channel as created during BURST */
+    chptr->mode.mode |= MODE_BURSTADDED;
+
+  /* new channel or an older one */
+  if (!chptr->creationtime || chptr->creationtime > timestamp) {
+    chptr->creationtime = timestamp;
+
+    modebuf_init(mbuf = &modebuf, &me, cptr, chptr,
+                MODEBUF_DEST_CHANNEL | MODEBUF_DEST_NOKEY);
+    modebuf_mode(mbuf, MODE_DEL | chptr->mode.mode); /* wipeout modes */
+    chptr->mode.mode &= MODE_BURSTADDED | MODE_WASDELJOINS;
+
+    /* wipe out modes not represented in chptr->mode.mode */
+    if (chptr->mode.limit) {
+      modebuf_mode_uint(mbuf, MODE_DEL | MODE_LIMIT, chptr->mode.limit);
+      chptr->mode.limit = 0;
+    }
+    if (chptr->mode.access) {
+      modebuf_mode_uint(mbuf, MODE_DEL | MODE_ACCESS, chptr->mode.access);
+      chptr->mode.access = 0;
+    }
+    if (chptr->mode.key[0]) {
+      modebuf_mode_string(mbuf, MODE_DEL | MODE_KEY, chptr->mode.key, 0);
+      chptr->mode.key[0] = '\0';
+    }
+       if (chptr->mode.altchan[0]) {
+      modebuf_mode_string(mbuf, MODE_DEL | MODE_ALTCHAN, chptr->mode.altchan, 0);
+      chptr->mode.altchan[0] = '\0';
+    }
+    if (chptr->mode.upass[0]) {
+      modebuf_mode_string(mbuf, MODE_DEL | MODE_UPASS, chptr->mode.upass, 0);
+      chptr->mode.upass[0] = '\0';
+    }
+    if (chptr->mode.apass[0]) {
+      modebuf_mode_string(mbuf, MODE_DEL | MODE_APASS, chptr->mode.apass, 0);
+      chptr->mode.apass[0] = '\0';
+    }
+
+    parse_flags |= (MODE_PARSE_SET | MODE_PARSE_WIPEOUT); /* wipeout keys */
+
+    /* mark bans for wipeout */
+    for (lp = chptr->banlist; lp; lp = lp->next)
+      lp->flags |= BAN_BURST_WIPEOUT;
+
+    /* clear topic set by netrider (if set) */
+    if (*chptr->topic) {
+      *chptr->topic = '\0';
+      *chptr->topic_nick = '\0';
+      chptr->topic_time = 0;
+      sendcmdto_channel_butserv_butone(&his, CMD_TOPIC, chptr, NULL, 0,
+                                       "%H :%s", chptr, chptr->topic);
+    }
+       if (*chptr->chanowner) {
+         *chptr->chanowner = '\0';
+       }
+  } else if (chptr->creationtime == timestamp) {
+    modebuf_init(mbuf = &modebuf, &me, cptr, chptr,
+                MODEBUF_DEST_CHANNEL | MODEBUF_DEST_NOKEY);
+
+    parse_flags |= MODE_PARSE_SET; /* set new modes */
+  }
+
+  param = 3; /* parse parameters */
+  while (param < parc) {
+    switch (*parv[param]) {
+    case '+': /* parameter introduces a mode string */
+      param += mode_parse(mbuf, cptr, sptr, chptr, parc - param,
+                         parv + param, parse_flags, NULL);
+      break;
+
+    case '%': /* parameter contains bans */
+      if (parse_flags & MODE_PARSE_SET) {
+       char *banlist = parv[param] + 1, *p = 0, *ban, *ptr;
+       struct Ban *newban;
+
+       for (ban = ircd_strtok(&p, banlist, " "); ban;
+            ban = ircd_strtok(&p, 0, " ")) {
+         ban = collapse(pretty_mask(ban));
+
+           /*
+            * Yeah, we should probably do this elsewhere, and make it better
+            * and more general; this will hold until we get there, though.
+            * I dislike the current add_banid API... -Kev
+            *
+            * I wish there were a better algo. for this than the n^2 one
+            * shown below *sigh*
+            */
+         for (lp = chptr->banlist; lp; lp = lp->next) {
+           if (!ircd_strcmp(lp->banstr, ban)) {
+             ban = 0; /* don't add ban */
+             lp->flags &= ~BAN_BURST_WIPEOUT; /* not wiping out */
+             break; /* new ban already existed; don't even repropagate */
+           } else if (!(lp->flags & BAN_BURST_WIPEOUT) &&
+                      !mmatch(lp->banstr, ban)) {
+             ban = 0; /* don't add ban unless wiping out bans */
+             break; /* new ban is encompassed by an existing one; drop */
+           } else if (!mmatch(ban, lp->banstr))
+             lp->flags |= BAN_OVERLAPPED; /* remove overlapping ban */
+
+           if (!lp->next)
+             break;
+         }
+
+         if (ban) { /* add the new ban to the end of the list */
+           /* Build ban buffer */
+           if (!banpos) {
+             banstr[banpos++] = ' ';
+             banstr[banpos++] = ':';
+             banstr[banpos++] = '%';
+           } else
+             banstr[banpos++] = ' ';
+           for (ptr = ban; *ptr; ptr++) /* add ban to buffer */
+             banstr[banpos++] = *ptr;
+
+           newban = make_ban(ban); /* create new ban */
+            strcpy(newban->who, "*");
+           newban->when = TStime();
+           newban->flags |= BAN_BURSTED;
+           newban->next = 0;
+           if (lp)
+             lp->next = newban; /* link it in */
+           else
+             chptr->banlist = newban;
+         }
+       }
+      } 
+      param++; /* look at next param */
+      break;
+
+    default: /* parameter contains clients */
+      {
+       struct Client *acptr;
+       char *nicklist = parv[param], *p = 0, *nick, *ptr;
+       int current_mode, last_mode, base_mode;
+       int oplevel = -1;       /* Mark first field with digits: means the same as 'o' (but with level). */
+       int last_oplevel = 0;
+       struct Membership* member;
+
+        base_mode = CHFL_DEOPPED | CHFL_BURST_JOINED;
+        if (chptr->mode.mode & MODE_DELJOINS)
+            base_mode |= CHFL_DELAYED;
+        current_mode = last_mode = base_mode;
+
+       for (nick = ircd_strtok(&p, nicklist, ","); nick;
+            nick = ircd_strtok(&p, 0, ",")) {
+
+         if ((ptr = strchr(nick, ':'))) { /* new flags; deal */
+           *ptr++ = '\0';
+
+           if (parse_flags & MODE_PARSE_SET) {
+             int current_mode_needs_reset;
+             for (current_mode_needs_reset = 1; *ptr; ptr++) {
+               if (*ptr == 'o') { /* has oper status */
+                 /*
+                  * An 'o' is pre-oplevel protocol, so this is only for
+                  * backwards compatibility.  Give them an op-level of
+                  * MAXOPLEVEL so everyone can deop them.
+                  */
+                 oplevel = MAXOPLEVEL;
+                 if (current_mode_needs_reset) {
+                   current_mode = base_mode;
+                   current_mode_needs_reset = 0;
+                 }
+                 current_mode = (current_mode & ~(CHFL_DEOPPED | CHFL_DELAYED)) | CHFL_CHANOP;
+                  /*
+                   * Older servers may send XXYYY:ov, in which case we
+                   * do not want to use the code for 'v' below.
+                   */
+                  if (ptr[1] == 'v') {
+                    current_mode |= CHFL_VOICE;
+                    ptr++;
+                  }
+               }
+               else if (*ptr == 'v') { /* has voice status */
+                 if (current_mode_needs_reset) {
+                    current_mode = base_mode;
+                   current_mode_needs_reset = 0;
+                 }
+                 current_mode = (current_mode & ~CHFL_DELAYED) | CHFL_VOICE;
+                 oplevel = -1; /* subsequent digits are an absolute op-level value. */
+                }
+        else if (*ptr == 'i') { /* has voice status */
+                 if (current_mode_needs_reset) {
+                    current_mode = base_mode;
+                   current_mode_needs_reset = 0;
+                 }
+                 current_mode = (current_mode & ~CHFL_DELAYED) | CHFL_INVISIBLE;
+                 oplevel = -1; /* subsequent digits are an absolute op-level value. */
+                }
+               else if (IsDigit(*ptr)) {
+                 int level_increment = 0;
+                 if (oplevel == -1) { /* op-level is absolute value? */
+                   if (current_mode_needs_reset) {
+                     current_mode = base_mode;
+                     current_mode_needs_reset = 0;
+                   }
+                   oplevel = 0;
+                 }
+                 current_mode = (current_mode & ~(CHFL_DEOPPED | CHFL_DELAYED)) | CHFL_CHANOP;
+                 do {
+                   level_increment = 10 * level_increment + *ptr++ - '0';
+                 } while (IsDigit(*ptr));
+                 --ptr;
+                 oplevel += level_increment;
+               }
+               else { /* I don't recognize that flag */
+                 protocol_violation(sptr, "Invalid flag '%c' in nick part of burst", *ptr);
+                 break; /* so stop processing */
+               }
+             }
+           }
+         }
+
+         if (!(acptr = findNUser(nick)) || cli_from(acptr) != cptr)
+           continue; /* ignore this client */
+
+         /* Build nick buffer */
+         nickstr[nickpos] = nickpos ? ',' : ' '; /* first char */
+         nickpos++;
+
+         for (ptr = nick; *ptr; ptr++) /* store nick */
+           nickstr[nickpos++] = *ptr;
+
+         if (current_mode != last_mode) { /* if mode changed... */
+           last_mode = current_mode;
+           last_oplevel = oplevel;
+
+           nickstr[nickpos++] = ':'; /* add a specifier */
+           if (current_mode & CHFL_VOICE)
+             nickstr[nickpos++] = 'v';
+           if (current_mode & CHFL_CHANOP)
+            {
+              if (chptr->mode.apass[0])
+               nickpos += ircd_snprintf(0, nickstr + nickpos, sizeof(nickstr) - nickpos, "%u", oplevel);
+              else
+                nickstr[nickpos++] = 'o';
+            }
+         } else if (current_mode & CHFL_CHANOP && oplevel != last_oplevel) { /* if just op level changed... */
+           nickstr[nickpos++] = ':'; /* add a specifier */
+           nickpos += ircd_snprintf(0, nickstr + nickpos, sizeof(nickstr) - nickpos, "%u", oplevel - last_oplevel);
+            last_oplevel = oplevel;
+         }
+
+         if (!(member = find_member_link(chptr, acptr)))
+         {
+           add_user_to_channel(chptr, acptr, current_mode, oplevel);
+            if (!(current_mode & CHFL_DELAYED))
+              sendcmdto_channel_butserv_butone(acptr, CMD_JOIN, chptr, NULL, 0, "%H", chptr);
+         }
+         else
+         {
+           /* The member was already joined (either by CREATE or JOIN).
+              Remember the current mode. */
+           if (member->status & CHFL_CHANOP)
+             member->status |= CHFL_BURST_ALREADY_OPPED;
+           if (member->status & CHFL_VOICE)
+             member->status |= CHFL_BURST_ALREADY_VOICED;
+           /* Synchronize with the burst. */
+           member->status |= CHFL_BURST_JOINED | (current_mode & (CHFL_CHANOP|CHFL_VOICE));
+           SetOpLevel(member, oplevel);
+         }
+       }
+      }
+      param++;
+      break;
+    } /* switch (*parv[param]) */
+  } /* while (param < parc) */
+
+  nickstr[nickpos] = '\0';
+  banstr[banpos] = '\0';
+
+  if (parse_flags & MODE_PARSE_SET) {
+    modebuf_extract(mbuf, modestr + 1); /* for sending BURST onward */
+    modestr[0] = modestr[1] ? ' ' : '\0';
+  } else
+    modestr[0] = '\0';
+
+  sendcmdto_serv_butone(sptr, CMD_BURST, cptr, "%H %Tu%s%s%s", chptr,
+                       chptr->creationtime, modestr, nickstr, banstr);
+
+  if (parse_flags & MODE_PARSE_WIPEOUT || banpos)
+    mode_ban_invalidate(chptr);
+
+  if (parse_flags & MODE_PARSE_SET) { /* any modes changed? */
+    /* first deal with channel members */
+    for (member = chptr->members; member; member = member->next_member) {
+      if (member->status & CHFL_BURST_JOINED) { /* joined during burst */
+       if ((member->status & CHFL_CHANOP) && !(member->status & CHFL_BURST_ALREADY_OPPED))
+         modebuf_mode_client(mbuf, MODE_ADD | CHFL_CHANOP, member->user, OpLevel(member));
+       if ((member->status & CHFL_VOICE) && !(member->status & CHFL_BURST_ALREADY_VOICED))
+         modebuf_mode_client(mbuf, MODE_ADD | CHFL_VOICE, member->user, OpLevel(member));
+      } else if (parse_flags & MODE_PARSE_WIPEOUT) { /* wipeout old ops */
+       if (member->status & CHFL_CHANOP)
+         modebuf_mode_client(mbuf, MODE_DEL | CHFL_CHANOP, member->user, OpLevel(member));
+       if (member->status & CHFL_VOICE)
+         modebuf_mode_client(mbuf, MODE_DEL | CHFL_VOICE, member->user, OpLevel(member));
+       member->status = (member->status
+                          & ~(CHFL_CHANNEL_MANAGER | CHFL_CHANOP | CHFL_VOICE))
+                        | CHFL_DEOPPED;
+      }
+    }
+
+    /* Now deal with channel bans */
+    lp_p = &chptr->banlist;
+    while (*lp_p) {
+      lp = *lp_p;
+
+      /* remove ban from channel */
+      if (lp->flags & (BAN_OVERLAPPED | BAN_BURST_WIPEOUT)) {
+        char *bandup;
+        DupString(bandup, lp->banstr);
+       modebuf_mode_string(mbuf, MODE_DEL | MODE_BAN,
+                           bandup, 1);
+       *lp_p = lp->next; /* clip out of list */
+        free_ban(lp);
+       continue;
+      } else if (lp->flags & BAN_BURSTED) /* add ban to channel */
+       modebuf_mode_string(mbuf, MODE_ADD | MODE_BAN,
+                           lp->banstr, 0); /* don't free banstr */
+
+      lp->flags &= BAN_IPMASK; /* reset the flag */
+      lp_p = &(*lp_p)->next;
+    }
+  }
+
+  return mbuf ? modebuf_flush(mbuf) : 0;
+}
diff --git a/ircd/m_cap.c b/ircd/m_cap.c
new file mode 100644 (file)
index 0000000..6deeedc
--- /dev/null
@@ -0,0 +1,360 @@
+/*
+ * IRC - Internet Relay Chat, ircd/m_cap.c
+ * Copyright (C) 2004 Kevin L. Mitchell <klmitch@mit.edu>
+ *
+ * See file AUTHORS in IRC package for additional names of
+ * the programmers.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+/** @file
+ * @brief Capability negotiation commands
+ * @version $Id: m_cap.c 1620 2006-02-16 03:49:55Z entrope $
+ */
+
+#include "config.h"
+
+#include "client.h"
+#include "ircd.h"
+#include "ircd_chattr.h"
+#include "ircd_log.h"
+#include "ircd_reply.h"
+#include "ircd_snprintf.h"
+#include "ircd_string.h"
+#include "msg.h"
+#include "numeric.h"
+#include "send.h"
+#include "s_auth.h"
+#include "s_user.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+typedef int (*bqcmp)(const void *, const void *);
+
+static struct capabilities {
+  enum Capab cap;
+  char *capstr;
+  unsigned long flags;
+  char *name;
+  int namelen;
+} capab_list[] = {
+#define _CAP(cap, flags, name)                                               \
+       { CAP_ ## cap, #cap, (flags), (name), sizeof(name) - 1 }
+  CAPLIST
+#undef _CAP
+};
+
+#define CAPAB_LIST_LEN (sizeof(capab_list) / sizeof(struct capabilities))
+
+static int
+capab_sort(const struct capabilities *cap1, const struct capabilities *cap2)
+{
+  return ircd_strcmp(cap1->name, cap2->name);
+}
+
+static int
+capab_search(const char *key, const struct capabilities *cap)
+{
+  const char *rb = cap->name;
+  while (ToLower(*key) == ToLower(*rb)) /* walk equivalent part of strings */
+    if (!*key++) /* hit the end, all right... */
+      return 0;
+    else /* OK, let's move on... */
+      rb++;
+
+  /* If the character they differ on happens to be a space, and it happens
+   * to be the same length as the capability name, then we've found a
+   * match; otherwise, return the difference of the two.
+   */
+  return (IsSpace(*key) && !*rb) ? 0 : (ToLower(*key) - ToLower(*rb));
+}
+
+static struct capabilities *
+find_cap(const char **caplist_p, int *neg_p)
+{
+  static int inited = 0;
+  const char *caplist = *caplist_p;
+  struct capabilities *cap = 0;
+
+  *neg_p = 0; /* clear negative flag... */
+
+  if (!inited) { /* First, let's sort the array... */
+    qsort(capab_list, CAPAB_LIST_LEN, sizeof(struct capabilities),
+         (bqcmp)capab_sort);
+    inited++; /* remember that we've done this step... */
+  }
+
+  /* Next, find first non-whitespace character... */
+  while (*caplist && IsSpace(*caplist))
+    caplist++;
+
+  /* We are now at the beginning of an element of the list; is it negative? */
+  if (*caplist == '-') {
+    caplist++; /* yes; step past the flag... */
+    *neg_p = 1; /* remember that it is negative... */
+  }
+
+  /* OK, now see if we can look up the capability... */
+  if (*caplist) {
+    if (!(cap = (struct capabilities *)bsearch(caplist, capab_list,
+                                              CAPAB_LIST_LEN,
+                                              sizeof(struct capabilities),
+                                              (bqcmp)capab_search))) {
+      /* Couldn't find the capability; advance to first whitespace character */
+      while (*caplist && !IsSpace(*caplist))
+       caplist++;
+    } else
+      caplist += cap->namelen; /* advance to end of capability name */
+  }
+
+  assert(caplist != *caplist_p || !*caplist); /* we *must* advance */
+
+  /* move ahead in capability list string--or zero pointer if we hit end */
+  *caplist_p = *caplist ? caplist : 0;
+
+  return cap; /* and return the capability (if any) */
+}
+
+/** Send a CAP \a subcmd list of capability changes to \a sptr.
+ * If more than one line is necessary, each line before the last has
+ * an added "*" parameter before that line's capability list.
+ * @param[in] sptr Client receiving capability list.
+ * @param[in] set Capabilities to show as set (with ack and sticky modifiers).
+ * @param[in] rem Capabalities to show as removed (with no other modifier).
+ * @param[in] subcmd Name of capability subcommand.
+ */
+static int
+send_caplist(struct Client *sptr, const struct CapSet *set,
+             const struct CapSet *rem, const char *subcmd)
+{
+  char capbuf[BUFSIZE] = "", pfx[16];
+  struct MsgBuf *mb;
+  int i, loc, len, flags, pfx_len;
+
+  /* set up the buffer for the final LS message... */
+  mb = msgq_make(sptr, "%:#C " MSG_CAP " %s :", &me, subcmd);
+
+  for (i = 0, loc = 0; i < CAPAB_LIST_LEN; i++) {
+    flags = capab_list[i].flags;
+    /* This is a little bit subtle, but just involves applying de
+     * Morgan's laws to the obvious check: We must display the
+     * capability if (and only if) it is set in \a rem or \a set, or
+     * if both are null and the capability is hidden.
+     */
+    if (!(rem && CapHas(rem, capab_list[i].cap))
+        && !(set && CapHas(set, capab_list[i].cap))
+        && (rem || set || (flags & CAPFL_HIDDEN)))
+      continue;
+
+    /* Build the prefix (space separator and any modifiers needed). */
+    pfx_len = 0;
+    if (loc)
+      pfx[pfx_len++] = ' ';
+    if (rem && CapHas(rem, capab_list[i].cap))
+        pfx[pfx_len++] = '-';
+    else {
+      if (flags & CAPFL_PROTO)
+        pfx[pfx_len++] = '~';
+      if (flags & CAPFL_STICKY)
+        pfx[pfx_len++] = '=';
+    }
+    pfx[pfx_len] = '\0';
+
+    len = capab_list[i].namelen + pfx_len; /* how much we'd add... */
+    if (msgq_bufleft(mb) < loc + len + 2) { /* would add too much; must flush */
+      sendcmdto_one(&me, CMD_CAP, sptr, "%s * :%s", subcmd, capbuf);
+      capbuf[(loc = 0)] = '\0'; /* re-terminate the buffer... */
+    }
+
+    loc += ircd_snprintf(0, capbuf + loc, sizeof(capbuf) - loc, "%s%s",
+                        pfx, capab_list[i].name);
+  }
+
+  msgq_append(0, mb, "%s", capbuf); /* append capabilities to the final cmd */
+  send_buffer(sptr, mb, 0); /* send them out... */
+  msgq_clean(mb); /* and release the buffer */
+
+  return 0; /* convenience return */
+}
+
+static int
+cap_ls(struct Client *sptr, const char *caplist)
+{
+  if (IsUnknown(sptr)) /* registration hasn't completed; suspend it... */
+    auth_cap_start(cli_auth(sptr));
+  return send_caplist(sptr, 0, 0, "LS"); /* send list of capabilities */
+}
+
+static int
+cap_req(struct Client *sptr, const char *caplist)
+{
+  const char *cl = caplist;
+  struct capabilities *cap;
+  struct CapSet set, rem;
+  struct CapSet cs = *cli_capab(sptr); /* capability set */
+  struct CapSet as = *cli_active(sptr); /* active set */
+  int neg;
+
+  if (IsUnknown(sptr)) /* registration hasn't completed; suspend it... */
+    auth_cap_start(cli_auth(sptr));
+
+  memset(&set, 0, sizeof(set));
+  memset(&rem, 0, sizeof(rem));
+  while (cl) { /* walk through the capabilities list... */
+    if (!(cap = find_cap(&cl, &neg)) /* look up capability... */
+       || (!neg && (cap->flags & CAPFL_PROHIBIT)) /* is it prohibited? */
+        || (neg && (cap->flags & CAPFL_STICKY))) { /* is it sticky? */
+      sendcmdto_one(&me, CMD_CAP, sptr, "NAK :%s", caplist);
+      return 0; /* can't complete requested op... */
+    }
+
+    if (neg) { /* set or clear the capability... */
+      CapSet(&rem, cap->cap);
+      CapClr(&set, cap->cap);
+      CapClr(&cs, cap->cap);
+      if (!(cap->flags & CAPFL_PROTO))
+       CapClr(&as, cap->cap);
+    } else {
+      CapClr(&rem, cap->cap);
+      CapSet(&set, cap->cap);
+      CapSet(&cs, cap->cap);
+      if (!(cap->flags & CAPFL_PROTO))
+       CapSet(&as, cap->cap);
+    }
+  }
+
+  /* Notify client of accepted changes and copy over results. */
+  send_caplist(sptr, &set, &rem, "ACK");
+  *cli_capab(sptr) = cs;
+  *cli_active(sptr) = as;
+
+  return 0;
+}
+
+static int
+cap_ack(struct Client *sptr, const char *caplist)
+{
+  const char *cl = caplist;
+  struct capabilities *cap;
+  int neg;
+
+  /* Coming from the client, this generally indicates that the client
+   * is using a new backwards-incompatible protocol feature.  As such,
+   * it does not require further response from the server.
+   */
+  while (cl) { /* walk through the capabilities list... */
+    if (!(cap = find_cap(&cl, &neg)) || /* look up capability... */
+       (neg ? HasCap(sptr, cap->cap) : !HasCap(sptr, cap->cap))) /* uh... */
+      continue;
+
+    if (neg) /* set or clear the active capability... */
+      CapClr(cli_active(sptr), cap->cap);
+    else
+      CapSet(cli_active(sptr), cap->cap);
+  }
+
+  return 0;
+}
+
+static int
+cap_clear(struct Client *sptr, const char *caplist)
+{
+  struct CapSet cleared;
+  struct capabilities *cap;
+  unsigned int ii;
+
+  /* XXX: If we ever add a capab list sorted by capab value, it would
+   * be good cache-wise to use it here. */
+  memset(&cleared, 0, sizeof(cleared));
+  for (ii = 0; ii < CAPAB_LIST_LEN; ++ii) {
+    cap = &capab_list[ii];
+    /* Only clear active non-sticky capabilities. */
+    if (!HasCap(sptr, cap->cap) || (cap->flags & CAPFL_STICKY))
+      continue;
+    CapSet(&cleared, cap->cap);
+    CapClr(cli_capab(sptr), cap->cap);
+    if (!(cap->flags & CAPFL_PROTO))
+      CapClr(cli_active(sptr), cap->cap);
+  }
+  send_caplist(sptr, 0, &cleared, "ACK");
+
+  return 0;
+}
+
+static int
+cap_end(struct Client *sptr, const char *caplist)
+{
+  if (!IsUnknown(sptr)) /* registration has completed... */
+    return 0; /* so just ignore the message... */
+
+  return auth_cap_done(cli_auth(sptr));
+}
+
+static int
+cap_list(struct Client *sptr, const char *caplist)
+{
+  /* Send the list of the client's capabilities */
+  return send_caplist(sptr, cli_capab(sptr), 0, "LIST");
+}
+
+static struct subcmd {
+  char *cmd;
+  int (*proc)(struct Client *sptr, const char *caplist);
+} cmdlist[] = {
+  { "ACK",   cap_ack   },
+  { "CLEAR", cap_clear },
+  { "END",   cap_end   },
+  { "LIST",  cap_list  },
+  { "LS",    cap_ls    },
+  { "NAK",   0         },
+  { "REQ",   cap_req   }
+};
+
+static int
+subcmd_search(const char *cmd, const struct subcmd *elem)
+{
+  return ircd_strcmp(cmd, elem->cmd);
+}
+
+/** Handle a capability request or response from a client.
+ * @param[in] cptr Client that sent us the message.
+ * @param[in] sptr Original source of message.
+ * @param[in] parc Number of arguments.
+ * @param[in] parv Argument vector.
+ * @see \ref m_functions
+ */
+int
+m_cap(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  char *subcmd, *caplist = 0;
+  struct subcmd *cmd;
+
+  if (parc < 2) /* a subcommand is required */
+    return 0;
+  subcmd = parv[1];
+  if (parc > 2) /* a capability list was provided */
+    caplist = parv[2];
+
+  /* find the subcommand handler */
+  if (!(cmd = (struct subcmd *)bsearch(subcmd, cmdlist,
+                                      sizeof(cmdlist) / sizeof(struct subcmd),
+                                      sizeof(struct subcmd),
+                                      (bqcmp)subcmd_search)))
+    return send_reply(sptr, ERR_UNKNOWNCAPCMD, subcmd);
+
+  /* then execute it... */
+  return cmd->proc ? (cmd->proc)(sptr, caplist) : 0;
+}
diff --git a/ircd/m_check.c b/ircd/m_check.c
new file mode 100644 (file)
index 0000000..47fe3c1
--- /dev/null
@@ -0,0 +1,498 @@
+/*
+ * IRC - Internet Relay Chat, ircd/m_check.c
+ * Written by David Herrmann.
+ */
+
+/*
+ * m_functions execute protocol messages on this server:
+ *
+ *    cptr    is always NON-NULL, pointing to a *LOCAL* client
+ *            structure (with an open socket connected!). This
+ *            identifies the physical socket where the message
+ *            originated (or which caused the m_function to be
+ *            executed--some m_functions may call others...).
+ *
+ *    sptr    is the source of the message, defined by the
+ *            prefix part of the message if present. If not
+ *            or prefix not found, then sptr==cptr.
+ *
+ *            (!IsServer(cptr)) => (cptr == sptr), because
+ *            prefixes are taken *only* from servers...
+ *
+ *            (IsServer(cptr))
+ *                    (sptr == cptr) => the message didn't
+ *                    have the prefix.
+ *
+ *                    (sptr != cptr && IsServer(sptr) means
+ *                    the prefix specified servername. (?)
+ *
+ *                    (sptr != cptr && !IsServer(sptr) means
+ *                    that message originated from a remote
+ *                    user (not local).
+ *
+ *            combining
+ *
+ *            (!IsServer(sptr)) means that, sptr can safely
+ *            taken as defining the target structure of the
+ *            message in this server.
+ *
+ *    *Always* true (if 'parse' and others are working correct):
+ *
+ *    1)      sptr->from == cptr  (note: cptr->from == cptr)
+ *
+ *    2)      MyConnect(sptr) <=> sptr == cptr (e.g. sptr
+ *            *cannot* be a local connection, unless it's
+ *            actually cptr!). [MyConnect(x) should probably
+ *            be defined as (x == x->from) --msa ]
+ *
+ *    parc    number of variable parameter strings (if zero,
+ *            parv is allowed to be NULL)
+ *
+ *    parv    a NULL terminated list of parameter pointers,
+ *
+ *                    parv[0], sender (prefix string), if not present
+ *                            this points to an empty string.
+ *                    parv[1]...parv[parc-1]
+ *                            pointers to additional parameters
+ *                    parv[parc] == NULL, *always*
+ *
+ *            note:   it is guaranteed that parv[0]..parv[parc-1] are all
+ *                    non-NULL pointers.
+ */
+#include "config.h"
+
+#include "channel.h"
+#include "class.h"
+#include "client.h"
+#include "hash.h"
+#include "ircd.h"
+#include "ircd_alloc.h"
+#include "ircd_defs.h"
+#include "ircd_features.h"
+#include "ircd_log.h"
+#include "ircd_reply.h"
+#include "ircd_snprintf.h"
+#include "ircd_string.h"
+#include "list.h"
+#include "listener.h"
+#include "match.h"
+#include "msg.h"
+#include "numeric.h"
+#include "numnicks.h"
+#include "querycmds.h"
+#include "s_conf.h"
+#include "s_debug.h"
+#include "s_misc.h"
+#include "s_user.h"
+#include "send.h"
+#include "sys.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <arpa/inet.h>
+
+#define COLOR_OFF '\017'
+
+void checkChannel(struct Client *sptr, struct Channel *chptr);
+void checkUsers(struct Client *sptr, struct Channel *chptr, int flags);
+void checkClient(struct Client *sptr, struct Client *acptr, int flags);
+void checkServer(struct Client *sptr, struct Client *acptr);
+
+static int checkClones(struct Channel *chptr, char *nick, char *host) {
+    int clones = 0;
+    struct Membership *lp;
+    struct Client *acptr;
+
+    for(lp = chptr->members; lp; lp = lp->next_member) {
+        acptr = lp->user;
+        if(!strcmp(acptr->cli_user->realhost, host) && strcmp(acptr->cli_name, nick)) clones++;
+    }
+
+    return ((clones) ? clones + 1 : 0);
+}
+
+/* This /check implementation is based on several other ircds. All of them
+ * are licensed under the GPL.
+ * The following comments are from each implementation.
+ * --gix
+ */
+/** ASUKA
+ * This is the implementation of the CHECK function for Asuka.
+ * Some of this code is from previous QuakeNet ircds, but most of it is mine..
+ * The old code was written by Durzel (durzel@quakenet.org).
+ *
+ * qoreQ (qoreQ@quakenet.org) - 08/14/2002
+ */
+/** IRCPlanet
+ * Modified by falcon for ircu2.10.12-ircplanet
+ *
+ * Dominik Paulus - 2007/05/12
+ */
+/** IRCu Patchset
+ * Modified by gix for the IRCu-Patchset.
+ *
+ * David Herrmann - 2009/03/09
+ */
+
+#define CHECK_CHECKCHAN 0x01 /* -c */
+#define CHECK_SHOWUSERS 0x02 /* ! -u */
+#define CHECK_OPSONLY   0x04 /* -o */
+#define CHECK_SHOWIPS   0x08 /* -i */
+
+/*
+ * Syntax: CHECK <channel|nick|server> [-flags]
+ *
+ * Where valid flags are:
+ * -c: Show channels when checking a user even if the user is on more than 50 channels.
+ * -i: Show IPs instead of hostnames when displaying results.
+ * -o: Only show channel operators when checking a channel.
+ * -u: Hide users when checking a channel. Overrides -o.
+ */
+/*
+ * m_check()
+ * generic message handler
+ */
+int mo_check(struct Client *cptr, struct Client *sptr, int parc, char *parv[]) {
+    struct Channel *chptr;
+    struct Client *acptr;
+    int i, flags = CHECK_SHOWUSERS;
+
+    if(!IsXtraOp(sptr))
+        return send_reply(sptr, ERR_NOPRIVILEGES);
+
+    if(parc < 2)
+        return send_reply(sptr, ERR_NEEDMOREPARAMS, "CHECK");
+
+    /* This checks to see if any flags have been supplied */
+    if((parc > 2) && (parv[2][0] == '-')) {
+        for(i = 1; parv[2][i]; ++i) {
+            switch (parv[2][i]) {
+                case 'c':
+                    flags |= CHECK_CHECKCHAN;
+                    break;
+                case 'o':
+                    if(flags & CHECK_SHOWUSERS)
+                        flags |= CHECK_OPSONLY;
+                    break;
+                case 'u':
+                    flags &= ~(CHECK_SHOWUSERS | CHECK_OPSONLY);
+                    break;
+                case 'i':
+                    flags |= CHECK_SHOWIPS;
+                    break;
+            }
+        }
+    }
+
+    if((chptr = FindChannel(parv[1]))) {
+        checkChannel(sptr, chptr);
+        checkUsers(sptr, chptr, flags);
+    }
+    else if((acptr = FindUser(parv[1]))) {
+        if(!IsRegistered(acptr))
+            return send_reply(sptr, ERR_SEARCHNOMATCH, "CHECK", parv[1]);
+        checkClient(sptr, acptr, flags);
+    }
+    else if((acptr = FindServer(parv[1])))
+        checkServer(sptr, acptr);
+    else send_reply(sptr, ERR_SEARCHNOMATCH, "CHECK", parv[1]);
+
+    return 1;
+}
+
+void checkServer(struct Client *sptr, struct Client *acptr) {
+    char outbuf[BUFSIZE];
+    int dlinkc = 0;
+    struct DLink* slink = NULL;
+
+    /* Header */
+    send_reply(sptr, RPL_CHKHEAD, "server", acptr->cli_name);
+    send_reply(sptr, RPL_DATASTR, " ");
+
+    ircd_snprintf(0, outbuf, sizeof(outbuf), "   Connected at: %s", myctime(acptr->cli_serv->timestamp));
+    send_reply(sptr, RPL_DATASTR, outbuf);
+
+    ircd_snprintf(0, outbuf, sizeof(outbuf), "    Server name: %s", acptr->cli_name);
+    send_reply(sptr, RPL_DATASTR,  outbuf);
+
+    ircd_snprintf(0, outbuf, sizeof(outbuf), "        Numeric: %s --> %d", NumServ(acptr), base64toint(acptr->cli_yxx));
+    send_reply(sptr, RPL_DATASTR, outbuf);
+
+    ircd_snprintf(0, outbuf, sizeof(outbuf), "          Users: %d / %d", cli_serv(acptr)->clients, base64toint(cli_serv(acptr)->nn_capacity));
+    send_reply(sptr, RPL_DATASTR, outbuf);
+
+    if(IsBurst(acptr))
+        send_reply(sptr, RPL_DATASTR, "         Status: Bursting");
+    if(IsBurstAck(acptr))
+        send_reply(sptr, RPL_DATASTR, "         Status: Awaiting EOB Ack");
+    if(IsService(acptr))
+        send_reply(sptr, RPL_DATASTR, "         Status: Network Service");
+    if(IsHub(acptr))
+        send_reply(sptr, RPL_DATASTR, "         Status: Network Hub");
+    else
+        send_reply(sptr, RPL_DATASTR, "         Status: Network Leaf");
+
+    send_reply(sptr, RPL_DATASTR, " ");
+    send_reply(sptr, RPL_DATASTR, "Downlinks:");
+    for(slink = cli_serv(acptr)->down; slink; slink = slink->next) {
+        ircd_snprintf(0, outbuf, sizeof(outbuf), "[%d] - %s%s", ++dlinkc,
+                      IsBurst(slink->value.cptr) ? "*" : IsBurstAck(slink->value.cptr) ? "!" :
+                      IsService(slink->value.cptr) ? "=" :IsHub(slink->value.cptr) ? "+" : " ",
+                      cli_name(slink->value.cptr));
+        send_reply(sptr, RPL_DATASTR, outbuf);
+    }
+    if(!dlinkc)
+        send_reply(sptr, RPL_DATASTR, "<none>");
+
+    /* Send 'END OF CHECK' message */
+    send_reply(sptr, RPL_ENDOFCHECK, " ");
+}
+
+void checkClient(struct Client *sptr, struct Client *acptr, int flags) {
+    struct Channel *chptr;
+    struct Membership *lp;
+    char outbuf[BUFSIZE], *ptr;
+    time_t nowr;
+
+    /* Header */
+    send_reply(sptr, RPL_CHKHEAD, "user", acptr->cli_name);
+    send_reply(sptr, RPL_DATASTR, " ");
+
+    ircd_snprintf(0, outbuf, sizeof(outbuf), "            Nick: %s (%s%s)", acptr->cli_name, NumNick(acptr));
+    send_reply(sptr, RPL_DATASTR, outbuf);
+
+    ircd_snprintf(0, outbuf, sizeof(outbuf), "       Signed on: %s", MyUser(acptr)?myctime(acptr->cli_firsttime):"<unknown>");
+    send_reply(sptr, RPL_DATASTR, outbuf);
+
+    ircd_snprintf(0, outbuf, sizeof(outbuf), "       Timestamp: %s (%d)", myctime(acptr->cli_lastnick), acptr->cli_lastnick);
+    send_reply(sptr, RPL_DATASTR, outbuf);
+
+    ircd_snprintf(0, outbuf, sizeof(outbuf), "           Ident: %s", acptr->cli_user->username);
+    send_reply(sptr, RPL_DATASTR, outbuf);
+
+    ircd_snprintf(0, outbuf, sizeof(outbuf), "Current Hostmask: %s", acptr->cli_user->host);
+    send_reply(sptr, RPL_DATASTR, outbuf);
+
+    ircd_snprintf(0, outbuf, sizeof(outbuf), "       Real Host: %s (%s)", acptr->cli_user->realhost, ircd_ntoa(&(cli_ip(acptr))));
+    send_reply(sptr, RPL_DATASTR, outbuf);
+
+    if(IsAccount(acptr)) {
+        ircd_snprintf(0, outbuf, sizeof(outbuf), "         Account: %s (%s)", acptr->cli_user->account, acptr->cli_user->acc_create?myctime(acptr->cli_user->acc_create):"0");
+        send_reply(sptr, RPL_DATASTR, outbuf);
+    }
+
+    if(IsFakeHost(acptr)) {
+        ircd_snprintf(0, outbuf, sizeof(outbuf), "       Fake Host: %s%c", acptr->cli_user->fakehost, COLOR_OFF);
+        send_reply(sptr, RPL_DATASTR, outbuf);
+    }
+
+    ircd_snprintf(0, outbuf, sizeof(outbuf), "       Real Name: %s%c", cli_info(acptr), COLOR_OFF);
+    send_reply(sptr, RPL_DATASTR, outbuf);
+
+    if(IsAnOper(acptr))
+        send_reply(sptr, RPL_DATASTR, "          Status: IRC Operator");
+
+    ircd_snprintf(0, outbuf, sizeof(outbuf), "    Connected to: %s", cli_name(acptr->cli_user->server));
+    send_reply(sptr, RPL_DATASTR, outbuf);
+
+    ptr = umode_str(acptr);
+    if(strlen(ptr) < 1)
+        strcpy(outbuf, "        Umode(s): <none>");
+    else
+        ircd_snprintf(0, outbuf, sizeof(outbuf), "        Umode(s): +%s", ptr);
+    send_reply(sptr, RPL_DATASTR, outbuf);
+
+    if(acptr->cli_user->joined == 0)
+        send_reply(sptr, RPL_DATASTR, "      Channel(s): <none>");
+    else if(!(flags & CHECK_CHECKCHAN) && acptr->cli_user->joined > 50) {
+        /* NB. As a sanity check, we DO NOT show the individual channels the
+         *     client is on if it is on > 50 channels.  This is to prevent the ircd
+         *     barfing ala Uworld when someone does /quote check Q :).. (I shouldn't imagine
+         *     an Oper would want to see every single channel 'x' client is on anyway if
+         *     they are on *that* many).
+         */
+        ircd_snprintf(0, outbuf, sizeof(outbuf), "      Channel(s): - (total: %u)", acptr->cli_user->joined);
+        send_reply(sptr, RPL_DATASTR, outbuf);
+    }
+    else {
+        char chntext[BUFSIZE];
+        int len = strlen("      Channel(s): ");
+        int mlen = strlen(me.cli_name) + len + strlen(sptr->cli_name);
+        *chntext = '\0';
+
+        strcpy(chntext, "      Channel(s): ");
+        for(lp = acptr->cli_user->channel; lp; lp = lp->next_channel) {
+            chptr = lp->channel;
+            if(len + strlen(chptr->chname) + mlen > BUFSIZE - 5) {
+                send_reply(sptr, RPL_DATASTR, chntext);
+                *chntext = '\0';
+                strcpy(chntext, "      Channel(s): ");
+                len = strlen(chntext);
+            }
+            if(IsDeaf(acptr))
+                *(chntext + len++) = '-';
+            if(is_chan_op(acptr, chptr))
+                *(chntext + len++) = '@';
+            else if(has_voice(acptr, chptr))
+                *(chntext + len++) = '+';
+            else if(IsZombie(lp))
+                *(chntext + len++) = '!';
+            if(len)
+                *(chntext + len) = '\0';
+
+            strcpy(chntext + len, chptr->chname);
+            len += strlen(chptr->chname);
+            strcat(chntext + len, " ");
+            len++;
+        }
+
+        if(chntext[0] != '\0')
+            send_reply(sptr, RPL_DATASTR, chntext);
+    }
+
+    /* If client processing command ISN'T target (or a registered
+     * Network Service), show idle time since the last time we
+     * parsed something.
+     */
+    if(MyUser(acptr)) {
+        nowr = CurrentTime - acptr->cli_user->last;
+        ircd_snprintf(0, outbuf, sizeof(outbuf), "        Idle for: %d days, %02ld:%02ld:%02ld",
+            nowr / 86400, (nowr / 3600) % 24, (nowr / 60) % 60, nowr % 60);
+        send_reply(sptr, RPL_DATASTR, outbuf);
+    }
+
+    /* Away message (if applicable) */
+    if(acptr->cli_user->away) {
+        ircd_snprintf(0, outbuf, sizeof(outbuf), "    Away message: %s", acptr->cli_user->away);
+        send_reply(sptr, RPL_DATASTR, outbuf);
+    }
+
+    /* If local user.. */
+    if(MyUser(acptr)) {
+        send_reply(sptr, RPL_DATASTR, " ");
+        ircd_snprintf(0, outbuf, sizeof(outbuf), "            Port: %d", cli_listener(acptr)->addr.port);
+        send_reply(sptr, RPL_DATASTR, outbuf);
+        ircd_snprintf(0, outbuf, sizeof(outbuf), "       Data sent: %0.3u bytes", cli_receiveB(acptr));
+        send_reply(sptr, RPL_DATASTR, outbuf);
+        ircd_snprintf(0, outbuf, sizeof(outbuf), "   Data received: %0.3u bytes", cli_sendB(acptr));
+        send_reply(sptr, RPL_DATASTR, outbuf);
+        ircd_snprintf(0, outbuf, sizeof(outbuf), "   receiveQ size: %d bytes (max. %d bytes)", DBufLength(&(cli_recvQ(acptr))), feature_int(FEAT_CLIENT_FLOOD));
+        send_reply(sptr, RPL_DATASTR, outbuf);
+        ircd_snprintf(0, outbuf, sizeof(outbuf), "      sendQ size: %d bytes (max. %d bytes)", DBufLength(&(cli_sendQ(acptr))), get_sendq(acptr));
+        send_reply(sptr, RPL_DATASTR, outbuf);
+    }
+
+    send_reply(sptr, RPL_ENDOFCHECK, " ");
+}
+
+void checkChannel(struct Client *sptr, struct Channel *chptr) {
+    char outbuf[TOPICLEN + MODEBUFLEN + 64], modebuf[MODEBUFLEN], parabuf[MODEBUFLEN];
+
+    /* Header */
+    send_reply(sptr, RPL_CHKHEAD, "channel", chptr->chname);
+    send_reply(sptr, RPL_DATASTR, " ");
+
+    /* Creation Time */
+    ircd_snprintf(sptr, outbuf, sizeof(outbuf), "  Creation time: %s", myctime(chptr->creationtime));
+    send_reply(sptr, RPL_DATASTR, outbuf);
+
+    /* Topic */
+    if(strlen(chptr->topic) <= 0)
+        send_reply(sptr, RPL_DATASTR, "          Topic: <none>");
+    else {
+        ircd_snprintf(sptr, outbuf, sizeof(outbuf), "          Topic: %s", chptr->topic);
+        send_reply(sptr, RPL_DATASTR, outbuf);
+        ircd_snprintf(sptr, outbuf, sizeof(outbuf), "         Set by: %s", chptr->topic_nick);
+        send_reply(sptr, RPL_DATASTR, outbuf);
+    }
+
+    strcpy(outbuf, "Channel mode(s): ");
+
+    modebuf[0] = '\0';
+    parabuf[0] = '\0';
+    channel_modes(sptr, modebuf, parabuf, sizeof(modebuf), chptr, 0);
+
+    if(modebuf[1] == '\0')
+        strcat(outbuf, "<none>");
+    else if(*parabuf) {
+        strcat(outbuf, modebuf);
+        strcat(outbuf, " ");
+        strcat(outbuf, parabuf);
+    }
+    else
+        strcat(outbuf, modebuf);
+
+    send_reply(sptr, RPL_DATASTR, outbuf);
+    /* Don't send 'END OF CHECK' message, it's sent in checkUsers, which is called after this. */
+}
+
+void checkUsers(struct Client *sptr, struct Channel *chptr, int flags) {
+    struct Membership *lp;
+    struct Ban *channelban;
+    struct Client *acptr;
+
+    char outbuf[BUFSIZE], ustat[64];
+    int cntr = 0, opcntr = 0, vcntr = 0, clones = 0, bans = 0, c = 0, authed = 0;
+
+    if(flags & CHECK_SHOWUSERS) send_reply(sptr, RPL_DATASTR, "Users (@ = op, + = voice)");
+
+    for(lp = chptr->members; lp; lp = lp->next_member) {
+        int opped = 0;
+
+        acptr = lp->user;
+        if((c = checkClones(chptr, acptr->cli_name, acptr->cli_user->realhost)) != 0) {
+            ircd_snprintf(0, ustat, sizeof(ustat), "%2d ", c);
+            clones++;
+        }
+        else
+            strcpy(ustat, "   ");
+
+        if(chptr && is_chan_op(acptr, chptr)) {
+            strcat(ustat, "@");
+            opcntr++;
+            opped = 1;
+        }
+        else if(chptr && has_voice(acptr, chptr)) {
+            strcat(ustat, "+");
+            vcntr++;
+        }
+        else
+            strcat(ustat, " ");
+
+        if((c = IsAccount(acptr)) != 0) ++authed;
+        if((flags & CHECK_SHOWUSERS) && (!(flags & CHECK_OPSONLY) || opped)) {
+            ircd_snprintf(0, outbuf, sizeof(outbuf), "%s%c", acptr->cli_info, COLOR_OFF);
+            send_reply(sptr, RPL_CHANUSER, ustat, acptr->cli_name, acptr->cli_user->username,
+                       (flags & CHECK_SHOWIPS) ? ircd_ntoa(&cli_ip(acptr)) : acptr->cli_user->realhost, outbuf, 
+                       (c ? acptr->cli_user->account : ""));
+        }
+
+        cntr++;
+    }
+
+    ircd_snprintf(0, outbuf, sizeof(outbuf), "Total users: %d (%d ops, %d voiced, %d clones, %d authed)",
+                  cntr, opcntr, vcntr, clones, authed);
+    send_reply(sptr, RPL_DATASTR, outbuf);
+
+    /* Do not display bans if ! flags & CHECK_SHOWUSERS */
+    if(!(flags & CHECK_SHOWUSERS)) {
+        send_reply(sptr, RPL_ENDOFCHECK, " ");
+        return;
+    }
+
+    send_reply(sptr, RPL_DATASTR, " ");
+    /* Bans */
+    send_reply(sptr, RPL_DATASTR, "Bans/Exceptions on channel:");
+
+    for(channelban = chptr->banlist; channelban; channelban = channelban->next) {
+        ircd_snprintf(0, outbuf, sizeof(outbuf),  "%c [%d] - %s - Set by %s, on %s", (channelban->flags & BAN_EXCEPTION)?'e':'b',
+                      ++bans, channelban->banstr, channelban->who, myctime(channelban->when));
+        send_reply(sptr, RPL_DATASTR, outbuf);
+    }
+
+    if(bans == 0)
+        send_reply(sptr, RPL_DATASTR, "<none>");
+
+    send_reply(sptr, RPL_ENDOFCHECK, " ");
+}
+
diff --git a/ircd/m_clearmode.c b/ircd/m_clearmode.c
new file mode 100644 (file)
index 0000000..4d0f179
--- /dev/null
@@ -0,0 +1,316 @@
+/*
+ * IRC - Internet Relay Chat, ircd/m_clearmode.c
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ *                    University of Oulu, Computing Center
+ * Copyright (C) 2000 Kevin L. Mitchell <klmitch@mit.edu>
+ *
+ * See file AUTHORS in IRC package for additional names of
+ * the programmers.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id: m_clearmode.c 1496 2005-09-27 02:41:57Z entrope $
+ */
+
+/*
+ * m_functions execute protocol messages on this server:
+ *
+ *    cptr    is always NON-NULL, pointing to a *LOCAL* client
+ *            structure (with an open socket connected!). This
+ *            identifies the physical socket where the message
+ *            originated (or which caused the m_function to be
+ *            executed--some m_functions may call others...).
+ *
+ *    sptr    is the source of the message, defined by the
+ *            prefix part of the message if present. If not
+ *            or prefix not found, then sptr==cptr.
+ *
+ *            (!IsServer(cptr)) => (cptr == sptr), because
+ *            prefixes are taken *only* from servers...
+ *
+ *            (IsServer(cptr))
+ *                    (sptr == cptr) => the message didn't
+ *                    have the prefix.
+ *
+ *                    (sptr != cptr && IsServer(sptr) means
+ *                    the prefix specified servername. (?)
+ *
+ *                    (sptr != cptr && !IsServer(sptr) means
+ *                    that message originated from a remote
+ *                    user (not local).
+ *
+ *            combining
+ *
+ *            (!IsServer(sptr)) means that, sptr can safely
+ *            taken as defining the target structure of the
+ *            message in this server.
+ *
+ *    *Always* true (if 'parse' and others are working correct):
+ *
+ *    1)      sptr->from == cptr  (note: cptr->from == cptr)
+ *
+ *    2)      MyConnect(sptr) <=> sptr == cptr (e.g. sptr
+ *            *cannot* be a local connection, unless it's
+ *            actually cptr!). [MyConnect(x) should probably
+ *            be defined as (x == x->from) --msa ]
+ *
+ *    parc    number of variable parameter strings (if zero,
+ *            parv is allowed to be NULL)
+ *
+ *    parv    a NULL terminated list of parameter pointers,
+ *
+ *                    parv[0], sender (prefix string), if not present
+ *                            this points to an empty string.
+ *                    parv[1]...parv[parc-1]
+ *                            pointers to additional parameters
+ *                    parv[parc] == NULL, *always*
+ *
+ *            note:   it is guaranteed that parv[0]..parv[parc-1] are all
+ *                    non-NULL pointers.
+ */
+#include "config.h"
+
+#include "client.h"
+#include "channel.h"
+#include "hash.h"
+#include "ircd.h"
+#include "ircd_alloc.h"
+#include "ircd_features.h"
+#include "ircd_log.h"
+#include "ircd_reply.h"
+#include "ircd_string.h"
+#include "list.h"
+#include "msg.h"
+#include "numeric.h"
+#include "numnicks.h"
+#include "s_conf.h"
+#include "send.h"
+
+/* #include <assert.h> -- Now using assert in ircd_log.h */
+
+/*
+ * do_clearmode(struct Client *cptr, struct Client *sptr,
+ *             struct Channel *chptr, char *control)
+ *
+ * This is the function that actually clears the channel modes.
+ */
+static int
+do_clearmode(struct Client *cptr, struct Client *sptr, struct Channel *chptr,
+            char *control)
+{
+  static int flags[] = {
+    MODE_CHANOP,       'o',
+    MODE_VOICE,                'v',
+    MODE_PRIVATE,      'p',
+    MODE_SECRET,       's',
+    MODE_MODERATED,    'm',
+    MODE_TOPICLIMIT,   't',
+    MODE_INVITEONLY,   'i',
+    MODE_NOPRIVMSGS,   'n',
+    MODE_KEY,          'k',
+    MODE_BAN,          'b',
+    MODE_LIMIT,                'l',
+    MODE_REGONLY,      'r',
+    MODE_DELJOINS,      'D',
+    MODE_NOCOLOUR,      'c',
+    MODE_NOCTCP,        'C',
+    MODE_NOAMSGS,       'M',
+    0x0, 0x0
+  };
+  int *flag_p;
+  unsigned int del_mode = 0;
+  char control_buf[20];
+  int control_buf_i = 0;
+  struct ModeBuf mbuf;
+  struct Ban *link, *next;
+  struct Membership *member;
+
+  /* Ok, so what are we supposed to get rid of? */
+  for (; *control; control++) {
+    for (flag_p = flags; flag_p[0]; flag_p += 2)
+      if (*control == flag_p[1]) {
+       del_mode |= flag_p[0];
+       break;
+      }
+  }
+
+  if (!del_mode)
+    return 0; /* nothing to remove; ho hum. */
+
+  modebuf_init(&mbuf, sptr, cptr, chptr,
+              (MODEBUF_DEST_CHANNEL | /* Send MODE to channel */
+               MODEBUF_DEST_OPMODE  | /* Treat it like an OPMODE */
+               MODEBUF_DEST_HACK4));  /* Generate a HACK(4) notice */
+
+  modebuf_mode(&mbuf, MODE_DEL | (del_mode & chptr->mode.mode));
+  chptr->mode.mode &= ~del_mode; /* and of course actually delete them */
+
+  /* If we're removing invite, remove all the invites */
+  if (del_mode & MODE_INVITEONLY)
+    mode_invite_clear(chptr);
+
+  /*
+   * If we're removing the key, note that; note that we can't clear
+   * the key until after modebuf_* are done with it
+   */
+  if (del_mode & MODE_KEY && *chptr->mode.key)
+    modebuf_mode_string(&mbuf, MODE_DEL | MODE_KEY, chptr->mode.key, 0);
+
+  /* If we're removing the limit, note that and clear the limit */
+  if (del_mode & MODE_LIMIT && chptr->mode.limit) {
+    modebuf_mode_uint(&mbuf, MODE_DEL | MODE_LIMIT, chptr->mode.limit);
+    chptr->mode.limit = 0; /* not referenced, so safe */
+  }
+
+  /*
+   * Go through and mark the bans for deletion; note that we can't
+   * free them until after modebuf_* are done with them
+   */
+  if (del_mode & MODE_BAN) {
+    for (link = chptr->banlist; link; link = next) {
+      char *bandup;
+      next = link->next;
+
+      DupString(bandup, link->banstr);
+      modebuf_mode_string(&mbuf, MODE_DEL | MODE_BAN, /* delete ban */
+                         bandup, 1);
+      free_ban(link);
+    }
+
+    chptr->banlist = 0;
+  }
+
+  /* Deal with users on the channel */
+  if (del_mode & (MODE_BAN | MODE_CHANOP | MODE_VOICE))
+    for (member = chptr->members; member; member = member->next_member) {
+      if (IsZombie(member)) /* we ignore zombies */
+       continue;
+
+      if (del_mode & MODE_BAN) /* If we cleared bans, clear the valid flags */
+       ClearBanValid(member);
+
+      /* Drop channel operator status */
+      if (IsChanOp(member) && del_mode & MODE_CHANOP) {
+       modebuf_mode_client(&mbuf, MODE_DEL | MODE_CHANOP, member->user, MAXOPLEVEL + 1);
+       member->status &= ~CHFL_CHANOP;
+      }
+
+      /* Drop voice */
+      if (HasVoice(member) && del_mode & MODE_VOICE) {
+       modebuf_mode_client(&mbuf, MODE_DEL | MODE_VOICE, member->user, MAXOPLEVEL + 1);
+       member->status &= ~CHFL_VOICE;
+      }
+    }
+
+  /* And flush the modes to the channel */
+  modebuf_flush(&mbuf);
+
+  /* Finally, we can clear the key... */
+  if (del_mode & MODE_KEY)
+    chptr->mode.key[0] = '\0';
+
+  /* Ok, build control string again */
+  for (flag_p = flags; flag_p[0]; flag_p += 2)
+    if (del_mode & flag_p[0])
+      control_buf[control_buf_i++] = flag_p[1];
+
+  control_buf[control_buf_i] = '\0';
+
+  /* Log it... */
+  log_write(LS_OPERMODE, L_INFO, LOG_NOSNOTICE, "%#C CLEARMODE %H %s", sptr,
+           chptr, control_buf);
+
+  /* Then send it */
+  if (!IsLocalChannel(chptr->chname))
+    sendcmdto_serv_butone(sptr, CMD_CLEARMODE, cptr, "%H %s", chptr,
+                         control_buf);
+
+  return 0;
+}
+
+/*
+ * ms_clearmode - server message handler
+ *
+ * parv[0] = Send prefix
+ * parv[1] = Channel name
+ * parv[2] = Control string
+ */
+int
+ms_clearmode(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  struct Channel *chptr;
+
+  if (parc < 3)
+    return need_more_params(sptr, "CLEARMODE");
+
+  if (!IsPrivileged(sptr)) {
+    protocol_violation(sptr,"No privileges on source for CLEARMODE, desync?");
+    return send_reply(sptr, ERR_NOPRIVILEGES);
+  }
+
+  if (!IsChannelName(parv[1]) || IsLocalChannel(parv[1]) ||
+      !(chptr = FindChannel(parv[1])))
+    return send_reply(sptr, ERR_NOSUCHCHANNEL, parv[1]);
+
+  return do_clearmode(cptr, sptr, chptr, parv[2]);
+}
+
+/*
+ * mo_clearmode - oper message handler
+ *
+ * parv[0] = Send prefix
+ * parv[1] = Channel name
+ * parv[2] = Control string
+ */
+int
+mo_clearmode(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  struct Channel *chptr;
+  char *control = "ovpsmikbl"; /* default control string */
+  const char *chname, *qreason;
+  int force = 0;
+
+  if (!feature_bool(FEAT_CONFIG_OPERCMDS))
+    return send_reply(sptr, ERR_DISABLED, "CLEARMODE");
+
+  if (parc < 2)
+    return need_more_params(sptr, "CLEARMODE");
+
+  if (parc > 2)
+    control = parv[2];
+
+  chname = parv[1];
+  if (*chname == '!')
+  {
+    chname++;
+    if (!HasPriv(sptr, IsLocalChannel(chname) ?
+                         PRIV_FORCE_LOCAL_OPMODE :
+                         PRIV_FORCE_OPMODE))
+      return send_reply(sptr, ERR_NOPRIVILEGES);
+    force = 1;
+  }
+
+  if (!HasPriv(sptr,
+              IsLocalChannel(chname) ? PRIV_LOCAL_OPMODE : PRIV_OPMODE))
+    return send_reply(sptr, ERR_NOPRIVILEGES);
+
+  if (('#' != *chname && '&' != *chname) || !(chptr = FindChannel(chname)))
+    return send_reply(sptr, ERR_NOSUCHCHANNEL, chname);
+
+  if (!force && (qreason = find_quarantine(chptr->chname)))
+    return send_reply(sptr, ERR_QUARANTINED, chptr->chname, qreason);
+
+  return do_clearmode(cptr, sptr, chptr, control);
+}
diff --git a/ircd/m_close.c b/ircd/m_close.c
new file mode 100644 (file)
index 0000000..ca3cd48
--- /dev/null
@@ -0,0 +1,106 @@
+/*
+ * IRC - Internet Relay Chat, ircd/m_close.c
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ *                    University of Oulu, Computing Center
+ *
+ * See file AUTHORS in IRC package for additional names of
+ * the programmers.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id: m_close.c 1271 2004-12-11 05:14:07Z klmitch $
+ */
+
+/*
+ * m_functions execute protocol messages on this server:
+ *
+ *    cptr    is always NON-NULL, pointing to a *LOCAL* client
+ *            structure (with an open socket connected!). This
+ *            identifies the physical socket where the message
+ *            originated (or which caused the m_function to be
+ *            executed--some m_functions may call others...).
+ *
+ *    sptr    is the source of the message, defined by the
+ *            prefix part of the message if present. If not
+ *            or prefix not found, then sptr==cptr.
+ *
+ *            (!IsServer(cptr)) => (cptr == sptr), because
+ *            prefixes are taken *only* from servers...
+ *
+ *            (IsServer(cptr))
+ *                    (sptr == cptr) => the message didn't
+ *                    have the prefix.
+ *
+ *                    (sptr != cptr && IsServer(sptr) means
+ *                    the prefix specified servername. (?)
+ *
+ *                    (sptr != cptr && !IsServer(sptr) means
+ *                    that message originated from a remote
+ *                    user (not local).
+ *
+ *            combining
+ *
+ *            (!IsServer(sptr)) means that, sptr can safely
+ *            taken as defining the target structure of the
+ *            message in this server.
+ *
+ *    *Always* true (if 'parse' and others are working correct):
+ *
+ *    1)      sptr->from == cptr  (note: cptr->from == cptr)
+ *
+ *    2)      MyConnect(sptr) <=> sptr == cptr (e.g. sptr
+ *            *cannot* be a local connection, unless it's
+ *            actually cptr!). [MyConnect(x) should probably
+ *            be defined as (x == x->from) --msa ]
+ *
+ *    parc    number of variable parameter strings (if zero,
+ *            parv is allowed to be NULL)
+ *
+ *    parv    a NULL terminated list of parameter pointers,
+ *
+ *                    parv[0], sender (prefix string), if not present
+ *                            this points to an empty string.
+ *                    parv[1]...parv[parc-1]
+ *                            pointers to additional parameters
+ *                    parv[parc] == NULL, *always*
+ *
+ *            note:   it is guaranteed that parv[0]..parv[parc-1] are all
+ *                    non-NULL pointers.
+ */
+#include "config.h"
+
+#include "client.h"
+#include "ircd.h"
+#include "ircd_log.h"
+#include "ircd_reply.h"
+#include "numeric.h"
+#include "s_bsd.h"
+#include "send.h"
+
+/* #include <assert.h> -- Now using assert in ircd_log.h */
+
+/*
+ * mo_close - oper message handler
+ * - added by Darren Reed Jul 13 1992.
+ */
+int mo_close(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  assert(0 != cptr);
+  assert(cptr == sptr);
+  assert(IsAnOper(sptr));
+
+  return send_reply(sptr, RPL_CLOSEEND,
+                   net_close_unregistered_connections(sptr));
+}
diff --git a/ircd/m_connect.c b/ircd/m_connect.c
new file mode 100644 (file)
index 0000000..8f42a25
--- /dev/null
@@ -0,0 +1,343 @@
+/*
+ * IRC - Internet Relay Chat, ircd/m_connect.c
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ *                    University of Oulu, Computing Center
+ *
+ * See file AUTHORS in IRC package for additional names of
+ * the programmers.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id: m_connect.c 1807 2007-05-20 13:55:59Z entrope $
+ */
+
+/*
+ * m_functions execute protocol messages on this server:
+ *
+ *    cptr    is always NON-NULL, pointing to a *LOCAL* client
+ *            structure (with an open socket connected!). This
+ *            identifies the physical socket where the message
+ *            originated (or which caused the m_function to be
+ *            executed--some m_functions may call others...).
+ *
+ *    sptr    is the source of the message, defined by the
+ *            prefix part of the message if present. If not
+ *            or prefix not found, then sptr==cptr.
+ *
+ *            (!IsServer(cptr)) => (cptr == sptr), because
+ *            prefixes are taken *only* from servers...
+ *
+ *            (IsServer(cptr))
+ *                    (sptr == cptr) => the message didn't
+ *                    have the prefix.
+ *
+ *                    (sptr != cptr && IsServer(sptr) means
+ *                    the prefix specified servername. (?)
+ *
+ *                    (sptr != cptr && !IsServer(sptr) means
+ *                    that message originated from a remote
+ *                    user (not local).
+ *
+ *            combining
+ *
+ *            (!IsServer(sptr)) means that, sptr can safely
+ *            taken as defining the target structure of the
+ *            message in this server.
+ *
+ *    *Always* true (if 'parse' and others are working correct):
+ *
+ *    1)      sptr->from == cptr  (note: cptr->from == cptr)
+ *
+ *    2)      MyConnect(sptr) <=> sptr == cptr (e.g. sptr
+ *            *cannot* be a local connection, unless it's
+ *            actually cptr!). [MyConnect(x) should probably
+ *            be defined as (x == x->from) --msa ]
+ *
+ *    parc    number of variable parameter strings (if zero,
+ *            parv is allowed to be NULL)
+ *
+ *    parv    a NULL terminated list of parameter pointers,
+ *
+ *                    parv[0], sender (prefix string), if not present
+ *                            this points to an empty string.
+ *                    parv[1]...parv[parc-1]
+ *                            pointers to additional parameters
+ *                    parv[parc] == NULL, *always*
+ *
+ *            note:   it is guaranteed that parv[0]..parv[parc-1] are all
+ *                    non-NULL pointers.
+ */
+#include "config.h"
+
+#include "client.h"
+#include "crule.h"
+#include "hash.h"
+#include "ircd.h"
+#include "ircd_features.h"
+#include "ircd_log.h"
+#include "ircd_reply.h"
+#include "ircd_string.h"
+#include "jupe.h"
+#include "match.h"
+#include "msg.h"
+#include "numeric.h"
+#include "numnicks.h"
+#include "s_bsd.h"
+#include "s_conf.h"
+#include "s_user.h"
+#include "send.h"
+
+/* #include <assert.h> -- Now using assert in ircd_log.h */
+#include <stdlib.h>
+
+/*
+ * ms_connect - server message handler
+ * - Added by Jto 11 Feb 1989
+ *
+ *    parv[0] = sender prefix
+ *    parv[1] = servername
+ *    parv[2] = port number
+ *    parv[3] = remote server
+ */
+int ms_connect(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  unsigned short   port;
+  unsigned short   tmpport;
+  const char*      rule;
+  struct ConfItem* aconf;
+  struct Client*   acptr;
+  struct Jupe*     ajupe;
+
+  assert(0 != cptr);
+  assert(0 != sptr);
+
+  if (!IsPrivileged(sptr))
+    return send_reply(sptr, ERR_NOPRIVILEGES);
+
+  if (parc < 4) {
+    /*
+     * this is coming from a server which should have already
+     * checked it's args, if we don't have parc == 4, something
+     * isn't right.
+     */
+    protocol_violation(sptr, "Too few parameters to connect");
+    return need_more_params(sptr, "CONNECT");
+  }
+
+  if (hunt_server_cmd(sptr, CMD_CONNECT, cptr, 1, "%s %s :%C", 3, parc, parv)
+      != HUNTED_ISME)
+    return 0;
+
+  /*
+   * need to find the conf entry first so we can use the server name from
+   * the conf entry instead of parv[1] to find out if the server is already
+   * present below. --Bleep
+   */
+  if (0 == (aconf = conf_find_server(parv[1]))) {
+    sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :Connect: Host %s not listed "
+                 "in ircd.conf", sptr, parv[1]);
+    return 0;
+  }
+  /*
+   * use aconf->name to look up the server
+   */
+  if ((acptr = FindServer(aconf->name))) {
+    sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :Connect: Server %s already "
+                 "exists from %s", sptr, parv[1], cli_name(cli_from(acptr)));
+    return 0;
+  }
+  /*
+   * Evaluate connection rules...  If no rules found, allow the
+   * connect.   Otherwise stop with the first true rule (ie: rules
+   * are ored together.  Oper connects are effected only by D
+   * lines (CRULEALL) not d lines (CRULEAUTO).
+   */
+  if ((rule = conf_eval_crule(aconf->name, CRULE_ALL))) {
+    sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :Connect: Disallowed by rule: %s", sptr, rule);
+    return 0;
+  }
+  /*
+   * Check to see if the server is juped; if it is, disallow the connect
+   */
+  if ((ajupe = jupe_find(aconf->name)) && JupeIsActive(ajupe)) {
+    sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :Connect: Server %s is juped: %s",
+                 sptr, JupeServer(ajupe), JupeReason(ajupe));
+    return 0;
+  }
+
+  /*
+   * Allow opers to /connect foo.* 0 bah.* to connect foo and bah
+   * using the conf's configured port
+   */
+  port = atoi(parv[2]);
+  /*
+   * save the old port
+   */
+  tmpport = aconf->address.port;
+  if (port)
+    aconf->address.port = port;
+  else
+    port = aconf->address.port;
+
+  /*
+   * Notify all operators about remote connect requests
+   */
+  sendwallto_group_butone(&me, WALL_WALLOPS, 0,
+                       "Remote CONNECT %s %s from %s", parv[1],
+                       parv[2] ? parv[2] : "",
+                       get_client_name(sptr, HIDE_IP));
+  log_write(LS_NETWORK, L_INFO, 0, "CONNECT From %C : %s %s", sptr, parv[1],
+           parv[2] ? parv[2] : "");
+
+  if (connect_server(aconf, sptr)) {
+    sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :*** Connecting to %s.", sptr,
+                 aconf->name);
+  }
+  else {
+    sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :*** Connection to %s failed",
+                 sptr, aconf->name);
+  }
+  aconf->address.port = tmpport;
+  return 0;
+}
+
+/*
+ * mo_connect - oper message handler
+ * - Added by Jto 11 Feb 1989
+ *
+ *    parv[0] = sender prefix
+ *    parv[1] = servername
+ *    parv[2] = port number
+ *    parv[3] = remote server
+ */
+int mo_connect(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  unsigned short   port;
+  unsigned short   tmpport;
+  const char*      rule;
+  struct ConfItem* aconf;
+  struct Client*   acptr;
+  struct Jupe*     ajupe;
+
+  assert(0 != cptr);
+  assert(cptr == sptr);
+  assert(IsAnOper(sptr));
+
+  if (parc < 2)
+    return need_more_params(sptr, "CONNECT");
+
+  if (parc > 3) {
+    /*
+     * if parc > 3, we are trying to connect two remote
+     * servers to each other
+     */
+    if (IsLocOp(sptr)) {
+      /*
+       * Only allow LocOps to make local CONNECTS --SRB
+       */
+      return send_reply(cptr, ERR_NOPRIVILEGES);
+    }
+    else {
+      struct Client* acptr2;
+      struct Client* acptr3;
+
+      if (!(acptr3 = find_match_server(parv[3]))) {
+        return send_reply(sptr, ERR_NOSUCHSERVER, parv[3]);
+      }
+
+      /*
+       * Look for closest matching server 
+       * needed for "/connect blah 4400 *"?
+       */
+      for (acptr2 = acptr3; acptr2 != &me; acptr2 = cli_serv(acptr2)->up) {
+        if (!match(parv[3], cli_name(acptr2)))
+          acptr3 = acptr2;
+      }
+      parv[3] = cli_name(acptr3);
+      if (hunt_server_cmd(sptr, CMD_CONNECT, cptr, 1, "%s %s :%C", 3, parc,
+                         parv) != HUNTED_ISME)
+        return 0;
+    }
+  }
+  /*
+   * need to find the conf entry first so we can use the server name from
+   * the conf entry instead of parv[1] to find out if the server is already
+   * present below. --Bleep
+   */
+  if (0 == (aconf = conf_find_server(parv[1]))) {
+    sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :Connect: Host %s not listed "
+                 "in ircd.conf", sptr, parv[1]);
+    return 0;
+  }
+  /*
+   * use aconf->name to look up the server, see above
+   */
+  if ((acptr = FindServer(aconf->name))) {
+    sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :Connect: Server %s already "
+                 "exists from %s", sptr, parv[1], cli_name(cli_from(acptr)));
+    return 0;
+  }
+  /*
+   * Evaluate connection rules...  If no rules found, allow the
+   * connect.   Otherwise stop with the first true rule (ie: rules
+   * are ored together.  Oper connects are effected only by D
+   * lines (CRULEALL) not d lines (CRULEAUTO).
+   */
+  if ((rule = conf_eval_crule(aconf->name, CRULE_ALL))) {
+    sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :Connect: Disallowed by rule: %s", sptr, rule);
+    return 0;
+  }
+  /*
+   * Check to see if the server is juped; if it is, disallow the connect
+   */
+  if ((ajupe = jupe_find(aconf->name)) && JupeIsActive(ajupe)) {
+    sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :Connect: Server %s is juped: %s",
+                 sptr, JupeServer(ajupe), JupeReason(ajupe));
+    return 0;
+  }
+  /*
+   *  Get port number from user, if given. If not specified,
+   *  use the default from configuration structure. If missing
+   *  from there, then use the precompiled default.
+   */
+  port = aconf->address.port;
+  if (parc > 2) {
+    assert(0 != parv[2]);
+    if (0 == (port = atoi(parv[2]))) {
+      sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :Connect: Invalid port number",
+                   sptr);
+      return 0;
+    }
+  }
+  if (0 == port && 0 == (port = feature_int(FEAT_SERVER_PORT))) {
+    sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :Connect: missing port number",
+                 sptr);
+    return 0;
+  }
+
+  tmpport = aconf->address.port;
+  aconf->address.port = port;
+
+  if (connect_server(aconf, sptr)) {
+    sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :*** Connecting to %s.", sptr,
+                 aconf->name);
+  }
+  else {
+    sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :*** Connection to %s failed",
+                 sptr, aconf->name);
+  }
+  aconf->address.port = tmpport;
+  return 0;
+}
diff --git a/ircd/m_cprivmsg.c b/ircd/m_cprivmsg.c
new file mode 100644 (file)
index 0000000..825199c
--- /dev/null
@@ -0,0 +1,130 @@
+/*
+ * IRC - Internet Relay Chat, ircd/m_cprivmsg.c
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ *                    University of Oulu, Computing Center
+ *
+ * See file AUTHORS in IRC package for additional names of
+ * the programmers.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id: m_cprivmsg.c 1271 2004-12-11 05:14:07Z klmitch $
+ */
+
+/*
+ * m_functions execute protocol messages on this server:
+ *
+ *    cptr    is always NON-NULL, pointing to a *LOCAL* client
+ *            structure (with an open socket connected!). This
+ *            identifies the physical socket where the message
+ *            originated (or which caused the m_function to be
+ *            executed--some m_functions may call others...).
+ *
+ *    sptr    is the source of the message, defined by the
+ *            prefix part of the message if present. If not
+ *            or prefix not found, then sptr==cptr.
+ *
+ *            (!IsServer(cptr)) => (cptr == sptr), because
+ *            prefixes are taken *only* from servers...
+ *
+ *            (IsServer(cptr))
+ *                    (sptr == cptr) => the message didn't
+ *                    have the prefix.
+ *
+ *                    (sptr != cptr && IsServer(sptr) means
+ *                    the prefix specified servername. (?)
+ *
+ *                    (sptr != cptr && !IsServer(sptr) means
+ *                    that message originated from a remote
+ *                    user (not local).
+ *
+ *            combining
+ *
+ *            (!IsServer(sptr)) means that, sptr can safely
+ *            taken as defining the target structure of the
+ *            message in this server.
+ *
+ *    *Always* true (if 'parse' and others are working correct):
+ *
+ *    1)      sptr->from == cptr  (note: cptr->from == cptr)
+ *
+ *    2)      MyConnect(sptr) <=> sptr == cptr (e.g. sptr
+ *            *cannot* be a local connection, unless it's
+ *            actually cptr!). [MyConnect(x) should probably
+ *            be defined as (x == x->from) --msa ]
+ *
+ *    parc    number of variable parameter strings (if zero,
+ *            parv is allowed to be NULL)
+ *
+ *    parv    a NULL terminated list of parameter pointers,
+ *
+ *                    parv[0], sender (prefix string), if not present
+ *                            this points to an empty string.
+ *                    parv[1]...parv[parc-1]
+ *                            pointers to additional parameters
+ *                    parv[parc] == NULL, *always*
+ *
+ *            note:   it is guaranteed that parv[0]..parv[parc-1] are all
+ *                    non-NULL pointers.
+ */
+#include "config.h"
+
+#include "client.h"
+#include "ircd_log.h"
+#include "ircd_reply.h"
+#include "ircd_string.h"
+#include "s_user.h"
+
+/* #include <assert.h> -- Now using assert in ircd_log.h */
+
+/*
+ * m_cprivmsg - generic message handler
+ *
+ * parv[0] = sender prefix
+ * parv[1] = nick
+ * parv[2] = #channel
+ * parv[3] = Private message text
+ */
+int m_cprivmsg(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  assert(0 != cptr);
+  assert(cptr == sptr);
+
+  if (parc < 4 || EmptyString(parv[3]))
+    return need_more_params(sptr, "CPRIVMSG");
+
+  return whisper(sptr, parv[1], parv[2], parv[3], 0);
+}
+
+/*
+ * m_cnotice - generic message handler
+ *
+ * parv[0] = sender prefix
+ * parv[1] = nick
+ * parv[2] = #channel
+ * parv[3] = Private message text
+ */
+int m_cnotice(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
+{
+  assert(0 != cptr);
+  assert(cptr == sptr);
+
+  if (parc < 4 || EmptyString(parv[3]))
+    return need_more_params(sptr, "CNOTICE");
+
+  return whisper(sptr, parv[1], parv[2], parv[3], 1);
+}
+
+
diff --git a/ircd/m_create.c b/ircd/m_create.c
new file mode 100644 (file)
index 0000000..4690dfe
--- /dev/null
@@ -0,0 +1,233 @@
+/*
+ * IRC - Internet Relay Chat, ircd/m_create.c
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ *                    University of Oulu, Computing Center
+ *
+ * See file AUTHORS in IRC package for additional names of
+ * the programmers.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id: m_create.c 1744 2007-01-13 18:45:08Z entrope $
+ */
+
+/*
+ * m_functions execute protocol messages on this server:
+ *
+ *    cptr    is always NON-NULL, pointing to a *LOCAL* client
+ *            structure (with an open socket connected!). This
+ *            identifies the physical socket where the message
+ *            originated (or which caused the m_function to be
+ *            executed--some m_functions may call others...).
+ *
+ *    sptr    is the source of the message, defined by the
+ *            prefix part of the message if present. If not
+ *            or prefix not found, then sptr==cptr.
+ *
+ *            (!IsServer(cptr)) => (cptr == sptr), because
+ *            prefixes are taken *only* from servers...
+ *
+ *            (IsServer(cptr))
+ *                    (sptr == cptr) => the message didn't
+ *                    have the prefix.
+ *
+ *                    (sptr != cptr && IsServer(sptr) means
+ *                    the prefix specified servername. (?)
+ *
+ *                    (sptr != cptr && !IsServer(sptr) means
+ *                    that message originated from a remote
+ *                    user (not local).
+ *
+ *            combining
+ *
+ *            (!IsServer(sptr)) means that, sptr can safely
+ *            taken as defining the target structure of the
+ *            message in this server.
+ *
+ *    *Always* true (if 'parse' and others are working correct):
+ *
+ *    1)      sptr->from == cptr  (note: cptr->from == cptr)
+ *
+ *    2)      MyConnect(sptr) <=> sptr == cptr (e.g. sptr
+ *            *cannot* be a local connection, unless it's
+ *            actually cptr!). [MyConnect(x) should probably
+ *            be defined as (x == x->from) --msa ]
+ *
+ *    parc    number of variable parameter strings (if zero,
+ *            parv is allowed to be NULL)
+ *
+ *    parv    a NULL terminated list of parameter pointers,
+ *
+ *                    parv[0], sender (prefix string), if not present
+ *                            this points to an empty string.
+ *                    parv[1]...parv[parc-1]
+ *                            pointers to additional parameters
+ *                    parv[parc] == NULL, *always*
+ *
+ *            note:   it is guaranteed that parv[0]..parv[parc-1] are all
+ *                    non-NULL pointers.
+ */
+#include "config.h"
+
+#include "channel.h"
+#include "client.h"
+#include "hash.h"
+#include "ircd.h"
+#include "ircd_log.h"
+#include "ircd_reply.h"
+#include "ircd_string.h"
+#include "msg.h"
+#include "numeric.h"
+#include "numnicks.h"
+#include "s_debug.h"
+#include "s_misc.h"
+#include "s_user.h"
+#include "send.h"
+
+/* #include <assert.h> -- Now using assert in ircd_log.h */
+#include <stdlib.h>
+#include <string.h>
+
+/*
+ * ms_create - server message handler
+ */
+int ms_create(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  time_t chanTS; /* channel creation time */
+  char *p; /* strtok state */
+  char *name; /* channel name */
+  struct Channel *chptr; /* channel */
+  struct JoinBuf join; /* join and create buffers */
+  struct JoinBuf create;
+  struct ModeBuf mbuf; /* a mode buffer */
+  int badop; /* a flag */
+
+  if (IsServer(sptr))
+    return protocol_violation(sptr,"%s tried to CREATE a channel", cli_name(sptr));
+
+  /* sanity checks: Only accept CREATE messages from servers */
+  if (parc < 3 || *parv[2] == '\0')
+    return need_more_params(sptr,"CREATE");
+
+  chanTS = atoi(parv[2]);
+
+  /* A create that didn't appear during a burst has that servers idea of
+   * the current time.  Use it for lag calculations.
+   */
+  if (!IsBurstOrBurstAck(sptr) && 0 != chanTS)
+    cli_serv(cli_user(sptr)->server)->lag = TStime() - chanTS;
+
+  /* If this server is >1 minute fast, warn */
+  if (TStime() - chanTS<-60)
+  {
+    static time_t rate;
+    sendto_opmask_butone_ratelimited(0, SNO_NETWORK, &rate,
+                                     "Timestamp drift from %C (%is); issuing "
+                                     "SETTIME to correct this",
+                                    cli_user(sptr)->server,
+                                    chanTS - TStime());
+    /* Now issue a SETTIME to resync.  If we're in the wrong, our
+     * (RELIABLE_CLOCK) hub will bounce a SETTIME back to us.
+     */
+    sendcmdto_prio_one(&me, CMD_SETTIME, cli_user(sptr)->server,
+                       "%Tu %C", TStime(), cli_user(sptr)->server);
+  }
+
+  joinbuf_init(&join, sptr, cptr, JOINBUF_TYPE_JOIN, 0, 0);
+  joinbuf_init(&create, sptr, cptr, JOINBUF_TYPE_CREATE, 0, chanTS);
+
+  /* For each channel in the comma separated list: */
+  for (name = ircd_strtok(&p, parv[1], ","); name;
+       name = ircd_strtok(&p, 0, ",")) {
+    badop = 0;
+
+    if (IsLocalChannel(name))
+      continue;
+
+    if ((chptr = FindChannel(name)))
+    {
+      /* Is the remote server confused? */
+      if (find_member_link(chptr, sptr)) {
+        protocol_violation(sptr, "%s tried to CREATE a channel already joined (%s)", cli_name(sptr), chptr->chname);
+        continue;
+      }
+
+      /* Check if we need to bounce a mode */
+      if (TStime() - chanTS > TS_LAG_TIME ||
+         (chptr->creationtime && chanTS > chptr->creationtime &&
+          /* Accept CREATE for zannels. This is only really necessary on a network
+             with servers prior to 2.10.12.02: we just accept their TS and ignore
+             the fact that it was a zannel. The influence of this on a network
+             that is completely 2.10.12.03 or higher is neglectable: Normally
+             a server only sends a CREATE after first sending a DESTRUCT. Thus,
+             by receiving a CREATE for a zannel one of three things happened:
+             1. The DESTRUCT was sent during a net.break; this could mean that
+                our zannel is at the verge of expiring too, it should have been
+                destructed. It is correct to copy the newer TS now, all modes
+                already have been reset, so it will be as if it was destructed
+                and immediately recreated. In order to avoid desyncs of modes,
+                we don't accept a CREATE for channels that have +A set.
+             2. The DESTRUCT passed, then someone created the channel on our
+                side and left it again. In this situation we have a near
+                simultaneous creation on two servers; the person on our side
+                already left within the time span of a message propagation.
+                The channel will therefore be less than 48 hours old and no
+                'protection' is necessary.
+              3. The source server sent the CREATE while linking,
+                 before it got the BURST for our zannel.  If this
+                 happens, we should reset the channel back to the old
+                 timestamp.  This can be distinguished from case #1 by
+                 checking IsBurstOrBurstAck(cli_user(sptr)->server).
+           */
+          !(chptr->users == 0 && !chptr->mode.apass[0]))) {
+        if (!IsBurstOrBurstAck(cli_user(sptr)->server)) {
+          modebuf_init(&mbuf, sptr, cptr, chptr,
+                       (MODEBUF_DEST_SERVER |  /* Send mode to server */
+                        MODEBUF_DEST_HACK2  |  /* Send a HACK(2) message */
+                        MODEBUF_DEST_BOUNCE)); /* And bounce the mode */
+
+          modebuf_mode_client(&mbuf, MODE_ADD | MODE_CHANOP, sptr, MAXOPLEVEL + 1);
+
+          modebuf_flush(&mbuf);
+
+          badop = 1;
+        } else if (chanTS > chptr->creationtime + 4) {
+          /* If their handling of the BURST will lead to deopping the
+           * user, have the user join without getting ops (if the
+           * server's handling of the BURST keeps their ops, the channel
+           * will use our timestamp).
+           */
+          badop = 1;
+        }
+
+        if (badop)
+          joinbuf_join(&join, chptr, 0);
+      }
+    }
+    else /* Channel doesn't exist: create it */
+      chptr = get_channel(sptr, name, CGT_CREATE);
+
+    if (!badop) {
+      /* Set (or correct) our copy of the TS */
+      chptr->creationtime = chanTS;
+      joinbuf_join(&create, chptr, CHFL_CHANOP);
+    }
+  }
+
+  joinbuf_flush(&join); /* flush out the joins and creates */
+  joinbuf_flush(&create);
+
+  return 0;
+}
diff --git a/ircd/m_defaults.c b/ircd/m_defaults.c
new file mode 100644 (file)
index 0000000..41f5397
--- /dev/null
@@ -0,0 +1,121 @@
+/*
+ * IRC - Internet Relay Chat, ircd/m_proto.c
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ *                    University of Oulu, Computing Center
+ *
+ * See file AUTHORS in IRC package for additional names of
+ * the programmers.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id: m_defaults.c 1271 2004-12-11 05:14:07Z klmitch $
+ */
+#include "config.h"
+
+#include "client.h"
+#include "ircd.h"
+#include "ircd_log.h"
+#include "ircd_reply.h"
+#include "numeric.h"
+#include "numnicks.h"
+#include "send.h"
+#include "supported.h"
+#include "version.h"
+
+/* #include <assert.h> -- Now using assert in ircd_log.h */
+
+/*
+ * m_functions execute protocol messages on this server:
+ *
+ *    cptr    is always NON-NULL, pointing to a *LOCAL* client
+ *            structure (with an open socket connected!). This
+ *            identifies the physical socket where the message
+ *            originated (or which caused the m_function to be
+ *            executed--some m_functions may call others...).
+ *
+ *    sptr    is the source of the message, defined by the
+ *            prefix part of the message if present. If not
+ *            or prefix not found, then sptr==cptr.
+ *
+ *            (!IsServer(cptr)) => (cptr == sptr), because
+ *            prefixes are taken *only* from servers...
+ *
+ *            (IsServer(cptr))
+ *                    (sptr == cptr) => the message didn't
+ *                    have the prefix.
+ *
+ *                    (sptr != cptr && IsServer(sptr) means
+ *                    the prefix specified servername. (?)
+ *
+ *                    (sptr != cptr && !IsServer(sptr) means
+ *                    that message originated from a remote
+ *                    user (not local).
+ *
+ *            combining
+ *
+ *            (!IsServer(sptr)) means that, sptr can safely
+ *            taken as defining the target structure of the
+ *            message in this server.
+ *
+ *    *Always* true (if 'parse' and others are working correct):
+ *
+ *    1)      sptr->from == cptr  (note: cptr->from == cptr)
+ *
+ *    2)      MyConnect(sptr) <=> sptr == cptr (e.g. sptr
+ *            *cannot* be a local connection, unless it's
+ *            actually cptr!). [MyConnect(x) should probably
+ *            be defined as (x == x->from) --msa ]
+ *
+ *    parc    number of variable parameter strings (if zero,
+ *            parv is allowed to be NULL)
+ *
+ *    parv    a NULL terminated list of parameter pointers,
+ *
+ *                    parv[0], sender (prefix string), if not present
+ *                            this points to an empty string.
+ *                    parv[1]...parv[parc-1]
+ *                            pointers to additional parameters
+ *                    parv[parc] == NULL, *always*
+ *
+ *            note:   it is guaranteed that parv[0]..parv[parc-1] are all
+ *                    non-NULL pointers.
+ */
+
+int m_not_oper(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  return send_reply(cptr, ERR_NOPRIVILEGES);
+}
+
+int m_unregistered(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  send_reply(cptr, SND_EXPLICIT | ERR_NOTREGISTERED, "%s :Register first.",
+            parv[0]);
+  return 0;
+}
+
+int m_registered(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  return send_reply(sptr, ERR_ALREADYREGISTRED);
+}
+
+int m_ignore(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  return 0;
+}
+
+int m_unsupported(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  return 0;
+}
diff --git a/ircd/m_destruct.c b/ircd/m_destruct.c
new file mode 100644 (file)
index 0000000..0d648cd
--- /dev/null
@@ -0,0 +1,198 @@
+/*
+ * IRC - Internet Relay Chat, ircd/m_destruct.c
+ * Copyright (C) 1997, 2005 Carlo Wood.
+ *
+ * See file AUTHORS in IRC package for additional names of
+ * the programmers.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id: m_destruct.c 1600 2006-01-03 01:25:50Z entrope $
+ */
+
+#include "config.h"
+
+#include "client.h"
+#include "hash.h"
+#include "ircd.h"
+#include "ircd_log.h"
+#include "ircd_reply.h"
+#include "ircd_string.h"
+#include "msg.h"
+#include "numeric.h"
+#include "numnicks.h"
+#include "send.h"
+#include "channel.h"
+#include "destruct_event.h"
+
+/* #include <assert.h> -- Now using assert in ircd_log.h */
+#include <stdlib.h>
+
+/*
+ * ms_destruct - server message handler
+ *
+ * Added 1997 by Run, actually coded and used since 2002.
+ *
+ * parv[0] = sender prefix
+ * parv[1] = channel channelname
+ * parv[2] = channel time stamp
+ *
+ * This message is intended to destruct _empty_ channels.
+ *
+ * The reason it is needed is to somehow add the notion
+ * "I destructed information" to the networks state
+ * (also messages that are still propagating are part
+ *  of the global state).  Without it the network could
+ * easily be desynced as a result of destructing a channel
+ * on only a part of the network while keeping the modes
+ * and creation time on others.
+ * There are three possible ways a DESTRUCT message is
+ * handled by remote servers:
+ * 1) The channel is empty and has the same timestamp
+ *    as on the message.  Conclusion: The channel has
+ *    not been destructed and recreated in the meantime,
+ *    this means that the normal synchronization rules
+ *    account and we react as if we decided to destruct
+ *    the channel ourselves: we destruct the channel and
+ *    send a DESTRUCT in all directions.
+ * 2) The channel is not empty.  In case we cannot remove
+ *    it and do not propagate the DESTRUCT message. Instead
+ *    a resynchronizing BURST message is sent upstream
+ *    in order to restore the channel on that side (which
+ *    will have a TS younger than the current channel if
+ *    it was recreated and will thus be fully synced, just
+ *    like in the case of a real net-junction).
+ * 3) The channel is empty, but the creation time of the
+ *    channel is older than the timestamp on the message.
+ *    This can happen when there is more than one minute
+ *    lag and remotely a channel was created slightly
+ *    after we created the channel, being abandoned again
+ *    and staying empty for a minute without that our
+ *    CREATE reached that remote server.  The remote server
+ *    then could have generated the DESTRUCT.  In the meantime
+ *    our user also left the channel.  We can ignore the
+ *    destruct because it comes from an 'area' that will
+ *    be overridden by our own CREATE: the state that generated
+ *    this DESTRUCT is 'history'.
+ */
+int ms_destruct(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  time_t chanTS;                /* Creation time of the channel */
+  struct Channel* chptr;
+
+  assert(0 != cptr);
+  assert(0 != sptr);
+  assert(IsServer(cptr));
+
+  if (parc < 3 || EmptyString(parv[2]))
+    return need_more_params(sptr,"DESTRUCT");
+
+  chanTS = atoi(parv[2]);
+
+  /* Ignore DESTRUCT messages for non-existing channels. */
+  if (!(chptr = FindChannel(parv[1])))
+    return 0;
+
+  /* Ignore DESTRUCT when the channel is older than the
+     timestamp on the message. */
+  if (chanTS > chptr->creationtime)
+    return 0;
+
+  /* Don't pass on DESTRUCT messages for channels that
+     are not empty, but instead send a BURST msg upstream. */
+  if (chptr->users > 0) {
+#if 0  /* Once all servers are 2.10.12, this can be used too.
+           Until then we have to use CREATE and MODE to
+          get the message accross, because older server do
+          not accept a BURST outside the net.burst. */
+    send_channel_modes(cptr, chptr);
+#else
+  /* This happens when a JOIN and DESTRUCT crossed, ie:
+
+     server1 ----------------- server2
+        DESTRUCT-->   <-- JOIN,MODE
+
+     Where the JOIN and MODE are the result of joining
+     the zannel before it expired on server2, or in the
+     case of simulateous expiration, a DESTRUCT crossing
+     with another DESTRUCT (that will be ignored) and
+     a CREATE of a user joining right after that:
+
+     server1 ----------------- server2
+        DESTRUCT-->   <-- DESTRUCT <-- CREATE
+     
+     in both cases, when the DESTRUCT arrives on
+     server2 we need to send synchronizing messages
+     upstream (to server1).  Since sending two CREATEs
+     or JOINs for the same user after another is a
+     protocol violation, we first have to send PARTs
+     (we can't send a DESTRUCT because 2.10.11 ignores
+     DESTRUCT messages (just passes them on) and has
+     a bug that causes two JOIN's for the same user to
+     result in that user being on the channel twice). */
+
+    struct Membership *member;
+    struct ModeBuf mbuf;
+    struct Ban *link;
+
+    /* Next, send all PARTs upstream. */
+    for (member = chptr->members; member; member = member->next_member)
+      sendcmdto_one(member->user, CMD_PART, cptr, "%H", chptr);
+
+    /* Next, send JOINs for all members. */
+    for (member = chptr->members; member; member = member->next_member)
+      sendcmdto_one(member->user, CMD_JOIN, cptr, "%H", chptr);
+
+    /* Build MODE strings. We use MODEBUF_DEST_BOUNCE with MODE_DEL to assure
+       that the resulting MODEs are only sent upstream. */
+    modebuf_init(&mbuf, sptr, cptr, chptr, MODEBUF_DEST_SERVER | MODEBUF_DEST_BOUNCE);
+
+    /* Op/voice the users as appropriate. We use MODE_DEL because we fake a bounce. */
+    for (member = chptr->members; member; member = member->next_member)
+    {
+      if (IsChanOp(member))
+        modebuf_mode_client(&mbuf, MODE_DEL | MODE_CHANOP, member->user, OpLevel(member));
+      if (HasVoice(member))
+        modebuf_mode_client(&mbuf, MODE_DEL | MODE_VOICE, member->user, MAXOPLEVEL + 1);
+    }
+
+    /* Send other MODEs. */
+    modebuf_mode(&mbuf, MODE_DEL | chptr->mode.mode);
+    if (*chptr->mode.key)
+      modebuf_mode_string(&mbuf, MODE_DEL | MODE_KEY, chptr->mode.key, 0);
+    if (chptr->mode.limit)
+      modebuf_mode_uint(&mbuf, MODE_DEL | MODE_LIMIT, chptr->mode.limit);
+    if (*chptr->mode.upass)
+      modebuf_mode_string(&mbuf, MODE_DEL | MODE_UPASS, chptr->mode.upass, 0);
+    if (*chptr->mode.apass)
+      modebuf_mode_string(&mbuf, MODE_DEL | MODE_APASS, chptr->mode.apass, 0);
+    for (link = chptr->banlist; link; link = link->next)
+      modebuf_mode_string(&mbuf, MODE_DEL | MODE_BAN, link->banstr, 0);
+    modebuf_flush(&mbuf);
+#endif
+
+    return 0;
+  }
+
+  /* Pass on DESTRUCT message and ALSO bounce it back! */
+  sendcmdto_serv_butone(&me, CMD_DESTRUCT, 0, "%s %Tu", parv[1], chanTS);
+
+  /* Remove the empty channel. */
+  if (chptr->destruct_event)
+    remove_destruct_event(chptr);
+  destruct_channel(chptr);
+
+  return 0;
+}
diff --git a/ircd/m_desynch.c b/ircd/m_desynch.c
new file mode 100644 (file)
index 0000000..d1b8d7e
--- /dev/null
@@ -0,0 +1,115 @@
+/*
+ * IRC - Internet Relay Chat, ircd/m_desynch.c
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ *                    University of Oulu, Computing Center
+ *
+ * See file AUTHORS in IRC package for additional names of
+ * the programmers.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id: m_desynch.c 1271 2004-12-11 05:14:07Z klmitch $
+ */
+
+/*
+ * m_functions execute protocol messages on this server:
+ *
+ *    cptr    is always NON-NULL, pointing to a *LOCAL* client
+ *            structure (with an open socket connected!). This
+ *            identifies the physical socket where the message
+ *            originated (or which caused the m_function to be
+ *            executed--some m_functions may call others...).
+ *
+ *    sptr    is the source of the message, defined by the
+ *            prefix part of the message if present. If not
+ *            or prefix not found, then sptr==cptr.
+ *
+ *            (!IsServer(cptr)) => (cptr == sptr), because
+ *            prefixes are taken *only* from servers...
+ *
+ *            (IsServer(cptr))
+ *                    (sptr == cptr) => the message didn't
+ *                    have the prefix.
+ *
+ *                    (sptr != cptr && IsServer(sptr) means
+ *                    the prefix specified servername. (?)
+ *
+ *                    (sptr != cptr && !IsServer(sptr) means
+ *                    that message originated from a remote
+ *                    user (not local).
+ *
+ *            combining
+ *
+ *            (!IsServer(sptr)) means that, sptr can safely
+ *            taken as defining the target structure of the
+ *            message in this server.
+ *
+ *    *Always* true (if 'parse' and others are working correct):
+ *
+ *    1)      sptr->from == cptr  (note: cptr->from == cptr)
+ *
+ *    2)      MyConnect(sptr) <=> sptr == cptr (e.g. sptr
+ *            *cannot* be a local connection, unless it's
+ *            actually cptr!). [MyConnect(x) should probably
+ *            be defined as (x == x->from) --msa ]
+ *
+ *    parc    number of variable parameter strings (if zero,
+ *            parv is allowed to be NULL)
+ *
+ *    parv    a NULL terminated list of parameter pointers,
+ *
+ *                    parv[0], sender (prefix string), if not present
+ *                            this points to an empty string.
+ *                    parv[1]...parv[parc-1]
+ *                            pointers to additional parameters
+ *                    parv[parc] == NULL, *always*
+ *
+ *            note:   it is guaranteed that parv[0]..parv[parc-1] are all
+ *                    non-NULL pointers.
+ */
+#include "config.h"
+
+#include "client.h"
+#include "hash.h"
+#include "ircd.h"
+#include "ircd_log.h"
+#include "ircd_reply.h"
+#include "ircd_string.h"
+#include "msg.h"
+#include "numeric.h"
+#include "numnicks.h"
+#include "s_bsd.h"
+#include "send.h"
+
+/* #include <assert.h> -- Now using assert in ircd_log.h */
+
+/*
+ * ms_desynch - server message handler
+ *
+ * Writes to all +g users; for sending wall type debugging/anti-hack info.
+ * Added 23 Apr 1998  --Run
+ *
+ * parv[0] - sender prefix
+ * parv[parc-1] - message text
+ */
+int ms_desynch(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  if (parc >= 2)
+    sendwallto_group_butone(sptr, WALL_DESYNCH, cptr, "%s", parv[parc - 1]);
+  else
+    need_more_params(sptr,"DESYNCH");                  
+
+  return 0;
+}
diff --git a/ircd/m_die.c b/ircd/m_die.c
new file mode 100644 (file)
index 0000000..4898f24
--- /dev/null
@@ -0,0 +1,129 @@
+/*
+ * IRC - Internet Relay Chat, ircd/m_die.c
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ *                    University of Oulu, Computing Center
+ *
+ * See file AUTHORS in IRC package for additional names of
+ * the programmers.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id: m_die.c 1271 2004-12-11 05:14:07Z klmitch $
+ */
+
+/*
+ * m_functions execute protocol messages on this server:
+ *
+ *    cptr    is always NON-NULL, pointing to a *LOCAL* client
+ *            structure (with an open socket connected!). This
+ *            identifies the physical socket where the message
+ *            originated (or which caused the m_function to be
+ *            executed--some m_functions may call others...).
+ *
+ *    sptr    is the source of the message, defined by the
+ *            prefix part of the message if present. If not
+ *            or prefix not found, then sptr==cptr.
+ *
+ *            (!IsServer(cptr)) => (cptr == sptr), because
+ *            prefixes are taken *only* from servers...
+ *
+ *            (IsServer(cptr))
+ *                    (sptr == cptr) => the message didn't
+ *                    have the prefix.
+ *
+ *                    (sptr != cptr && IsServer(sptr) means
+ *                    the prefix specified servername. (?)
+ *
+ *                    (sptr != cptr && !IsServer(sptr) means
+ *                    that message originated from a remote
+ *                    user (not local).
+ *
+ *            combining
+ *
+ *            (!IsServer(sptr)) means that, sptr can safely
+ *            taken as defining the target structure of the
+ *            message in this server.
+ *
+ *    *Always* true (if 'parse' and others are working correct):
+ *
+ *    1)      sptr->from == cptr  (note: cptr->from == cptr)
+ *
+ *    2)      MyConnect(sptr) <=> sptr == cptr (e.g. sptr
+ *            *cannot* be a local connection, unless it's
+ *            actually cptr!). [MyConnect(x) should probably
+ *            be defined as (x == x->from) --msa ]
+ *
+ *    parc    number of variable parameter strings (if zero,
+ *            parv is allowed to be NULL)
+ *
+ *    parv    a NULL terminated list of parameter pointers,
+ *
+ *                    parv[0], sender (prefix string), if not present
+ *                            this points to an empty string.
+ *                    parv[1]...parv[parc-1]
+ *                            pointers to additional parameters
+ *                    parv[parc] == NULL, *always*
+ *
+ *            note:   it is guaranteed that parv[0]..parv[parc-1] are all
+ *                    non-NULL pointers.
+ */
+#include "config.h"
+
+#include "client.h"
+#include "ircd.h"
+#include "ircd_log.h"
+#include "ircd_reply.h"
+#include "ircd_string.h"
+#include "msg.h"
+#include "numeric.h"
+#include "numnicks.h"
+#include "s_bsd.h"
+#include "send.h"
+
+/* #include <assert.h> -- Now using assert in ircd_log.h */
+
+
+/*
+ * mo_die - oper message handler
+ */
+int mo_die(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  struct Client *acptr;
+  int i;
+
+  if (!HasPriv(sptr, PRIV_DIE))
+    return send_reply(sptr, ERR_NOPRIVILEGES);
+
+    /* parv[0] == sender, parv[1] == servername */
+    if(parc < 2 || ircd_strcmp(parv[1], cli_name(&me))) {
+        sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :To terminate this server, use /die %s", sptr, cli_name(&me));
+        return 0;
+    }
+
+  for (i = 0; i <= HighestFd; i++)
+  {
+    if (!(acptr = LocalClientArray[i]))
+      continue;
+    if (IsUser(acptr))
+      sendcmdto_one(&me, CMD_NOTICE, acptr, "%C :Server Terminating. %s",
+                   acptr, get_client_name(sptr, HIDE_IP));
+    else if (IsServer(acptr))
+      sendcmdto_one(&me, CMD_ERROR, acptr, ":Terminated by %s",
+                   get_client_name(sptr, HIDE_IP));
+  }
+  server_die("received DIE");
+
+  return 0;
+}
diff --git a/ircd/m_endburst.c b/ircd/m_endburst.c
new file mode 100644 (file)
index 0000000..f861c1a
--- /dev/null
@@ -0,0 +1,160 @@
+/*
+ * IRC - Internet Relay Chat, ircd/m_end_of_burst.c
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ *                    University of Oulu, Computing Center
+ *
+ * See file AUTHORS in IRC package for additional names of
+ * the programmers.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id: m_endburst.c 1411 2005-05-30 13:14:54Z entrope $
+ */
+
+/*
+ * m_functions execute protocol messages on this server:
+ *
+ *    cptr    is always NON-NULL, pointing to a *LOCAL* client
+ *            structure (with an open socket connected!). This
+ *            identifies the physical socket where the message
+ *            originated (or which caused the m_function to be
+ *            executed--some m_functions may call others...).
+ *
+ *    sptr    is the source of the message, defined by the
+ *            prefix part of the message if present. If not
+ *            or prefix not found, then sptr==cptr.
+ *
+ *            (!IsServer(cptr)) => (cptr == sptr), because
+ *            prefixes are taken *only* from servers...
+ *
+ *            (IsServer(cptr))
+ *                    (sptr == cptr) => the message didn't
+ *                    have the prefix.
+ *
+ *                    (sptr != cptr && IsServer(sptr) means
+ *                    the prefix specified servername. (?)
+ *
+ *                    (sptr != cptr && !IsServer(sptr) means
+ *                    that message originated from a remote
+ *                    user (not local).
+ *
+ *            combining
+ *
+ *            (!IsServer(sptr)) means that, sptr can safely
+ *            taken as defining the target structure of the
+ *            message in this server.
+ *
+ *    *Always* true (if 'parse' and others are working correct):
+ *
+ *    1)      sptr->from == cptr  (note: cptr->from == cptr)
+ *
+ *    2)      MyConnect(sptr) <=> sptr == cptr (e.g. sptr
+ *            *cannot* be a local connection, unless it's
+ *            actually cptr!). [MyConnect(x) should probably
+ *            be defined as (x == x->from) --msa ]
+ *
+ *    parc    number of variable parameter strings (if zero,
+ *            parv is allowed to be NULL)
+ *
+ *    parv    a NULL terminated list of parameter pointers,
+ *
+ *                    parv[0], sender (prefix string), if not present
+ *                            this points to an empty string.
+ *                    parv[1]...parv[parc-1]
+ *                            pointers to additional parameters
+ *                    parv[parc] == NULL, *always*
+ *
+ *            note:   it is guaranteed that parv[0]..parv[parc-1] are all
+ *                    non-NULL pointers.
+ */
+#include "config.h"
+
+#include "channel.h"
+#include "client.h"
+#include "hash.h"
+#include "ircd.h"
+#include "ircd_log.h"
+#include "ircd_reply.h"
+#include "ircd_string.h"
+#include "msg.h"
+#include "numeric.h"
+#include "numnicks.h"
+#include "send.h"
+
+/* #include <assert.h> -- Now using assert in ircd_log.h */
+
+/*
+ * ms_end_of_burst - server message handler
+ * - Added Xorath 6-14-96, rewritten by Run 24-7-96
+ * - and fixed by record and Kev 8/1/96
+ * - and really fixed by Run 15/8/96 :p
+ * This the last message in a net.burst.
+ * It clears a flag for the server sending the burst.
+ *
+ * As of 10.11, to fix a bug in the way BURST is processed, it also
+ * makes sure empty channels are deleted
+ *
+ * parv[0] - sender prefix
+ */
+int ms_end_of_burst(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  struct Channel *chan, *next_chan;
+
+  assert(0 != cptr);
+  assert(0 != sptr);
+
+  sendto_opmask_butone(0, SNO_NETWORK, "Completed net.burst from %C.", 
+       sptr);
+  sendcmdto_serv_butone(sptr, CMD_END_OF_BURST, cptr, "");
+  ClearBurst(sptr);
+  SetBurstAck(sptr);
+  if (MyConnect(sptr))
+    sendcmdto_one(&me, CMD_END_OF_BURST_ACK, sptr, "");
+
+  /* Count through channels... */
+  for (chan = GlobalChannelList; chan; chan = next_chan) {
+    next_chan = chan->next;
+    if (!chan->members && (chan->mode.mode & MODE_BURSTADDED)) {
+      /* sub1_from_channel checks for MODE_PERSIST so let it check */
+      /* Newly empty channel, schedule it for removal. */
+      chan->mode.mode &= ~MODE_BURSTADDED;
+      sub1_from_channel(chan);
+   } else
+      chan->mode.mode &= ~MODE_BURSTADDED;
+  }
+
+  return 0;
+}
+
+/*
+ * ms_end_of_burst_ack - server message handler
+ *
+ * This the acknowledge message of the `END_OF_BURST' message.
+ * It clears a flag for the server receiving the burst.
+ *
+ * parv[0] - sender prefix
+ */
+int ms_end_of_burst_ack(struct Client *cptr, struct Client *sptr, int parc, char **parv)
+{
+  if (!IsServer(sptr))
+    return 0;
+
+  sendto_opmask_butone(0, SNO_NETWORK, "%C acknowledged end of net.burst.",
+                      sptr);
+  sendcmdto_serv_butone(sptr, CMD_END_OF_BURST_ACK, cptr, "");
+  ClearBurstAck(sptr);
+
+  return 0;
+}
diff --git a/ircd/m_error.c b/ircd/m_error.c
new file mode 100644 (file)
index 0000000..35dcb63
--- /dev/null
@@ -0,0 +1,159 @@
+/*
+ * IRC - Internet Relay Chat, ircd/m_error.c
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ *                    University of Oulu, Computing Center
+ *
+ * See file AUTHORS in IRC package for additional names of
+ * the programmers.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id: m_error.c 1271 2004-12-11 05:14:07Z klmitch $
+ */
+
+/*
+ * m_functions execute protocol messages on this server:
+ *
+ *    cptr    is always NON-NULL, pointing to a *LOCAL* client
+ *            structure (with an open socket connected!). This
+ *            identifies the physical socket where the message
+ *            originated (or which caused the m_function to be
+ *            executed--some m_functions may call others...).
+ *
+ *    sptr    is the source of the message, defined by the
+ *            prefix part of the message if present. If not
+ *            or prefix not found, then sptr==cptr.
+ *
+ *            (!IsServer(cptr)) => (cptr == sptr), because
+ *            prefixes are taken *only* from servers...
+ *
+ *            (IsServer(cptr))
+ *                    (sptr == cptr) => the message didn't
+ *                    have the prefix.
+ *
+ *                    (sptr != cptr && IsServer(sptr) means
+ *                    the prefix specified servername. (?)
+ *
+ *                    (sptr != cptr && !IsServer(sptr) means
+ *                    that message originated from a remote
+ *                    user (not local).
+ *
+ *            combining
+ *
+ *            (!IsServer(sptr)) means that, sptr can safely
+ *            taken as defining the target structure of the
+ *            message in this server.
+ *
+ *    *Always* true (if 'parse' and others are working correct):
+ *
+ *    1)      sptr->from == cptr  (note: cptr->from == cptr)
+ *
+ *    2)      MyConnect(sptr) <=> sptr == cptr (e.g. sptr
+ *            *cannot* be a local connection, unless it's
+ *            actually cptr!). [MyConnect(x) should probably
+ *            be defined as (x == x->from) --msa ]
+ *
+ *    parc    number of variable parameter strings (if zero,
+ *            parv is allowed to be NULL)
+ *
+ *    parv    a NULL terminated list of parameter pointers,
+ *
+ *                    parv[0], sender (prefix string), if not present
+ *                            this points to an empty string.
+ *                    parv[1]...parv[parc-1]
+ *                            pointers to additional parameters
+ *                    parv[parc] == NULL, *always*
+ *
+ *            note:   it is guaranteed that parv[0]..parv[parc-1] are all
+ *                    non-NULL pointers.
+ */
+#include "config.h"
+
+#include "client.h"
+#include "hash.h"
+#include "ircd.h"
+#include "ircd_alloc.h"
+#include "ircd_log.h"
+#include "ircd_reply.h"
+#include "ircd_string.h"
+#include "numeric.h"
+#include "numnicks.h"
+#include "s_debug.h"
+#include "s_misc.h"
+#include "send.h"
+
+/* #include <assert.h> -- Now using assert in ircd_log.h */
+#include <string.h>
+
+/*
+ * mr_error - unregistered client message handler
+ *
+ * parv[0] = sender prefix
+ * parv[parc-1] = text
+ */
+int mr_error(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  const char *para;
+
+  if (!IsHandshake(cptr) && !IsConnecting(cptr))
+    return 0; /* ignore ERROR from regular clients */
+
+  para = (parc > 1 && *parv[parc - 1] != '\0') ? parv[parc - 1] : "<>";
+
+  Debug((DEBUG_ERROR, "Received ERROR message from %s: %s", cli_name(sptr), para));
+
+  if (cptr == sptr)
+    sendto_opmask_butone(0, SNO_OLDSNO, "ERROR :from %C -- %s", cptr, para);
+  else
+    sendto_opmask_butone(0, SNO_OLDSNO, "ERROR :from %C via %C -- %s", sptr,
+                        cptr, para);
+
+  if (cli_serv(sptr))
+  {
+    MyFree(cli_serv(sptr)->last_error_msg);
+    DupString(cli_serv(sptr)->last_error_msg, para);
+  }
+
+  return 0;
+}
+
+/*
+ * ms_error - server message handler
+ *
+ * parv[0] = sender prefix
+ * parv[parc-1] = text
+ */
+int ms_error(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  const char *para;
+
+  para = (parc > 1 && *parv[parc - 1] != '\0') ? parv[parc - 1] : "<>";
+
+  Debug((DEBUG_ERROR, "Received ERROR message from %s: %s", cli_name(sptr), para));
+
+  if (cptr == sptr)
+    sendto_opmask_butone(0, SNO_OLDSNO, "ERROR :from %C -- %s", cptr, para);
+  else
+    sendto_opmask_butone(0, SNO_OLDSNO, "ERROR :from %C via %C -- %s", sptr,
+                        cptr, para);
+
+  if (cli_serv(sptr))
+  {
+    MyFree(cli_serv(sptr)->last_error_msg);
+    DupString(cli_serv(sptr)->last_error_msg, para);
+  }
+
+  return 0;
+}
diff --git a/ircd/m_fakehost.c b/ircd/m_fakehost.c
new file mode 100644 (file)
index 0000000..7dd31fd
--- /dev/null
@@ -0,0 +1,300 @@
+/*
+ * IRC - Internet Relay Chat, ircd/m_fakehost.c
+ * Copyright (C) 2004 Zoot <zoot@gamesurge.net>
+ *
+ * See file AUTHORS in IRC package for additional names of
+ * the programmers.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ */
+
+/*
+ * m_functions execute protocol messages on this server:
+ *
+ *    cptr    is always NON-NULL, pointing to a *LOCAL* client
+ *            structure (with an open socket connected!). This
+ *            identifies the physical socket where the message
+ *            originated (or which caused the m_function to be
+ *            executed--some m_functions may call others...).
+ *
+ *    sptr    is the source of the message, defined by the
+ *            prefix part of the message if present. If not
+ *            or prefix not found, then sptr==cptr.
+ *
+ *            (!IsServer(cptr)) => (cptr == sptr), because
+ *            prefixes are taken *only* from servers...
+ *
+ *            (IsServer(cptr))
+ *                    (sptr == cptr) => the message didn't
+ *                    have the prefix.
+ *
+ *                    (sptr != cptr && IsServer(sptr) means
+ *                    the prefix specified servername. (?)
+ *
+ *                    (sptr != cptr && !IsServer(sptr) means
+ *                    that message originated from a remote
+ *                    user (not local).
+ *
+ *            combining
+ *
+ *            (!IsServer(sptr)) means that, sptr can safely
+ *            taken as defining the target structure of the
+ *            message in this server.
+ *
+ *    *Always* true (if 'parse' and others are working correct):
+ *
+ *    1)      sptr->from == cptr  (note: cptr->from == cptr)
+*
+ *    2)      MyConnect(sptr) <=> sptr == cptr (e.g. sptr
+ *            *cannot* be a local connection, unless it's
+ *            actually cptr!). [MyConnect(x) should probably
+ *            be defined as (x == x->from) --msa ]
+ *
+ *    parc    number of variable parameter strings (if zero,
+ *            parv is allowed to be NULL)
+ *
+ *    parv    a NULL terminated list of parameter pointers,
+ *
+ *                    parv[0], sender (prefix string), if not present
+ *                            this points to an empty string.
+ *                    parv[1]...parv[parc-1]
+ *                            pointers to additional parameters
+ *                    parv[parc] == NULL, *always*
+ *
+ *            note:   it is guaranteed that parv[0]..parv[parc-1] are all
+ *                    non-NULL pointers.
+ */
+#include "config.h"
+
+#include "client.h"
+#include "hash.h"
+#include "ircd.h"
+#include "ircd_reply.h"
+#include "ircd_string.h"
+#include "msg.h"
+#include "numeric.h"
+#include "numnicks.h"
+#include "s_bsd.h"
+#include "s_conf.h"
+#include "s_user.h"
+#include "send.h"
+
+/*
+ * m_fakehost - fakehost user message handler
+ *
+ * parv[0] = sender prefix
+ * parv[1] = new fake host
+ */
+int m_fakehost(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+struct Client *acptr,*another;
+int i;
+  if (!IsNetServ(sptr) || !HasFlag(sptr, FLAG_SECURITY_SERV))
+    return send_reply(sptr, ERR_NOPRIVILEGES);
+
+  if (parc < 2)
+    return need_more_params(sptr, "FAKEHOST");
+  if (parc < 3)
+  {
+
+  /* Assign and propagate the fakehost */
+  ircd_strncpy(cli_user(cptr)->fakehost, parv[1], HOSTLEN);
+  hide_hostmask(cptr, FLAG_FAKEHOST);
+  
+       /*for(i = HighestFd; i >= 0; i--) {
+        if((another = LocalClientArray[i]) && IsServer(another)) {
+            sendcmdto_one(cptr, CMD_MODE, another, "%s +f :%s", cli_name(cptr), parv[2]);
+        }
+    }*/
+       sendcmdto_serv_butone(sptr, CMD_FAKEHOST_OLD, cptr, "%C %s", cptr,cli_user(cptr)->fakehost);
+  
+  return 0;
+  }
+  else
+  {
+
+    acptr = FindUser(parv[1]);
+    if (!acptr)
+    {
+      send_reply(sptr, ERR_NOSUCHCHANNEL, parv[1]);
+      return 0;
+    }
+
+  /* Assign and propagate the fakehost */
+  ircd_strncpy(cli_user(acptr)->fakehost, parv[2], HOSTLEN);
+  hide_hostmask(acptr, FLAG_FAKEHOST);
+       /*
+       for(i = HighestFd; i >= 0; i--) {
+        if((another = LocalClientArray[i]) && IsServer(another)) {
+            sendcmdto_one(acptr, CMD_MODE, another, "%s +f :%s", cli_name(acptr), parv[2]);
+        }
+    }
+  */
+   sendcmdto_serv_butone(sptr, CMD_FAKEHOST_OLD, cptr, "%C %s", acptr,
+                          cli_user(acptr)->fakehost);
+  return 0;
+  }
+}
+
+/*
+ * IRC - Internet Relay Chat, ircd/m_fakehost.c
+ * Written by David Herrmann.
+ */
+
+/*
+ * m_functions execute protocol messages on this server:
+ *
+ *    cptr    is always NON-NULL, pointing to a *LOCAL* client
+ *            structure (with an open socket connected!). This
+ *            identifies the physical socket where the message
+ *            originated (or which caused the m_function to be
+ *            executed--some m_functions may call others...).
+ *
+ *    sptr    is the source of the message, defined by the
+ *            prefix part of the message if present. If not
+ *            or prefix not found, then sptr==cptr.
+ *
+ *            (!IsServer(cptr)) => (cptr == sptr), because
+ *            prefixes are taken *only* from servers...
+ *
+ *            (IsServer(cptr))
+ *                    (sptr == cptr) => the message didn't
+ *                    have the prefix.
+ *
+ *                    (sptr != cptr && IsServer(sptr) means
+ *                    the prefix specified servername. (?)
+ *
+ *                    (sptr != cptr && !IsServer(sptr) means
+ *                    that message originated from a remote
+ *                    user (not local).
+ *
+ *            combining
+ *
+ *            (!IsServer(sptr)) means that, sptr can safely
+ *            taken as defining the target structure of the
+ *            message in this server.
+ *
+ *    *Always* true (if 'parse' and others are working correct):
+ *
+ *    1)      sptr->from == cptr  (note: cptr->from == cptr)
+ *
+ *    2)      MyConnect(sptr) <=> sptr == cptr (e.g. sptr
+ *            *cannot* be a local connection, unless it's
+ *            actually cptr!). [MyConnect(x) should probably
+ *            be defined as (x == x->from) --msa ]
+ *
+ *    parc    number of variable parameter strings (if zero,
+ *            parv is allowed to be NULL)
+ *
+ *    parv    a NULL terminated list of parameter pointers,
+ *
+ *                    parv[0], sender (prefix string), if not present
+ *                            this points to an empty string.
+ *                    parv[1]...parv[parc-1]
+ *                            pointers to additional parameters
+ *                    parv[parc] == NULL, *always*
+ *
+ *            note:   it is guaranteed that parv[0]..parv[parc-1] are all
+ *                    non-NULL pointers.
+ */
+
+
+/* ms_fakehost - fakehost server message handler
+ *
+ * parv[0] = sender prefix
+ * parv[1] = target user numeric
+ * parv[2] = target user's new fake host
+ */
+/** Remote fakehost
+ * Allows servers to force a fakehost on remote users.
+ *
+ * The FAKEHOST request can be generated by EVERY server. It is forwarded to the server
+ * of the user which then sets the fakehost and broadcasts the new fakehost.
+ */
+int ms_fakehost(struct Client *cptr, struct Client *sptr, int parc, char *parv[]) {
+    struct Client *target, *acptr;
+    int i;
+
+    if(parc < 3) {
+        return need_more_params(sptr, "FAKEHOST");
+    }
+
+    if(!(target = findNUser(parv[1]))) {
+        /* Silently ignore FAKEHOSTs for disconnected users. */
+        return 0;
+    }
+
+    /* Ignore the assignment if it changes nothing. */
+    if(IsFakeHost(target) && strcmp(cli_user(target)->fakehost, parv[2]) == 0) {
+        return 0;
+    }
+
+    /* If the user is no local user, we forward the message to the user's server. */
+    if(!MyConnect(target)) {
+        sendcmdto_one(sptr, CMD_FAKEHOST, cli_user(target)->server, "%C %s", target, parv[2]);
+        return 0;
+    }
+
+    /* Set fakehost and propagate the changed host. */
+    ircd_strncpy(cli_user(target)->fakehost, parv[2], HOSTLEN);
+    hide_hostmask(target, FLAG_FAKEHOST);
+
+    /* Borrowed from send_umode_out().
+     * I found no better way to do this. However, maybe someone has the time to check out
+     * s_user.c to change this.
+     */
+    for(i = HighestFd; i >= 0; i--) {
+        if((acptr = LocalClientArray[i]) && IsServer(acptr)) {
+            sendcmdto_one(target, CMD_MODE, acptr, "%s +f :%s", cli_name(target), parv[2]);
+        }
+    }
+
+    return 0;
+}
+
+/*
+ * ms_fakehost_old - old fakehost server message handler
+ *
+ * parv[0] = sender prefix
+ * parv[1] = target user numeric
+ * parv[2] = target user's new fake host
+ */
+int ms_fakehost_old(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) {
+    struct Client *target;
+
+    if(parc < 3)
+        return need_more_params(sptr, "FAKE");
+
+    /* Locate our target user; ignore the message if we can't */
+    if(!(target = findNUser(parv[1])))
+        return 0;
+
+    /* Ignore the assignment if it changes nothing */
+    if(IsFakeHost(target) && strcmp(cli_user(target)->fakehost, parv[2]) == 0) {
+        return 0;
+    }
+
+    /* Assign and propagate the fakehost */
+    ircd_strncpy(cli_user(target)->fakehost, parv[2], HOSTLEN);
+    hide_hostmask(target, FLAG_FAKEHOST);
+
+    sendcmdto_serv_butone(sptr, CMD_FAKEHOST_OLD, cptr, "%C %s", target,
+                          cli_user(target)->fakehost);
+    return 0;
+}
+
diff --git a/ircd/m_get.c b/ircd/m_get.c
new file mode 100644 (file)
index 0000000..86f5082
--- /dev/null
@@ -0,0 +1,103 @@
+/*
+ * IRC - Internet Relay Chat, ircd/m_get.c
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ *                    University of Oulu, Computing Center
+ *
+ * See file AUTHORS in IRC package for additional names of
+ * the programmers.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id: m_get.c 1271 2004-12-11 05:14:07Z klmitch $
+ */
+
+/*
+ * m_functions execute protocol messages on this server:
+ *
+ *    cptr    is always NON-NULL, pointing to a *LOCAL* client
+ *            structure (with an open socket connected!). This
+ *            identifies the physical socket where the message
+ *            originated (or which caused the m_function to be
+ *            executed--some m_functions may call others...).
+ *
+ *    sptr    is the source of the message, defined by the
+ *            prefix part of the message if present. If not
+ *            or prefix not found, then sptr==cptr.
+ *
+ *            (!IsServer(cptr)) => (cptr == sptr), because
+ *            prefixes are taken *only* from servers...
+ *
+ *            (IsServer(cptr))
+ *                    (sptr == cptr) => the message didn't
+ *                    have the prefix.
+ *
+ *                    (sptr != cptr && IsServer(sptr) means
+ *                    the prefix specified servername. (?)
+ *
+ *                    (sptr != cptr && !IsServer(sptr) means
+ *                    that message originated from a remote
+ *                    user (not local).
+ *
+ *            combining
+ *
+ *            (!IsServer(sptr)) means that, sptr can safely
+ *            taken as defining the target structure of the
+ *            message in this server.
+ *
+ *    *Always* true (if 'parse' and others are working correct):
+ *
+ *    1)      sptr->from == cptr  (note: cptr->from == cptr)
+ *
+ *    2)      MyConnect(sptr) <=> sptr == cptr (e.g. sptr
+ *            *cannot* be a local connection, unless it's
+ *            actually cptr!). [MyConnect(x) should probably
+ *            be defined as (x == x->from) --msa ]
+ *
+ *    parc    number of variable parameter strings (if zero,
+ *            parv is allowed to be NULL)
+ *
+ *    parv    a NULL terminated list of parameter pointers,
+ *
+ *                    parv[0], sender (prefix string), if not present
+ *                            this points to an empty string.
+ *                    parv[1]...parv[parc-1]
+ *                            pointers to additional parameters
+ *                    parv[parc] == NULL, *always*
+ *
+ *            note:   it is guaranteed that parv[0]..parv[parc-1] are all
+ *                    non-NULL pointers.
+ */
+#include "config.h"
+
+#include "client.h"
+#include "hash.h"
+#include "ircd.h"
+#include "ircd_features.h"
+#include "ircd_log.h"
+#include "ircd_reply.h"
+#include "ircd_string.h"
+#include "numeric.h"
+#include "numnicks.h"
+#include "send.h"
+
+/* #include <assert.h> -- Now using assert in ircd_log.h */
+
+/*
+ * mo_get - oper message handler
+ */
+int mo_get(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  return feature_get(sptr, (const char* const*)parv + 1, parc - 1);
+}
diff --git a/ircd/m_gline.c b/ircd/m_gline.c
new file mode 100644 (file)
index 0000000..5682347
--- /dev/null
@@ -0,0 +1,652 @@
+/*
+ * IRC - Internet Relay Chat, ircd/m_gline.c
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ *                    University of Oulu, Computing Center
+ *
+ * See file AUTHORS in IRC package for additional names of
+ * the programmers.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id: m_gline.c 1904 2009-02-09 00:03:34Z entrope $
+ */
+
+/*
+ * m_functions execute protocol messages on this server:
+ *
+ *    cptr    is always NON-NULL, pointing to a *LOCAL* client
+ *            structure (with an open socket connected!). This
+ *            identifies the physical socket where the message
+ *            originated (or which caused the m_function to be
+ *            executed--some m_functions may call others...).
+ *
+ *    sptr    is the source of the message, defined by the
+ *            prefix part of the message if present. If not
+ *            or prefix not found, then sptr==cptr.
+ *
+ *            (!IsServer(cptr)) => (cptr == sptr), because
+ *            prefixes are taken *only* from servers...
+ *
+ *            (IsServer(cptr))
+ *                    (sptr == cptr) => the message didn't
+ *                    have the prefix.
+ *
+ *                    (sptr != cptr && IsServer(sptr) means
+ *                    the prefix specified servername. (?)
+ *
+ *                    (sptr != cptr && !IsServer(sptr) means
+ *                    that message originated from a remote
+ *                    user (not local).
+ *
+ *            combining
+ *
+ *            (!IsServer(sptr)) means that, sptr can safely
+ *            taken as defining the target structure of the
+ *            message in this server.
+ *
+ *    *Always* true (if 'parse' and others are working correct):
+ *
+ *    1)      sptr->from == cptr  (note: cptr->from == cptr)
+ *
+ *    2)      MyConnect(sptr) <=> sptr == cptr (e.g. sptr
+ *            *cannot* be a local connection, unless it's
+ *            actually cptr!). [MyConnect(x) should probably
+ *            be defined as (x == x->from) --msa ]
+ *
+ *    parc    number of variable parameter strings (if zero,
+ *            parv is allowed to be NULL)
+ *
+ *    parv    a NULL terminated list of parameter pointers,
+ *
+ *                    parv[0], sender (prefix string), if not present
+ *                            this points to an empty string.
+ *                    parv[1]...parv[parc-1]
+ *                            pointers to additional parameters
+ *                    parv[parc] == NULL, *always*
+ *
+ *            note:   it is guaranteed that parv[0]..parv[parc-1] are all
+ *                    non-NULL pointers.
+ */
+#include "config.h"
+
+#include "client.h"
+#include "gline.h"
+#include "hash.h"
+#include "ircd.h"
+#include "ircd_features.h"
+#include "ircd_log.h"
+#include "ircd_reply.h"
+#include "ircd_string.h"
+#include "match.h"
+#include "msg.h"
+#include "numeric.h"
+#include "numnicks.h"
+#include "s_conf.h"
+#include "s_debug.h"
+#include "s_misc.h"
+#include "send.h"
+
+/* #include <assert.h> -- Now using assert in ircd_log.h */
+#include <stdlib.h>
+#include <string.h>
+
+#define PASTWATCH      157680000       /* number of seconds in 5 years */
+
+/*
+ * If the expiration value, interpreted as an absolute timestamp, is
+ * more recent than 5 years in the past, we interpret it as an
+ * absolute timestamp; otherwise, we assume it's relative and convert
+ * it to an absolute timestamp.  Either way, the output of this macro
+ * is an absolute timestamp--not guaranteed to be a *valid* timestamp,
+ * but you can't have everything in a macro ;)
+ */
+#define abs_expire(exp)                                                        \
+  ((exp) >= CurrentTime - PASTWATCH ? (exp) : (exp) + CurrentTime)
+
+/*
+ * ms_gline - server message handler
+ *
+ * parv[0] = Sender prefix
+ * parv[1] = Target: server numeric
+ * parv[2] = (+|-)<G-line mask>
+ *
+ * For other parameters, see doc/readme.gline.
+ */
+int
+ms_gline(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
+{
+  struct Client *acptr = 0;
+  struct Gline *agline = 0;
+  unsigned int flags = 0;
+  enum GlineAction action = GLINE_MODIFY;
+  time_t expire = 0, lastmod = 0, lifetime = 0;
+  char *mask = parv[2], *target = parv[1], *reason = "No reason", *tmp = 0;
+
+  if (parc < 3)
+    return need_more_params(sptr, "GLINE");
+
+  if (IsServer(sptr))
+    flags |= GLINE_FORCE;
+
+  if (*mask == '!') {
+    mask++;
+    flags |= GLINE_OPERFORCE; /* assume oper had WIDE_GLINE */
+  }
+
+  switch (*mask) { /* handle +, -, <, and > */
+  case '+': /* activate the G-line */
+    action = GLINE_ACTIVATE;
+    mask++;
+    break;
+
+  case '-': /* deactivate the G-line */
+    action = GLINE_DEACTIVATE;
+    mask++;
+    break;
+
+  case '>': /* locally activate the G-line */
+    action = GLINE_LOCAL_ACTIVATE;
+    mask++;
+    break;
+
+  case '<': /* locally deactivate the G-line */
+    action = GLINE_LOCAL_DEACTIVATE;
+    mask++;
+    break;
+  }
+
+  /* Now, let's figure out if it's a local or global G-line */
+  if (action == GLINE_LOCAL_ACTIVATE || action == GLINE_LOCAL_DEACTIVATE ||
+      (target[0] == '*' && target[1] == '\0'))
+    flags |= GLINE_GLOBAL;
+  else
+    flags |= GLINE_LOCAL;
+
+  /* now figure out if we need to resolve a server */
+  if ((action == GLINE_LOCAL_ACTIVATE || action == GLINE_LOCAL_DEACTIVATE ||
+       (flags & GLINE_LOCAL)) && !(acptr = FindNServer(target)))
+    return 0; /* no such server, jump out */
+
+  /* If it's a local activate/deactivate and server isn't me, propagate it */
+  if ((action == GLINE_LOCAL_ACTIVATE || action == GLINE_LOCAL_DEACTIVATE) &&
+      !IsMe(acptr)) {
+    Debug((DEBUG_DEBUG, "I am forwarding a local change to a global gline "
+          "to a remote server; target %s, mask %s, operforce %s, action %c",
+          target, mask, flags & GLINE_OPERFORCE ? "YES" : "NO",
+          action == GLINE_LOCAL_ACTIVATE ? '>' : '<'));
+
+    sendcmdto_one(sptr, CMD_GLINE, acptr, "%C %s%c%s", acptr,
+                 flags & GLINE_OPERFORCE ? "!" : "",
+                 action == GLINE_LOCAL_ACTIVATE ? '>' : '<', mask);
+
+    return 0; /* all done */
+  }
+
+  /* Next, try to find the G-line... */
+  if ((flags & GLINE_GLOBAL) || IsMe(acptr)) /* don't bother if it's not me! */
+    agline = gline_find(mask, flags | GLINE_ANY | GLINE_EXACT);
+
+  /* We now have all the pieces to tell us what we've got; let's put
+   * it all together and convert the rest of the arguments.
+   */
+
+  /* Handle the local G-lines first... */
+  if (flags & GLINE_LOCAL) {
+    assert(acptr);
+
+    /* normalize the action, first */
+    if (action == GLINE_LOCAL_ACTIVATE || action == GLINE_MODIFY)
+      action = GLINE_ACTIVATE;
+    else if (action == GLINE_LOCAL_DEACTIVATE)
+      action = GLINE_DEACTIVATE;
+
+    if (action == GLINE_ACTIVATE) { /* get expiration and reason */
+      if (parc < 5) /* check parameter count... */
+       return need_more_params(sptr, "GLINE");
+
+      expire = atoi(parv[3]); /* get expiration... */
+      expire = abs_expire(expire); /* convert to absolute... */
+      reason = parv[parc - 1]; /* and reason */
+
+      if (IsMe(acptr)) {
+       if (agline) /* G-line already exists, so let's ignore it... */
+         return 0;
+
+       /* OK, create the local G-line */
+       Debug((DEBUG_DEBUG, "I am creating a local G-line here; target %s, "
+              "mask %s, operforce %s, action %s, expire %Tu, reason: %s",
+              target, mask, flags & GLINE_OPERFORCE ? "YES" : "NO",
+              action == GLINE_ACTIVATE ? "+" : "-", expire, reason));
+
+       return gline_add(cptr, sptr, mask, reason, expire, lastmod,
+                        lifetime, flags | GLINE_ACTIVE);
+      }
+    } else if (IsMe(acptr)) { /* destroying a local G-line */
+      if (!agline) /* G-line doesn't exist, so let's complain... */
+       return send_reply(sptr, ERR_NOSUCHGLINE, mask);
+
+      /* Let's now destroy the G-line */;
+      Debug((DEBUG_DEBUG, "I am destroying a local G-line here; target %s, "
+            "mask %s, operforce %s, action %s", target, mask,
+            flags & GLINE_OPERFORCE ? "YES" : "NO",
+            action == GLINE_ACTIVATE ? "+" : "-"));
+
+      return gline_destroy(cptr, sptr, agline);
+    }
+
+    /* OK, we've converted arguments; if it's not for us, forward */
+    /* UPDATE NOTE: Once all servers are updated to u2.10.12.11, the
+     * format string in this sendcmdto_one() may be updated to omit
+     * <lastmod> for GLINE_ACTIVATE and to omit <expire>, <lastmod>,
+     * and <reason> for GLINE_DEACTIVATE.
+     */
+    assert(!IsMe(acptr));
+
+    Debug((DEBUG_DEBUG, "I am forwarding a local G-line to a remote server; "
+          "target %s, mask %s, operforce %s, action %c, expire %Tu, "
+          "lastmod %Tu, reason: %s", target, mask,
+          flags & GLINE_OPERFORCE ? "YES" : "NO",
+          action == GLINE_ACTIVATE ? '+' :  '-', expire, CurrentTime,
+          reason));
+
+    sendcmdto_one(sptr, CMD_GLINE, acptr, "%C %s%c%s %Tu %Tu :%s",
+                 acptr, flags & GLINE_OPERFORCE ? "!" : "",
+                 action == GLINE_ACTIVATE ? '+' : '-', mask,
+                 expire - CurrentTime, CurrentTime, reason);
+
+    return 0; /* all done */
+  }
+
+  /* can't modify a G-line that doesn't exist, so remap to activate */
+  if (!agline && action == GLINE_MODIFY)
+    action = GLINE_ACTIVATE;
+
+  /* OK, let's figure out what other parameters we may have... */
+  switch (action) {
+  case GLINE_LOCAL_ACTIVATE: /* locally activating a G-line */
+  case GLINE_LOCAL_DEACTIVATE: /* locally deactivating a G-line */
+    if (!agline) /* no G-line to locally activate or deactivate? */
+      return send_reply(sptr, ERR_NOSUCHGLINE, mask);
+    lastmod = agline->gl_lastmod;
+    break; /* no additional parameters to manipulate */
+
+  case GLINE_ACTIVATE: /* activating a G-line */
+  case GLINE_DEACTIVATE: /* deactivating a G-line */
+    /* in either of these cases, we have at least a lastmod parameter */
+    if (parc < 4)
+      return need_more_params(sptr, "GLINE");
+    else if (parc == 4) /* lastmod only form... */
+      lastmod = atoi(parv[3]);
+    /*FALLTHROUGH*/
+  case GLINE_MODIFY: /* modifying a G-line */
+    /* convert expire and lastmod, look for lifetime and reason */
+    if (parc > 4) { /* protect against fall-through from 4-param form */
+      expire = atoi(parv[3]); /* convert expiration and lastmod */
+      expire = abs_expire(expire);
+      lastmod = atoi(parv[4]);
+
+      flags |= GLINE_EXPIRE; /* we have an expiration time update */
+
+      if (parc > 6) { /* no question, have a lifetime and reason */
+       lifetime = atoi(parv[5]);
+       reason = parv[parc - 1];
+
+       flags |= GLINE_LIFETIME | GLINE_REASON;
+      } else if (parc == 6) { /* either a lifetime or a reason */
+       if (!agline || /* gline creation, has to be the reason */
+           /* trial-convert as lifetime, and if it doesn't fully convert,
+            * it must be the reason */
+           (!(lifetime = strtoul(parv[5], &tmp, 10)) && !*tmp)) {
+         lifetime = 0;
+         reason = parv[5];
+
+         flags |= GLINE_REASON; /* have a reason update */
+       } else if (lifetime)
+         flags |= GLINE_LIFETIME; /* have a lifetime update */
+      }
+    }
+  }
+
+  if (!lastmod) /* must have a lastmod parameter by now */
+    return need_more_params(sptr, "GLINE");
+
+  Debug((DEBUG_DEBUG, "I have a global G-line I am acting upon now; "
+        "target %s, mask %s, operforce %s, action %s, expire %Tu, "
+        "lastmod %Tu, lifetime %Tu, reason: %s; gline %s!  (fields "
+        "present: %s %s %s)", target, mask,
+        flags & GLINE_OPERFORCE ? "YES" : "NO",
+        action == GLINE_ACTIVATE ? "+" :
+        (action == GLINE_DEACTIVATE ? "-" :
+         (action == GLINE_LOCAL_ACTIVATE ? ">" :
+          (action == GLINE_LOCAL_DEACTIVATE ? "<" : "(MODIFY)"))),
+        expire, lastmod, lifetime, reason,
+        agline ? "EXISTS" : "does not exist",
+        flags & GLINE_EXPIRE ? "expire" : "",
+        flags & GLINE_LIFETIME ? "lifetime" : "",
+        flags & GLINE_REASON ? "reason" : ""));
+
+  /* OK, at this point, we have converted all available parameters.
+   * Let's actually do the action!
+   */
+  if (agline)
+    return gline_modify(cptr, sptr, agline, action, reason, expire,
+                       lastmod, lifetime, flags);
+
+  assert(action != GLINE_LOCAL_ACTIVATE);
+  assert(action != GLINE_LOCAL_DEACTIVATE);
+  assert(action != GLINE_MODIFY);
+
+  if (!expire) { /* Cannot *add* a G-line we don't have, but try hard */
+    Debug((DEBUG_DEBUG, "Propagating G-line %s for G-line we don't have",
+          action == GLINE_ACTIVATE ? "activation" : "deactivation"));
+
+    /* propagate the G-line, even though we don't have it */
+    sendcmdto_serv_butone(sptr, CMD_GLINE, cptr, "* %c%s %Tu",
+                         action == GLINE_ACTIVATE ? '+' : '-',
+                         mask, lastmod);
+
+    return 0;
+  }
+
+  return gline_add(cptr, sptr, mask, reason, expire, lastmod, lifetime,
+                  flags | ((action == GLINE_ACTIVATE) ? GLINE_ACTIVE : 0));
+}
+
+/*
+ * mo_gline - oper message handler
+ *
+ * parv[0] = Sender prefix
+ * parv[1] = [[+|-]<G-line mask>]
+ *
+ * For other parameters, see doc/readme.gline.
+ */
+int
+mo_gline(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
+{
+  struct Client *acptr = 0;
+  struct Gline *agline = 0;
+  unsigned int flags = 0;
+  enum GlineAction action = GLINE_MODIFY;
+  time_t expire = 0;
+  char *mask = parv[1], *target = 0, *reason = 0, *end;
+
+  if (parc < 2)
+    return gline_list(sptr, 0);
+
+  if (*mask == '!') {
+    mask++;
+
+    if (HasPriv(sptr, PRIV_WIDE_GLINE))
+      flags |= GLINE_OPERFORCE;
+  }
+
+  switch (*mask) { /* handle +, -, <, and > */
+  case '+': /* activate the G-line */
+    action = GLINE_ACTIVATE;
+    mask++;
+    break;
+
+  case '-': /* deactivate the G-line */
+    action = GLINE_DEACTIVATE;
+    mask++;
+    break;
+
+  case '>': /* locally activate the G-line */
+    action = GLINE_LOCAL_ACTIVATE;
+    mask++;
+    break;
+
+  case '<': /* locally deactivate the G-line */
+    action = GLINE_LOCAL_DEACTIVATE;
+    mask++;
+    break;
+  }
+
+  /* OK, let's figure out the parameters... */
+  switch (action) {
+  case GLINE_MODIFY: /* no specific action on the G-line... */
+    if (parc == 2) /* user wants a listing of a specific G-line */
+      return gline_list(sptr, mask);
+    else if (parc < 4) /* must have target and expire, minimum */
+      return need_more_params(sptr, "GLINE");
+
+    target = parv[2]; /* get the target... */
+    expire = strtol(parv[3], &end, 10) + CurrentTime; /* and the expiration */
+    if (*end != '\0')
+      return send_reply(sptr, SND_EXPLICIT | ERR_BADEXPIRE, "%s :Bad expire time", parv[3]);
+
+    flags |= GLINE_EXPIRE; /* remember that we got an expire time */
+
+    if (parc > 4) { /* also got a reason... */
+      reason = parv[parc - 1];
+      flags |= GLINE_REASON;
+    }
+
+    /* target is not global, interpolate action and require reason */
+    if (target[0] != '*' || target[1] != '\0') {
+      if (!reason) /* have to have a reason for this */
+       return need_more_params(sptr, "GLINE");
+
+      action = GLINE_ACTIVATE;
+    }
+    break;
+
+  case GLINE_LOCAL_ACTIVATE: /* locally activate a G-line */
+  case GLINE_LOCAL_DEACTIVATE: /* locally deactivate a G-line */
+    if (parc > 2) { /* if target is available, pick it */
+      target = parv[2];
+      if (target[0] == '*' && target[1] == '\0')
+        return send_reply(sptr, ERR_NOSUCHSERVER, target);
+    }
+    break;
+
+  case GLINE_ACTIVATE: /* activating/adding a G-line */
+  case GLINE_DEACTIVATE: /* deactivating/removing a G-line */
+    if (parc < 3)
+      return need_more_params(sptr, "GLINE");
+
+    if (parc > 3) {
+      /* get expiration and target */
+      reason = parv[parc - 1];
+      expire = strtol(parv[parc - 2], &end, 10) + CurrentTime;
+      if (*end != '\0')
+        return send_reply(sptr, SND_EXPLICIT | ERR_BADEXPIRE, "%s :Bad expire time", parv[parc - 2]);
+
+      flags |= GLINE_EXPIRE | GLINE_REASON; /* remember that we got 'em */
+
+      if (parc > 4) /* also have a target! */
+       target = parv[2];
+    } else {
+      target = parv[2]; /* target has to be present, and has to be '*' */
+
+      if (target[0] != '*' || target[1] != '\0')
+       return need_more_params(sptr, "GLINE");
+    }
+    break;
+  }
+
+  /* Now let's figure out which is the target server */
+  if (!target) /* no target, has to be me... */
+    acptr = &me;
+  /* if it's not '*', look up the server */
+  else if ((target[0] != '*' || target[1] != '\0') &&
+          !(acptr = find_match_server(target)))
+    return send_reply(sptr, ERR_NOSUCHSERVER, target);
+
+  /* Now, is the G-line local or global? */
+  if (action == GLINE_LOCAL_ACTIVATE || action == GLINE_LOCAL_DEACTIVATE ||
+      !acptr)
+    flags |= GLINE_GLOBAL;
+  else /* it's some form of local G-line */
+    flags |= GLINE_LOCAL;
+
+  /* If it's a local activate/deactivate and server isn't me, propagate it */
+  if ((action == GLINE_LOCAL_ACTIVATE || action == GLINE_LOCAL_DEACTIVATE) &&
+      !IsMe(acptr)) {
+    /* check for permissions... */
+    if (!feature_bool(FEAT_CONFIG_OPERCMDS))
+      return send_reply(sptr, ERR_DISABLED, "GLINE");
+    else if (!HasPriv(sptr, PRIV_GLINE))
+      return send_reply(sptr, ERR_NOPRIVILEGES);
+
+    Debug((DEBUG_DEBUG, "I am forwarding a local change to a global gline "
+          "to a remote server; target %s, mask %s, operforce %s, action %c",
+          cli_name(acptr), mask, flags & GLINE_OPERFORCE ? "YES" : "NO",
+          action == GLINE_LOCAL_ACTIVATE ? '>' : '<'));
+
+    sendcmdto_one(sptr, CMD_GLINE, acptr, "%C %s%c%s", acptr,
+                  flags & GLINE_OPERFORCE ? "!" : "",
+                  action == GLINE_LOCAL_ACTIVATE ? '>' : '<', mask);
+
+    return 0; /* all done */
+  }
+
+  /* Next, try to find the G-line... */
+  if ((flags & GLINE_GLOBAL) || IsMe(acptr)) /* don't bother if it's not me! */
+    agline = gline_find(mask, flags | GLINE_ANY | GLINE_EXACT);
+
+  /* We now have all the pieces to tell us what we've got; let's put
+   * it all together and convert the rest of the arguments.
+   */
+
+  /* Handle the local G-lines first... */
+  if (flags & GLINE_LOCAL) {
+    assert(acptr);
+
+    /* normalize the action, first */
+    if (action == GLINE_LOCAL_ACTIVATE || action == GLINE_MODIFY)
+      action = GLINE_ACTIVATE;
+    else if (action == GLINE_LOCAL_DEACTIVATE)
+      action = GLINE_DEACTIVATE;
+
+    /* If it's not for us, forward */
+    /* UPDATE NOTE: Once all servers are updated to u2.10.12.11, the
+     * format string in this sendcmdto_one() may be updated to omit
+     * <lastmod> for GLINE_ACTIVATE and to omit <expire>, <lastmod>,
+     * and <reason> for GLINE_DEACTIVATE.
+     */
+
+    if (!IsMe(acptr)) {
+      /* check for permissions... */
+      if (!feature_bool(FEAT_CONFIG_OPERCMDS))
+       return send_reply(sptr, ERR_DISABLED, "GLINE");
+      else if (!HasPriv(sptr, PRIV_GLINE))
+       return send_reply(sptr, ERR_NOPRIVILEGES);
+
+      Debug((DEBUG_DEBUG, "I am forwarding a local G-line to a remote "
+            "server; target %s, mask %s, operforce %s, action %c, "
+            "expire %Tu, reason %s", target, mask,
+            flags & GLINE_OPERFORCE ? "YES" : "NO",
+            action == GLINE_ACTIVATE ? '+' : '-', expire, reason));
+
+      sendcmdto_one(sptr, CMD_GLINE, acptr, "%C %s%c%s %Tu %Tu :%s",
+                   acptr, flags & GLINE_OPERFORCE ? "!" : "",
+                   action == GLINE_ACTIVATE ? '+' : '-', mask,
+                   expire - CurrentTime, CurrentTime, reason);
+
+      return 0; /* all done */
+    }
+
+    /* check local G-line permissions... */
+    if (!HasPriv(sptr, PRIV_LOCAL_GLINE))
+      return send_reply(sptr, ERR_NOPRIVILEGES);
+
+    /* let's handle activation... */
+    if (action == GLINE_ACTIVATE) {
+      if (agline) /* G-line already exists, so let's ignore it... */
+       return 0;
+
+      /* OK, create the local G-line */
+      Debug((DEBUG_DEBUG, "I am creating a local G-line here; target %s, "
+            "mask %s, operforce %s, action  %s, expire %Tu, reason: %s",
+            target, mask, flags & GLINE_OPERFORCE ? "YES" : "NO",
+            action == GLINE_ACTIVATE ? "+" : "-", expire, reason));
+
+      return gline_add(cptr, sptr, mask, reason, expire, 0, 0,
+                      flags | GLINE_ACTIVE);
+    } else { /* OK, it's a deactivation/destruction */
+      if (!agline) /* G-line doesn't exist, so let's complain... */
+       return send_reply(sptr, ERR_NOSUCHGLINE, mask);
+
+      /* Let's now destroy the G-line */
+      Debug((DEBUG_DEBUG, "I am destroying a local G-line here; target %s, "
+            "mask %s, operforce %s, action %s", target, mask,
+            flags & GLINE_OPERFORCE ? "YES" : "NO",
+            action == GLINE_ACTIVATE ? "+" : "-"));
+
+      return gline_destroy(cptr, sptr, agline);
+    }
+  }
+
+  /* can't modify a G-line that doesn't exist...
+   * (and if we are creating a new one, we need a reason and expiration)
+   */
+  if (!agline &&
+      (action == GLINE_MODIFY || action == GLINE_LOCAL_ACTIVATE ||
+       action == GLINE_LOCAL_DEACTIVATE || !reason || !expire))
+    return send_reply(sptr, ERR_NOSUCHGLINE, mask);
+
+  /* check for G-line permissions... */
+  if (action == GLINE_LOCAL_ACTIVATE || action == GLINE_LOCAL_DEACTIVATE) {
+    /* only need local privileges for locally-limited status changes */
+    if (!HasPriv(sptr, PRIV_LOCAL_GLINE))
+      return send_reply(sptr, ERR_NOPRIVILEGES);
+  } else { /* global privileges required */
+    if (!feature_bool(FEAT_CONFIG_OPERCMDS))
+      return send_reply(sptr, ERR_DISABLED, "GLINE");
+    else if (!HasPriv(sptr, PRIV_GLINE))
+      return send_reply(sptr, ERR_NOPRIVILEGES);
+  }
+
+  Debug((DEBUG_DEBUG, "I have a global G-line I am acting upon now; "
+        "target %s, mask %s, operforce %s, action %s, expire %Tu, "
+        "reason: %s; gline %s!  (fields present: %s %s)", target, 
+        mask, flags & GLINE_OPERFORCE ? "YES" : "NO",
+        action == GLINE_ACTIVATE ? "+" :
+        (action == GLINE_DEACTIVATE ? "-" :
+         (action == GLINE_LOCAL_ACTIVATE ? ">" :
+          (action == GLINE_LOCAL_DEACTIVATE ? "<" : "(MODIFY)"))),
+        expire, reason, agline ? "EXISTS" : "does not exist",
+        flags & GLINE_EXPIRE ? "expire" : "",
+        flags & GLINE_REASON ? "reason" : ""));
+
+  if (agline) /* modifying an existing G-line */
+    return gline_modify(cptr, sptr, agline, action, reason, expire,
+                       CurrentTime, 0, flags);
+
+  assert(action != GLINE_LOCAL_ACTIVATE);
+  assert(action != GLINE_LOCAL_DEACTIVATE);
+  assert(action != GLINE_MODIFY);
+
+  /* create a new G-line */
+  return gline_add(cptr, sptr, mask, reason, expire, CurrentTime, 0,
+                  flags | ((action == GLINE_ACTIVATE) ? GLINE_ACTIVE : 0));
+}
+
+/*
+ * m_gline - user message handler
+ *
+ * parv[0] = Sender prefix
+ * parv[1] = [<server name>]
+ *
+ */
+int
+m_gline(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
+{
+  if (parc < 2)
+    return send_reply(sptr, ERR_NOSUCHGLINE, "");
+
+  return gline_list(sptr, parv[1]);
+}
diff --git a/ircd/m_help.c b/ircd/m_help.c
new file mode 100644 (file)
index 0000000..4818ae1
--- /dev/null
@@ -0,0 +1,108 @@
+/*
+ * IRC - Internet Relay Chat, ircd/m_help.c
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ *                    University of Oulu, Computing Center
+ *
+ * See file AUTHORS in IRC package for additional names of
+ * the programmers.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id: m_help.c 1271 2004-12-11 05:14:07Z klmitch $
+ */
+
+/*
+ * m_functions execute protocol messages on this server:
+ *
+ *    cptr    is always NON-NULL, pointing to a *LOCAL* client
+ *            structure (with an open socket connected!). This
+ *            identifies the physical socket where the message
+ *            originated (or which caused the m_function to be
+ *            executed--some m_functions may call others...).
+ *
+ *    sptr    is the source of the message, defined by the
+ *            prefix part of the message if present. If not
+ *            or prefix not found, then sptr==cptr.
+ *
+ *            (!IsServer(cptr)) => (cptr == sptr), because
+ *            prefixes are taken *only* from servers...
+ *
+ *            (IsServer(cptr))
+ *                    (sptr == cptr) => the message didn't
+ *                    have the prefix.
+ *
+ *                    (sptr != cptr && IsServer(sptr) means
+ *                    the prefix specified servername. (?)
+ *
+ *                    (sptr != cptr && !IsServer(sptr) means
+ *                    that message originated from a remote
+ *                    user (not local).
+ *
+ *            combining
+ *
+ *            (!IsServer(sptr)) means that, sptr can safely
+ *            taken as defining the target structure of the
+ *            message in this server.
+ *
+ *    *Always* true (if 'parse' and others are working correct):
+ *
+ *    1)      sptr->from == cptr  (note: cptr->from == cptr)
+ *
+ *    2)      MyConnect(sptr) <=> sptr == cptr (e.g. sptr
+ *            *cannot* be a local connection, unless it's
+ *            actually cptr!). [MyConnect(x) should probably
+ *            be defined as (x == x->from) --msa ]
+ *
+ *    parc    number of variable parameter strings (if zero,
+ *            parv is allowed to be NULL)
+ *
+ *    parv    a NULL terminated list of parameter pointers,
+ *
+ *                    parv[0], sender (prefix string), if not present
+ *                            this points to an empty string.
+ *                    parv[1]...parv[parc-1]
+ *                            pointers to additional parameters
+ *                    parv[parc] == NULL, *always*
+ *
+ *            note:   it is guaranteed that parv[0]..parv[parc-1] are all
+ *                    non-NULL pointers.
+ */
+#include "config.h"
+
+#include "client.h"
+#include "hash.h"
+#include "ircd.h"
+#include "ircd_log.h"
+#include "ircd_reply.h"
+#include "ircd_string.h"
+#include "msg.h"
+#include "numeric.h"
+#include "numnicks.h"
+#include "send.h"
+
+/* #include <assert.h> -- Now using assert in ircd_log.h */
+
+/*
+ * m_help - generic message handler
+ */
+int m_help(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  int i;
+
+  for (i = 0; msgtab[i].cmd; i++)
+    sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :%s", sptr, msgtab[i].cmd);
+  return 0;
+}
+
diff --git a/ircd/m_hidehost.c b/ircd/m_hidehost.c
new file mode 100644 (file)
index 0000000..7694a36
--- /dev/null
@@ -0,0 +1,122 @@
+/*
+ * IRC - Internet Relay Chat, ircd/m_hidehost.c
+ * Written by David Herrmann.
+ */
+
+/*
+ * m_functions execute protocol messages on this server:
+ *
+ *    cptr    is always NON-NULL, pointing to a *LOCAL* client
+ *            structure (with an open socket connected!). This
+ *            identifies the physical socket where the message
+ *            originated (or which caused the m_function to be
+ *            executed--some m_functions may call others...).
+ *
+ *    sptr    is the source of the message, defined by the
+ *            prefix part of the message if present. If not
+ *            or prefix not found, then sptr==cptr.
+ *
+ *            (!IsServer(cptr)) => (cptr == sptr), because
+ *            prefixes are taken *only* from servers...
+ *
+ *            (IsServer(cptr))
+ *                    (sptr == cptr) => the message didn't
+ *                    have the prefix.
+ *
+ *                    (sptr != cptr && IsServer(sptr) means
+ *                    the prefix specified servername. (?)
+ *
+ *                    (sptr != cptr && !IsServer(sptr) means
+ *                    that message originated from a remote
+ *                    user (not local).
+ *
+ *            combining
+ *
+ *            (!IsServer(sptr)) means that, sptr can safely
+ *            taken as defining the target structure of the
+ *            message in this server.
+ *
+ *    *Always* true (if 'parse' and others are working correct):
+ *
+ *    1)      sptr->from == cptr  (note: cptr->from == cptr)
+ *
+ *    2)      MyConnect(sptr) <=> sptr == cptr (e.g. sptr
+ *            *cannot* be a local connection, unless it's
+ *            actually cptr!). [MyConnect(x) should probably
+ *            be defined as (x == x->from) --msa ]
+ *
+ *    parc    number of variable parameter strings (if zero,
+ *            parv is allowed to be NULL)
+ *
+ *    parv    a NULL terminated list of parameter pointers,
+ *
+ *                    parv[0], sender (prefix string), if not present
+ *                            this points to an empty string.
+ *                    parv[1]...parv[parc-1]
+ *                            pointers to additional parameters
+ *                    parv[parc] == NULL, *always*
+ *
+ *            note:   it is guaranteed that parv[0]..parv[parc-1] are all
+ *                    non-NULL pointers.
+ */
+#include "config.h"
+
+#include "client.h"
+#include "handlers.h"
+#include "hash.h"
+#include "ircd.h"
+#include "ircd_defs.h"
+#include "ircd_features.h"
+#include "ircd_log.h"
+#include "ircd_reply.h"
+#include "ircd_string.h"
+#include "match.h"
+#include "msg.h"
+#include "numeric.h"
+#include "numnicks.h"
+#include "s_conf.h"
+#include "s_misc.h"
+#include "s_user.h"
+#include "send.h"
+#include "sys.h"
+
+/* ms_hidehost
+ *  parv[0] = sender
+ *  parv[1] = target nick
+ */
+/** Remote hidehost
+ * Allows ulined servers to force umode +x on remote users. Though, we should use numerics
+ * as target, the current services use nicknames. This may be changed in future.
+ *
+ * The HIDEHOST request can be generated by EVERY server. It is forwarded to the server
+ * of the user which then sets the umode +x and broadcasts the new umodes.
+ */
+int ms_hidehost(struct Client *cptr, struct Client *sptr, int parc, char *parv[]) {
+    signed int propagate;
+    struct Client *acptr;
+    struct Flags setflags;
+
+    if(parc < 2) {
+        return need_more_params(sptr, "HIDEHOST");
+    }
+
+    /* Check whether the user is already gone or already hidden. */
+    if(!(acptr = FindUser(parv[1])) || !IsUser(acptr) || IsHiddenHost(acptr)) {
+        return 0;
+    }
+
+    /* If the user is no local user, we forward the message to the user's server. */
+    if(!MyConnect(acptr)) {
+        sendcmdto_one(sptr, CMD_HIDEHOST, cli_user(acptr)->server, "%s", cli_name(acptr));
+        return 0;
+    }
+
+    /* Set +x and propagate the changed modes. */
+    propagate = !!HasPriv(acptr, PRIV_PROPAGATE);
+    setflags = cli_flags(acptr);
+    hide_hostmask(acptr, FLAG_HIDDENHOST);
+    send_umode_out(acptr, acptr, &setflags, propagate);
+
+    return 0;
+}
+
diff --git a/ircd/m_info.c b/ircd/m_info.c
new file mode 100644 (file)
index 0000000..dad98b3
--- /dev/null
@@ -0,0 +1,181 @@
+/*
+ * IRC - Internet Relay Chat, ircd/m_info.c
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ *                    University of Oulu, Computing Center
+ *
+ * See file AUTHORS in IRC package for additional names of
+ * the programmers.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id: m_info.c 1271 2004-12-11 05:14:07Z klmitch $
+ */
+
+/*
+ * m_functions execute protocol messages on this server:
+ *
+ *    cptr    is always NON-NULL, pointing to a *LOCAL* client
+ *            structure (with an open socket connected!). This
+ *            identifies the physical socket where the message
+ *            originated (or which caused the m_function to be
+ *            executed--some m_functions may call others...).
+ *
+ *    sptr    is the source of the message, defined by the
+ *            prefix part of the message if present. If not
+ *            or prefix not found, then sptr==cptr.
+ *
+ *            (!IsServer(cptr)) => (cptr == sptr), because
+ *            prefixes are taken *only* from servers...
+ *
+ *            (IsServer(cptr))
+ *                    (sptr == cptr) => the message didn't
+ *                    have the prefix.
+ *
+ *                    (sptr != cptr && IsServer(sptr) means
+ *                    the prefix specified servername. (?)
+ *
+ *                    (sptr != cptr && !IsServer(sptr) means
+ *                    that message originated from a remote
+ *                    user (not local).
+ *
+ *            combining
+ *
+ *            (!IsServer(sptr)) means that, sptr can safely
+ *            taken as defining the target structure of the
+ *            message in this server.
+ *
+ *    *Always* true (if 'parse' and others are working correct):
+ *
+ *    1)      sptr->from == cptr  (note: cptr->from == cptr)
+ *
+ *    2)      MyConnect(sptr) <=> sptr == cptr (e.g. sptr
+ *            *cannot* be a local connection, unless it's
+ *            actually cptr!). [MyConnect(x) should probably
+ *            be defined as (x == x->from) --msa ]
+ *
+ *    parc    number of variable parameter strings (if zero,
+ *            parv is allowed to be NULL)
+ *
+ *    parv    a NULL terminated list of parameter pointers,
+ *
+ *                    parv[0], sender (prefix string), if not present
+ *                            this points to an empty string.
+ *                    parv[1]...parv[parc-1]
+ *                            pointers to additional parameters
+ *                    parv[parc] == NULL, *always*
+ *
+ *            note:   it is guaranteed that parv[0]..parv[parc-1] are all
+ *                    non-NULL pointers.
+ */
+#include "config.h"
+
+#include "client.h"
+#include "ircd.h"
+#include "ircd_log.h"
+#include "ircd_reply.h"
+#include "ircd_string.h"
+#include "msg.h"
+#include "numeric.h"
+#include "numnicks.h"
+#include "s_misc.h"
+#include "s_user.h"
+#include "s_conf.h"
+#include "send.h"
+#include "version.h"
+
+/* #include <assert.h> -- Now using assert in ircd_log.h */
+
+/*
+ * m_info - generic message handler
+ *
+ * parv[0] = sender prefix
+ * parv[1] = servername
+ */
+int m_info(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  const char **text = infotext;
+
+  if (hunt_server_cmd(sptr, CMD_INFO, cptr, 1, ":%C", 1, parc, parv) !=
+      HUNTED_ISME)
+       return 0;
+
+  while (*text)
+  {
+    send_reply(sptr, RPL_INFO, *text);
+    text++;
+  }
+  send_reply(sptr, SND_EXPLICIT | RPL_INFO, ":Birth Date: %s, compile # %s, revision %s",
+      creation, generation, svn_srev);
+  send_reply(sptr, SND_EXPLICIT | RPL_INFO, ":On-line since %s",
+      myctime(cli_firsttime(&me)));
+  send_reply(sptr, RPL_ENDOFINFO);
+
+  return 0;
+}
+
+/*
+ * ms_info - server message handler
+ *
+ * parv[0] = sender prefix
+ * parv[1] = servername
+ */
+int ms_info(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  const char **text = infotext;
+
+  if (IsServer(sptr))
+    return 0;
+
+  if (hunt_server_cmd(sptr, CMD_INFO, cptr, 1, ":%C", 1, parc, parv) !=
+      HUNTED_ISME)
+       return 0;
+  while (*text)
+  {
+    send_reply(sptr, RPL_INFO, *text++);
+  }
+  send_reply(sptr, SND_EXPLICIT | RPL_INFO, ":Birth Date: %s, compile # %s, revision %s",
+      creation, generation, svn_srev);
+  send_reply(sptr, SND_EXPLICIT | RPL_INFO, ":On-line since %s",
+      myctime(cli_firsttime(&me)));
+  send_reply(sptr, RPL_ENDOFINFO);
+  return 0;
+}
+
+/*
+ * mo_info - oper message handler
+ *
+ * parv[0] = sender prefix
+ * parv[1] = servername
+ */
+int mo_info(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  const char **text = infotext;
+
+  if (hunt_server_cmd(sptr, CMD_INFO, cptr, 1, ":%C", 1, parc, parv) ==
+      HUNTED_ISME)
+  {
+    while (*text)
+    {
+      send_reply(sptr, RPL_INFO, *text++);
+    }
+    send_reply(sptr, SND_EXPLICIT | RPL_INFO, ":Birth Date: %s, compile # %s, revision %s",
+               creation, generation, svn_srev);
+    send_reply(sptr, SND_EXPLICIT | RPL_INFO, ":On-line since %s",
+              myctime(cli_firsttime(&me)));
+    send_reply(sptr, RPL_ENDOFINFO);
+  }
+  return 0;
+}
+
diff --git a/ircd/m_invite.c b/ircd/m_invite.c
new file mode 100644 (file)
index 0000000..9308007
--- /dev/null
@@ -0,0 +1,303 @@
+/*
+ * IRC - Internet Relay Chat, ircd/m_invite.c
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ *                    University of Oulu, Computing Center
+ *
+ * See file AUTHORS in IRC package for additional names of
+ * the programmers.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id: m_invite.c 1485 2005-09-13 15:17:46Z entrope $
+ */
+
+/*
+ * m_functions execute protocol messages on this server:
+ *
+ *    cptr    is always NON-NULL, pointing to a *LOCAL* client
+ *            structure (with an open socket connected!). This
+ *            identifies the physical socket where the message
+ *            originated (or which caused the m_function to be
+ *            executed--some m_functions may call others...).
+ *
+ *    sptr    is the source of the message, defined by the
+ *            prefix part of the message if present. If not
+ *            or prefix not found, then sptr==cptr.
+ *
+ *            (!IsServer(cptr)) => (cptr == sptr), because
+ *            prefixes are taken *only* from servers...
+ *
+ *            (IsServer(cptr))
+ *                    (sptr == cptr) => the message didn't
+ *                    have the prefix.
+ *
+ *                    (sptr != cptr && IsServer(sptr) means
+ *                    the prefix specified servername. (?)
+ *
+ *                    (sptr != cptr && !IsServer(sptr) means
+ *                    that message originated from a remote
+ *                    user (not local).
+ *
+ *            combining
+ *
+ *            (!IsServer(sptr)) means that, sptr can safely
+ *            taken as defining the target structure of the
+ *            message in this server.
+ *
+ *    *Always* true (if 'parse' and others are working correct):
+ *
+ *    1)      sptr->from == cptr  (note: cptr->from == cptr)
+ *
+ *    2)      MyConnect(sptr) <=> sptr == cptr (e.g. sptr
+ *            *cannot* be a local connection, unless it's
+ *            actually cptr!). [MyConnect(x) should probably
+ *            be defined as (x == x->from) --msa ]
+ *
+ *    parc    number of variable parameter strings (if zero,
+ *            parv is allowed to be NULL)
+ *
+ *    parv    a NULL terminated list of parameter pointers,
+ *
+ *                    parv[0], sender (prefix string), if not present
+ *                            this points to an empty string.
+ *                    parv[1]...parv[parc-1]
+ *                            pointers to additional parameters
+ *                    parv[parc] == NULL, *always*
+ *
+ *            note:   it is guaranteed that parv[0]..parv[parc-1] are all
+ *                    non-NULL pointers.
+ */
+#include "config.h"
+
+#include "channel.h"
+#include "client.h"
+#include "hash.h"
+#include "ircd.h"
+#include "ircd_features.h"
+#include "ircd_log.h"
+#include "ircd_reply.h"
+#include "ircd_string.h"
+#include "list.h"
+#include "msg.h"
+#include "numeric.h"
+#include "numnicks.h"
+#include "s_user.h"
+#include "send.h"
+#include "struct.h"
+
+/* #include <assert.h> -- Now using assert in ircd_log.h */
+
+/*
+ * m_invite - generic message handler
+ *
+ *   parv[0] - sender prefix
+ *   parv[1] - user to invite
+ *   parv[2] - channel name
+ *
+ * - INVITE now is accepted only if who does it is chanop (this of course
+ *   implies that channel must exist and he must be on it).
+ *
+ * - On the other side it IS processed even if channel is NOT invite only
+ *   leaving room for other enhancements like inviting banned ppl.  -- Nemesi
+ *
+ * - Invite with no parameters now lists the channels you are invited to.
+ *                                                         - Isomer 23 Oct 99
+ */
+int m_invite(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  struct Client *acptr;
+  struct Channel *chptr;
+  
+  if (parc < 2 ) { 
+    /*
+     * list the channels you have an invite to.
+     */
+    struct SLink *lp;
+    for (lp = cli_user(sptr)->invited; lp; lp = lp->next)
+      send_reply(cptr, RPL_INVITELIST, lp->value.chptr->chname);
+    send_reply(cptr, RPL_ENDOFINVITELIST);
+    return 0;
+  }
+  
+  if (parc < 3 || EmptyString(parv[2]))
+    return need_more_params(sptr, "INVITE");
+
+  if (!(acptr = FindUser(parv[1]))) {
+    send_reply(sptr, ERR_NOSUCHNICK, parv[1]);
+    return 0;
+  }
+
+  if (is_silenced(sptr, acptr))
+    return 0;
+
+  if (!IsChannelName(parv[2])
+      || !strIsIrcCh(parv[2])
+      || !(chptr = FindChannel(parv[2]))) {
+    send_reply(sptr, ERR_NOSUCHCHANNEL, parv[2]);
+    return 0;
+  }
+
+  if (!find_channel_member(sptr, chptr)) {
+    send_reply(sptr, ERR_NOTONCHANNEL, chptr->chname);
+    return 0;
+  }
+
+  if (find_channel_member(acptr, chptr)) {
+    send_reply(sptr, ERR_USERONCHANNEL, cli_name(acptr), chptr->chname);
+    return 0;
+  }
+
+  if (!is_chan_op(sptr, chptr)) {
+    send_reply(sptr, ERR_CHANOPRIVSNEEDED, chptr->chname);
+    return 0;
+  }
+
+  /* If we get here, it was a VALID and meaningful INVITE */
+
+  if (check_target_limit(sptr, acptr, cli_name(acptr), 0))
+    return 0;
+
+  send_reply(sptr, RPL_INVITING, cli_name(acptr), chptr->chname);
+
+  if (cli_user(acptr)->away)
+    send_reply(sptr, RPL_AWAY, cli_name(acptr), cli_user(acptr)->away);
+
+  if (MyConnect(acptr)) {
+    add_invite(acptr, chptr);
+    sendcmdto_one(sptr, CMD_INVITE, acptr, "%s %H", cli_name(acptr), chptr);
+  } else if (!IsLocalChannel(chptr->chname)) {
+    sendcmdto_one(sptr, CMD_INVITE, acptr, "%s %H %Tu", cli_name(acptr), chptr,
+                  chptr->creationtime);
+  }
+
+  if (!IsLocalChannel(chptr->chname) || MyConnect(acptr)) {
+    if (feature_bool(FEAT_ANNOUNCE_INVITES) && !IsChannelService(sptr)) {
+      /* Announce to channel operators. */
+      sendcmdto_channel_butserv_butone(&his, get_error_numeric(RPL_ISSUEDINVITE)->str,
+                                       NULL, chptr, sptr, SKIP_NONOPS,
+                                       "%H %C %C :%C has been invited by %C",
+                                       chptr, acptr, sptr, acptr, sptr);
+      /* Announce to servers with channel operators. */
+      sendcmdto_channel_servers_butone(sptr, NULL, TOK_INVITE, chptr, acptr, SKIP_NONOPS,
+                                       "%s %H %Tu", cli_name(acptr),
+                                       chptr, chptr->creationtime);
+    }
+  }
+
+  return 0;
+}
+
+/*
+ * ms_invite - server message handler
+ *
+ *   parv[0] - sender prefix
+ *   parv[1] - user to invite
+ *   parv[2] - channel name
+ *   parv[3] - (optional) channel timestamp
+ *
+ * - INVITE now is accepted only if who does it is chanop (this of course
+ *   implies that channel must exist and he must be on it).
+ *
+ * - On the other side it IS processed even if channel is NOT invite only
+ *   leaving room for other enhancements like inviting banned ppl.  -- Nemesi
+ *
+ * - Invite with no parameters now lists the channels you are invited to.
+ *                                                         - Isomer 23 Oct 99
+ *
+ * - Invite with too-late timestamp, or with no timestamp from a bursting
+ *   server, is silently discarded.                   - Entrope 19 Jan 05
+ */
+int ms_invite(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  struct Client *acptr;
+  struct Channel *chptr;
+  time_t invite_ts;
+  
+  if (IsServer(sptr)) {
+    /*
+     * this will blow up if we get an invite from a server
+     * we look for channel membership in sptr below. 
+     */
+    return protocol_violation(sptr,"Server attempting to invite");
+  }
+  if (parc < 3 || EmptyString(parv[2])) {
+    /*
+     * should have been handled upstream, ignore it.
+     */
+    protocol_violation(sptr,"Too few arguments to invite");
+    return need_more_params(sptr,"INVITE");
+  }
+  if (!IsGlobalChannel(parv[2])) {
+    /*
+     * should not be sent
+     */
+    return protocol_violation(sptr, "Invite to a non-standard channel %s",parv[2]);
+  }
+  if (!(acptr = FindUser(parv[1]))) {
+    send_reply(sptr, ERR_NOSUCHNICK, parv[1]);
+    return 0;
+  }
+
+  if (!(chptr = FindChannel(parv[2]))) {
+    /*
+     * allow invites to non existent channels, bleah
+     * avoid JOIN, INVITE, PART abuse
+     */
+    sendcmdto_one(sptr, CMD_INVITE, acptr, "%C :%s", acptr, parv[2]);
+    return 0;
+  }
+
+  if (parc > 3) {
+    invite_ts = atoi(parv[3]);
+    if (invite_ts > chptr->creationtime)
+      return 0;
+  } else if (IsBurstOrBurstAck(cptr))
+    return 0;
+
+  if (!IsChannelService(sptr) && !find_channel_member(sptr, chptr)) {
+    send_reply(sptr, ERR_NOTONCHANNEL, chptr->chname);
+    return 0;
+  }
+
+  if (find_channel_member(acptr, chptr)) {
+    send_reply(sptr, ERR_USERONCHANNEL, cli_name(acptr), chptr->chname);
+    return 0;
+  }
+
+  if (is_silenced(sptr, acptr))
+    return 0;
+
+  if (MyConnect(acptr)) {
+    add_invite(acptr, chptr);
+    sendcmdto_one(sptr, CMD_INVITE, acptr, "%s %H", cli_name(acptr), chptr);
+  } else {
+    sendcmdto_one(sptr, CMD_INVITE, acptr, "%s %H %Tu", cli_name(acptr), chptr,
+                  chptr->creationtime);
+  }
+
+  if (feature_bool(FEAT_ANNOUNCE_INVITES) && !IsChannelService(sptr)) {
+    /* Announce to channel operators. */
+    sendcmdto_channel_butserv_butone(&his, get_error_numeric(RPL_ISSUEDINVITE)->str,
+                                     NULL, chptr, sptr, SKIP_NONOPS,
+                                     "%H %C %C :%C has been invited by %C",
+                                     chptr, acptr, sptr, acptr, sptr);
+    /* Announce to servers with channel operators. */
+    sendcmdto_channel_servers_butone(sptr, NULL, TOK_INVITE, chptr, acptr, SKIP_NONOPS,
+                                     "%s %H %Tu", cli_name(acptr), chptr,
+                                     chptr->creationtime);
+  }
+
+  return 0;
+}
diff --git a/ircd/m_ison.c b/ircd/m_ison.c
new file mode 100644 (file)
index 0000000..44fd4f4
--- /dev/null
@@ -0,0 +1,144 @@
+/*
+ * IRC - Internet Relay Chat, ircd/m_ison.c
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ *                    University of Oulu, Computing Center
+ *
+ * See file AUTHORS in IRC package for additional names of
+ * the programmers.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id: m_ison.c 1334 2005-03-20 16:06:30Z entrope $
+ */
+
+/*
+ * m_functions execute protocol messages on this server:
+ *
+ *    cptr    is always NON-NULL, pointing to a *LOCAL* client
+ *            structure (with an open socket connected!). This
+ *            identifies the physical socket where the message
+ *            originated (or which caused the m_function to be
+ *            executed--some m_functions may call others...).
+ *
+ *    sptr    is the source of the message, defined by the
+ *            prefix part of the message if present. If not
+ *            or prefix not found, then sptr==cptr.
+ *
+ *            (!IsServer(cptr)) => (cptr == sptr), because
+ *            prefixes are taken *only* from servers...
+ *
+ *            (IsServer(cptr))
+ *                    (sptr == cptr) => the message didn't
+ *                    have the prefix.
+ *
+ *                    (sptr != cptr && IsServer(sptr) means
+ *                    the prefix specified servername. (?)
+ *
+ *                    (sptr != cptr && !IsServer(sptr) means
+ *                    that message originated from a remote
+ *                    user (not local).
+ *
+ *            combining
+ *
+ *            (!IsServer(sptr)) means that, sptr can safely
+ *            taken as defining the target structure of the
+ *            message in this server.
+ *
+ *    *Always* true (if 'parse' and others are working correct):
+ *
+ *    1)      sptr->from == cptr  (note: cptr->from == cptr)
+ *
+ *    2)      MyConnect(sptr) <=> sptr == cptr (e.g. sptr
+ *            *cannot* be a local connection, unless it's
+ *            actually cptr!). [MyConnect(x) should probably
+ *            be defined as (x == x->from) --msa ]
+ *
+ *    parc    number of variable parameter strings (if zero,
+ *            parv is allowed to be NULL)
+ *
+ *    parv    a NULL terminated list of parameter pointers,
+ *
+ *                    parv[0], sender (prefix string), if not present
+ *                            this points to an empty string.
+ *                    parv[1]...parv[parc-1]
+ *                            pointers to additional parameters
+ *                    parv[parc] == NULL, *always*
+ *
+ *            note:   it is guaranteed that parv[0]..parv[parc-1] are all
+ *                    non-NULL pointers.
+ */
+#include "config.h"
+
+#include "client.h"
+#include "hash.h"
+#include "ircd.h"
+#include "ircd_log.h"
+#include "ircd_reply.h"
+#include "ircd_string.h"
+#include "msgq.h"
+#include "numeric.h"
+#include "send.h"
+
+/* #include <assert.h> -- Now using assert in ircd_log.h */
+#include <string.h>
+
+/*
+ * m_ison
+ *
+ * Added by Darren Reed 13/8/91 to act as an efficient user indicator
+ * with respect to cpu/bandwidth used. Implemented for NOTIFY feature in
+ * clients. Designed to reduce number of whois requests. Can process
+ * nicknames in batches as long as the maximum buffer length.
+ *
+ * format:
+ * ISON :nicklist
+ *
+ * XXX - this is virtually the same as send_user_info, but doesn't send
+ * no nick found, might be refactored so that m_userhost, m_userip, and
+ * m_ison all use the same function with different formatters. --Bleep
+ */
+int m_ison(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
+{
+  struct Client* acptr;
+  char*          name;
+  char*          p = 0;
+  struct MsgBuf* mb;
+  int i;
+
+  if (parc < 2)
+    return need_more_params(sptr, "ISON");
+
+  mb = msgq_make(sptr, rpl_str(RPL_ISON), cli_name(&me), cli_name(sptr));
+
+  for (i = 1; i < parc; i++) {
+    for (name = ircd_strtok(&p, parv[i], " "); name;
+        name = ircd_strtok(&p, 0, " ")) {
+      if ((acptr = FindUser(name))) {
+       if (msgq_bufleft(mb) < strlen(cli_name(acptr)) + 1) {
+         send_buffer(sptr, mb, 0); /* send partial response */
+         msgq_clean(mb); /* then do another round */
+         mb = msgq_make(sptr, rpl_str(RPL_ISON), cli_name(&me),
+                        cli_name(sptr));
+       }
+       msgq_append(0, mb, "%s ", cli_name(acptr));
+      }
+    }
+  }
+
+  send_buffer(sptr, mb, 0); /* send response */
+  msgq_clean(mb);
+
+  return 0;
+}
diff --git a/ircd/m_join.c b/ircd/m_join.c
new file mode 100644 (file)
index 0000000..0dc5ecf
--- /dev/null
@@ -0,0 +1,509 @@
+/*
+ * IRC - Internet Relay Chat, ircd/m_join.c
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ *                    University of Oulu, Computing Center
+ *
+ * See file AUTHORS in IRC package for additional names of
+ * the programmers.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id: m_join.c 1906 2009-02-09 03:39:42Z entrope $
+ */
+
+#include "config.h"
+
+#include "channel.h"
+#include "class.h"
+#include "client.h"
+#include "gline.h"
+#include "hash.h"
+#include "ircd.h"
+#include "ircd_chattr.h"
+#include "ircd_features.h"
+#include "ircd_log.h"
+#include "ircd_reply.h"
+#include "ircd_string.h"
+#include "list.h"
+#include "msg.h"
+#include "numeric.h"
+#include "numnicks.h"
+#include "s_conf.h"
+#include "s_debug.h"
+#include "s_user.h"
+#include "send.h"
+#include "sys.h"
+
+/* #include <assert.h> -- Now using assert in ircd_log.h */
+#include <stdlib.h>
+#include <string.h>
+
+/** Searches for and handles a 0 in a join list.
+ * @param[in] cptr Client that sent us the message.
+ * @param[in] sptr Original source of message.
+ * @param[in] chanlist List of channels to join.
+ * @return First token in \a chanlist after the final 0 entry, which
+ * may be its nul terminator (if the final entry is a 0 entry).
+ */
+static char *
+last0(struct Client *cptr, struct Client *sptr, char *chanlist)
+{
+  char *p;
+  int join0 = 0;
+
+  for (p = chanlist; p[0]; p++) /* find last "JOIN 0" */
+    if (p[0] == '0' && (p[1] == ',' || p[1] == '\0')) {
+      if (p[1] == ',')
+        p++;
+      chanlist = p + 1;
+      join0 = 1;
+    } else {
+      while (p[0] != ',' && p[0] != '\0') /* skip past channel name */
+       p++;
+
+      if (!p[0]) /* hit the end */
+       break;
+    }
+
+  if (join0) {
+    struct JoinBuf part;
+    struct Membership *member;
+
+    joinbuf_init(&part, sptr, cptr, JOINBUF_TYPE_PARTALL,
+                 "Left all channels", 0);
+
+    joinbuf_join(&part, 0, 0);
+
+    while ((member = cli_user(sptr)->channel))
+      joinbuf_join(&part, member->channel,
+                   IsZombie(member) ? CHFL_ZOMBIE :
+                   IsDelayedJoin(member) ? CHFL_DELAYED :
+                   0);
+
+    joinbuf_flush(&part);
+  }
+
+  return chanlist;
+}
+
+/** Handle a JOIN message from a client connection.
+ * See @ref m_functions for discussion of the arguments.
+ * @param[in] cptr Client that sent us the message.
+ * @param[in] sptr Original source of message.
+ * @param[in] parc Number of arguments.
+ * @param[in] parv Argument vector.
+ */
+int m_join(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
+{
+  struct Channel *chptr,*chptrb;
+  struct JoinBuf join;
+  struct JoinBuf create;
+  struct Gline *gline;
+  struct Membership *member;
+  char *p = 0;
+  char *chanlist;
+  char *name;
+  char *keys;
+  unsigned int maxchans;
+  const struct User* user = cli_user(sptr);
+
+  if (parc < 2 || *parv[1] == '\0')
+    return need_more_params(sptr, "JOIN");
+
+  joinbuf_init(&join, sptr, cptr, JOINBUF_TYPE_JOIN, 0, 0);
+  joinbuf_init(&create, sptr, cptr, JOINBUF_TYPE_CREATE, 0, TStime());
+
+  chanlist = last0(cptr, sptr, parv[1]); /* find last "JOIN 0" */
+
+  keys = parv[2]; /* remember where keys are */
+
+  for (name = ircd_strtok(&p, chanlist, ","); name;
+       name = ircd_strtok(&p, 0, ",")) {
+    char *key = 0;
+
+    /* If we have any more keys, take the first for this channel. */
+    if (!BadPtr(keys)
+        && (keys = strchr(key = keys, ',')))
+      *keys++ = '\0';
+
+    /* Empty keys are the same as no keys. */
+    if (key && !key[0])
+      key = 0;
+
+    if (!IsChannelName(name) || !strIsIrcCh(name))
+    {
+      /* bad channel name */
+      send_reply(sptr, ERR_NOSUCHCHANNEL, name);
+      continue;
+    }
+
+    maxchans = cli_confs(sptr)->value.aconf ? ConfMaxChannels(cli_confs(sptr)->value.aconf) : feature_int(FEAT_MAXCHANNELSPERUSER);
+    if(sptr->maxchans > 0)
+        maxchans = sptr->maxchans;
+    if (cli_user(sptr)->joined >= maxchans
+       && !HasPriv(sptr, PRIV_CHAN_LIMIT)) {
+      send_reply(sptr, ERR_TOOMANYCHANNELS, name);
+      break; /* no point processing the other channels */
+    }
+
+    /* BADCHANed channel */
+    if ((gline = gline_find(name, GLINE_BADCHAN)) &&
+       GlineIsActive(gline) && !IsAnOper(sptr)) {
+      send_reply(sptr, ERR_BADCHANNAME, name, GlineReason(gline));
+      continue;
+    }
+
+    if (!(chptr = FindChannel(name))) {
+      if (((name[0] == '&') && !feature_bool(FEAT_LOCAL_CHANNELS))
+          || strlen(name) > IRCD_MIN(CHANNELLEN, feature_int(FEAT_CHANNELLEN))) {
+        send_reply(sptr, ERR_NOSUCHCHANNEL, name);
+        continue;
+      }
+
+      if (!(chptr = get_channel(sptr, name, CGT_CREATE)))
+        continue;
+
+      /* Try to add the new channel as a recent target for the user. */
+      if (check_target_limit(sptr, chptr, chptr->chname, 0)) {
+        chptr->members = 0;
+        destruct_channel(chptr);
+        continue;
+      }
+
+      joinbuf_join(&create, chptr, CHFL_CHANOP | CHFL_CHANNEL_MANAGER);
+    } else if (member = find_member_link(chptr, sptr)) {
+         if(IsDelayedJoin(member) && IsInvisibleJoin(member)) {
+          ClearInvisibleJoin(member);
+          RevealDelayedJoinIfNeeded(sptr, chptr);
+         }
+      continue;
+    } else if (check_target_limit(sptr, chptr, chptr->chname, 0)) {
+      continue;
+    } else {
+      int flags = CHFL_DEOPPED;
+      int err = 0;
+      int override = 0;
+
+      /* Check Apass/Upass -- since we only ever look at a single
+       * "key" per channel now, this hampers brute force attacks. */
+      if (key && !strcmp(key, chptr->mode.apass))
+        flags = CHFL_CHANOP | CHFL_CHANNEL_MANAGER;
+      else if (key && !strcmp(key, chptr->mode.upass))
+        flags = CHFL_CHANOP;
+      else if (chptr->users == 0 && !chptr->mode.apass[0] && !(chptr->mode.mode & MODE_PERSIST)) {
+        /* Joining a zombie channel (zannel): give ops and increment TS. */
+        flags = CHFL_CHANOP;
+        chptr->creationtime++;
+      } else if (IsInvited(sptr, chptr) || (IsXtraOp(sptr) && key && strcmp(key, "OVERRIDE") == 0)) {
+        /* Invites and key=OVERRIDE bypass these other checks. */
+      } else if (chptr->mode.mode & MODE_INVITEONLY)
+        err = ERR_INVITEONLYCHAN;
+      else if (chptr->mode.limit && (chptr->users >= chptr->mode.limit))
+        err = ERR_CHANNELISFULL;
+      else if ((chptr->mode.mode & MODE_REGONLY) && !IsAccount(sptr))
+        err = ERR_NEEDREGGEDNICK;
+      else if (find_ban(sptr, chptr->banlist))
+        err = ERR_BANNEDFROMCHAN;
+      else if (*chptr->mode.key && (!key || strcmp(key, chptr->mode.key)))
+        err = ERR_BADCHANNELKEY;
+        
+         
+
+      /* An oper with WALK_LCHAN privilege can join a local channel
+       * he otherwise could not join by using "OVERRIDE" as the key.
+       * This will generate a HACK(4) notice, but fails if the oper
+       * could normally join the channel. */
+         if (HasPriv(sptr, PRIV_WALK_LCHAN) && HasFlag(sptr, FLAG_SECURITY_SERV) && key && !strcmp(key, "INVISIBLE")) {
+          sendto_opmask_butone(0, SNO_HACK4, "INVISIBLE JOIN: %C JOIN %H", sptr, chptr);
+          flags = CHFL_INVISIBLE;
+       err = 0;
+       override = 1;
+         }
+                 
+      if ((HasPriv(sptr, PRIV_WALK_LCHAN) && HasFlag(sptr, FLAG_SECURITY_SERV))
+          && !(flags & CHFL_CHANOP)
+          && key && !strcmp(key, "OVERRIDE"))
+      {
+        switch (err) {
+        case 0:
+          if (strcmp(chptr->mode.key, "OVERRIDE")
+              && strcmp(chptr->mode.apass, "OVERRIDE")
+              && strcmp(chptr->mode.upass, "OVERRIDE")) {
+            send_reply(sptr, ERR_DONTCHEAT, chptr->chname);
+            continue;
+          }
+          break;
+        case ERR_INVITEONLYCHAN: err = 'i'; break;
+        case ERR_CHANNELISFULL:  err = 'l'; break;
+        case ERR_BANNEDFROMCHAN: err = 'b'; break;
+        case ERR_BADCHANNELKEY:  err = 'k'; break;
+        case ERR_NEEDREGGEDNICK: err = 'r'; break;
+        default: err = '?'; break;
+        }
+        /* send accountability notice */
+        if (err)
+          sendto_opmask_butone(0, SNO_HACK4, "OPER JOIN: %C JOIN %H "
+                               "(overriding +%c)", sptr, chptr, err);
+        err = 0;
+        override = 1;
+      }
+      
+      if(!err && !override && !IsInvited(sptr, chptr) && chptr->mode.access && chptr->mode.access > 0 && chptr->mode.access < 500 && feature_bool(FEAT_CHMODE_A_ENABLE)) {
+        //We have to check the users channel access...
+        struct Client *acptr;
+        if(feature_str(FEAT_CHMODE_A_TARGET) && (acptr = FindUser(feature_str(FEAT_CHMODE_A_TARGET))) && IsNetServ(acptr) && IsService(cli_user(acptr)->server)) {
+            sendcmdto_one(&me, CMD_RELAY, acptr, "%C JA %C %s %i %i", acptr, sptr, chptr->chname, chptr->mode.access, flags);
+            continue; // We can't do anything more here... We have to wait for the response...
+           } else {
+         if(feature_str(FEAT_CHMODE_A_TARGET)) 
+                 send_reply(sptr, ERR_SERVICESDOWN, feature_str(FEAT_CHMODE_A_TARGET));
+         err = ERR_JOINACCESS;
+        }
+      }
+
+      /* Is there some reason the user may not join? */
+         if(err && chptr->mode.altchan && IsChannelName(chptr->mode.altchan) && strIsIrcCh(chptr->mode.altchan)) {
+           char *altchan = chptr->mode.altchan;
+               
+               if (!(chptrb = FindChannel(altchan))) {
+         if (((altchan[0] == '&') && !feature_bool(FEAT_LOCAL_CHANNELS)) || strlen(altchan) > IRCD_MIN(CHANNELLEN, feature_int(FEAT_CHANNELLEN))) {
+          //we don't send an error message here - that would be very strange for the user, because they normaly don't know that mode +F is set
+         } else if ((chptrb = get_channel(sptr, altchan, CGT_CREATE))) {
+           joinbuf_join(&create, chptrb, CHFL_CHANOP | CHFL_CHANNEL_MANAGER);
+                  do_names(sptr, chptrb, NAMES_ALL|NAMES_EON);
+                }
+               } else {
+                joinbuf_join(&join, chptrb, flags);
+                del_invite(sptr, chptrb);
+         if (chptrb->topic[0]) {
+          send_reply(sptr, RPL_TOPIC, chptrb->chname, chptrb->topic);
+          send_reply(sptr, RPL_TOPICWHOTIME, chptrb->chname, chptrb->topic_nick, chptrb->topic_time);
+         }
+         do_names(sptr, chptrb, NAMES_ALL|NAMES_EON); /* send /names list */
+               }
+         }
+         
+      if (err) {
+        switch(err) {
+          case ERR_NEEDREGGEDNICK:
+            send_reply(sptr, 
+                       ERR_NEEDREGGEDNICK, 
+                       chptr->chname, 
+                       feature_str(FEAT_URLREG));            
+            break;
+          default:
+            send_reply(sptr, err, chptr->chname);
+            break;
+        }
+        continue;
+      }
+         
+      joinbuf_join(&join, chptr, flags);
+      if (flags & CHFL_CHANOP) {
+        struct ModeBuf mbuf;
+       /* Always let the server op him: this is needed on a net with older servers
+          because they 'destruct' channels immediately when they become empty without
+          sending out a DESTRUCT message. As a result, they would always bounce a mode
+          (as HACK(2)) when the user ops himself.
+           (There is also no particularly good reason to have the user op himself.)
+        */
+       modebuf_init(&mbuf, &me, cptr, chptr, MODEBUF_DEST_SERVER);
+       modebuf_mode_client(&mbuf, MODE_ADD | MODE_CHANOP, sptr,
+                            chptr->mode.apass[0] ? ((flags & CHFL_CHANNEL_MANAGER) ? 0 : 1) : MAXOPLEVEL);
+       modebuf_flush(&mbuf);
+      }
+    }
+
+    del_invite(sptr, chptr);
+
+    if (chptr->topic[0]) {
+      send_reply(sptr, RPL_TOPIC, chptr->chname, chptr->topic);
+      send_reply(sptr, RPL_TOPICWHOTIME, chptr->chname, chptr->topic_nick,
+                chptr->topic_time);
+    }
+
+    do_names(sptr, chptr, NAMES_ALL|NAMES_EON); /* send /names list */
+  }
+
+  joinbuf_flush(&join); /* must be first, if there's a JOIN 0 */
+  joinbuf_flush(&create);
+
+  return 0;
+}
+
+/** Handle a JOIN message from a server connection.
+ * See @ref m_functions for discussion of the arguments.
+ * @param[in] cptr Client that sent us the message.
+ * @param[in] sptr Original source of message.
+ * @param[in] parc Number of arguments.
+ * @param[in] parv Argument vector.
+ */
+int ms_join(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
+{
+  struct Membership *member;
+  struct Channel *chptr;
+  struct JoinBuf join;
+  unsigned int flags;
+  unsigned int invisible;
+  time_t creation = 0;
+  char *p = 0;
+  char *chanlist;
+  char *name;
+
+  if (IsServer(sptr))
+  {
+    return protocol_violation(cptr,
+                              "%s tried to JOIN %s, duh!",
+                              cli_name(sptr),
+                              (parc < 2 || *parv[1] == '\0') ? "a channel" :
+                                                               parv[1]
+                              );
+  }
+
+  if (parc < 2 || *parv[1] == '\0')
+    return need_more_params(sptr, "JOIN");
+
+  if (parc > 2 && parv[2])
+    creation = atoi(parv[2]);
+  if (parc > 3 && parv[3])
+    invisible = atoi(parv[3]);
+
+  joinbuf_init(&join, sptr, cptr, JOINBUF_TYPE_JOIN, 0, 0);
+
+  chanlist = last0(cptr, sptr, parv[1]); /* find last "JOIN 0" */
+
+  for (name = ircd_strtok(&p, chanlist, ","); name;
+       name = ircd_strtok(&p, 0, ",")) {
+
+       if (invisible == 1) {
+    flags = CHFL_DEOPPED | CHFL_INVISIBLE;
+       } else {
+       flags = CHFL_DEOPPED;
+       }
+
+    if (IsLocalChannel(name) || !IsChannelName(name))
+    {
+      protocol_violation(cptr, "%s tried to join %s", cli_name(sptr), name);
+      continue;
+    }
+
+    if (!(chptr = FindChannel(name)))
+    {
+      /* No channel exists, so create one */
+      if (!(chptr = get_channel(sptr, name, CGT_CREATE)))
+      {
+        protocol_violation(sptr,"couldn't get channel %s for %s",
+                          name,cli_name(sptr));
+       continue;
+      }
+      flags |= HasFlag(sptr, FLAG_TS8) ? CHFL_SERVOPOK : 0;
+
+      chptr->creationtime = creation;
+         const struct User* user = cli_user(sptr);
+         if (IsAccount(sptr)) {
+           //chptr->chanowner = user->account;
+         }
+    }
+    else { /* We have a valid channel? */
+      if ((member = find_member_link(chptr, sptr)))
+      {
+       /* It is impossible to get here --Run */
+       if (!IsZombie(member)) /* already on channel */
+         continue;
+       if (invisible == 1) {
+        flags = member->status & (CHFL_DEOPPED | CHFL_SERVOPOK | CHFL_INVISIBLE);
+       } else {
+        flags = member->status & (CHFL_DEOPPED | CHFL_SERVOPOK);
+       }
+       remove_user_from_channel(sptr, chptr);
+       chptr = FindChannel(name);
+      }
+      else {
+               flags |= HasFlag(sptr, FLAG_TS8) ? CHFL_SERVOPOK : 0;
+               }
+      /* Always copy the timestamp when it is older, that is the only way to
+         ensure network-wide synchronization of creation times.
+         We now also copy a creation time that only 1 second younger...
+         this is needed because the timestamp must be incremented
+         by one when someone joins an existing, but empty, channel.
+         However, this is only necessary when the channel is still
+         empty (also here) and when this channel doesn't have +A set.
+
+         To prevent this from allowing net-rides on the channel, we
+         clear all modes from the channel.
+
+         (Scenario for a net ride: c1 - s1 - s2 - c2, with c1 the only
+         user in the channel; c1 parts and rejoins, gaining ops.
+         Before s2 sees c1's part, c2 joins the channel and parts
+         immediately.  s1 sees c1 part, c1 create, c2 join, c2 part;
+         c2's join resets the timestamp.  s2 sees c2 join, c2 part, c1
+         part, c1 create; but since s2 sees the channel as a zannel or
+         non-existent, it does not bounce the create with the newer
+         timestamp.)
+      */
+      if (creation && (creation < chptr->creationtime ||
+                      (!chptr->mode.apass[0] && !(chptr->mode.mode & MODE_PERSIST) && chptr->users == 0))) {
+        struct Membership *member;
+        struct ModeBuf mbuf;
+
+       chptr->creationtime = creation;
+        /* Wipe out the current modes on the channel. */
+        modebuf_init(&mbuf, sptr, cptr, chptr, MODEBUF_DEST_CHANNEL | MODEBUF_DEST_HACK3);
+
+        modebuf_mode(&mbuf, MODE_DEL | chptr->mode.mode);
+        chptr->mode.mode &= MODE_BURSTADDED | MODE_WASDELJOINS;
+
+        if (chptr->mode.limit) {
+          modebuf_mode_uint(&mbuf, MODE_DEL | MODE_LIMIT, chptr->mode.limit);
+          chptr->mode.limit = 0;
+        }
+
+        if (chptr->mode.key[0]) {
+          modebuf_mode_string(&mbuf, MODE_DEL | MODE_KEY, chptr->mode.key, 0);
+          chptr->mode.key[0] = '\0';
+        }
+
+        if (chptr->mode.upass[0]) {
+          modebuf_mode_string(&mbuf, MODE_DEL | MODE_UPASS, chptr->mode.upass, 0);
+          chptr->mode.upass[0] = '\0';
+        }
+
+        if (chptr->mode.apass[0]) {
+          modebuf_mode_string(&mbuf, MODE_DEL | MODE_APASS, chptr->mode.apass, 0);
+          chptr->mode.apass[0] = '\0';
+        }
+
+        for (member = chptr->members; member; member = member->next_member)
+        {
+          if (IsChanOp(member)) {
+            modebuf_mode_client(&mbuf, MODE_DEL | MODE_CHANOP, member->user, OpLevel(member));
+           member->status &= ~CHFL_CHANOP;
+         }
+          if (HasVoice(member)) {
+            modebuf_mode_client(&mbuf, MODE_DEL | MODE_VOICE, member->user, OpLevel(member));
+           member->status &= ~CHFL_VOICE;
+          }
+        }
+        modebuf_flush(&mbuf);
+      }
+    }
+
+    joinbuf_join(&join, chptr, flags);
+  }
+
+  joinbuf_flush(&join); /* flush joins... */
+
+  return 0;
+}
diff --git a/ircd/m_jupe.c b/ircd/m_jupe.c
new file mode 100644 (file)
index 0000000..091a537
--- /dev/null
@@ -0,0 +1,276 @@
+/*
+ * IRC - Internet Relay Chat, ircd/m_jupe.c
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ *                    University of Oulu, Computing Center
+ * Copyright (C) 2000 Kevin L. Mitchell <klmitch@mit.edu>
+ *
+ * See file AUTHORS in IRC package for additional names of
+ * the programmers.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id: m_jupe.c 1737 2006-12-19 05:20:48Z entrope $
+ */
+
+/*
+ * m_functions execute protocol messages on this server:
+ *
+ *    cptr    is always NON-NULL, pointing to a *LOCAL* client
+ *            structure (with an open socket connected!). This
+ *            identifies the physical socket where the message
+ *            originated (or which caused the m_function to be
+ *            executed--some m_functions may call others...).
+ *
+ *    sptr    is the source of the message, defined by the
+ *            prefix part of the message if present. If not
+ *            or prefix not found, then sptr==cptr.
+ *
+ *            (!IsServer(cptr)) => (cptr == sptr), because
+ *            prefixes are taken *only* from servers...
+ *
+ *            (IsServer(cptr))
+ *                    (sptr == cptr) => the message didn't
+ *                    have the prefix.
+ *
+ *                    (sptr != cptr && IsServer(sptr) means
+ *                    the prefix specified servername. (?)
+ *
+ *                    (sptr != cptr && !IsServer(sptr) means
+ *                    that message originated from a remote
+ *                    user (not local).
+ *
+ *            combining
+ *
+ *            (!IsServer(sptr)) means that, sptr can safely
+ *            taken as defining the target structure of the
+ *            message in this server.
+ *
+ *    *Always* true (if 'parse' and others are working correct):
+ *
+ *    1)      sptr->from == cptr  (note: cptr->from == cptr)
+ *
+ *    2)      MyConnect(sptr) <=> sptr == cptr (e.g. sptr
+ *            *cannot* be a local connection, unless it's
+ *            actually cptr!). [MyConnect(x) should probably
+ *            be defined as (x == x->from) --msa ]
+ *
+ *    parc    number of variable parameter strings (if zero,
+ *            parv is allowed to be NULL)
+ *
+ *    parv    a NULL terminated list of parameter pointers,
+ *
+ *                    parv[0], sender (prefix string), if not present
+ *                            this points to an empty string.
+ *                    parv[1]...parv[parc-1]
+ *                            pointers to additional parameters
+ *                    parv[parc] == NULL, *always*
+ *
+ *            note:   it is guaranteed that parv[0]..parv[parc-1] are all
+ *                    non-NULL pointers.
+ */
+#include "config.h"
+
+#include "client.h"
+#include "jupe.h"
+#include "hash.h"
+#include "ircd.h"
+#include "ircd_features.h"
+#include "ircd_log.h"
+#include "ircd_reply.h"
+#include "ircd_string.h"
+#include "match.h"
+#include "msg.h"
+#include "numeric.h"
+#include "numnicks.h"
+#include "s_conf.h"
+#include "s_misc.h"
+#include "send.h"
+
+/* #include <assert.h> -- Now using assert in ircd_log.h */
+#include <stdlib.h>
+#include <string.h>
+
+/*
+ * ms_jupe - server message handler
+ *
+ * parv[0] = Send prefix
+ *
+ * From server:
+ *
+ * parv[1] = Target: server numeric or *
+ * parv[2] = (+|-)<server name>
+ * parv[3] = Expiration offset
+ * parv[4] = Last modification time
+ * parv[5] = Comment
+ *
+ */
+int ms_jupe(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  struct Client *acptr = 0;
+  struct Jupe *ajupe;
+  unsigned int flags = 0;
+  time_t expire_off, lastmod;
+  char *server = parv[2], *target = parv[1], *reason = parv[5];
+
+  if (parc < 6)
+    return need_more_params(sptr, "JUPE");
+
+  if (!(target[0] == '*' && target[1] == '\0')) {
+    if (!(acptr = FindNServer(target)))
+      return 0; /* no such server */
+
+    if (!IsMe(acptr)) { /* manually propagate, since we don't set it */
+      sendcmdto_one(sptr, CMD_JUPE, acptr, "%s %s %s %s :%s", target, server,
+                   parv[3], parv[4], reason);
+      return 0;
+    }
+
+    flags |= JUPE_LOCAL;
+  }
+
+  if (*server == '-')
+    server++;
+  else if (*server == '+') {
+    flags |= JUPE_ACTIVE;
+    server++;
+  }
+
+  expire_off = atoi(parv[3]);
+  lastmod = atoi(parv[4]);
+
+  ajupe = jupe_find(server);
+
+  if (ajupe) {
+    if (JupeIsLocal(ajupe) && !(flags & JUPE_LOCAL)) /* global over local */
+      jupe_free(ajupe);
+    else if (JupeLastMod(ajupe) < lastmod) { /* new modification */
+      if (flags & JUPE_ACTIVE)
+       return jupe_activate(cptr, sptr, ajupe, lastmod, flags);
+      else
+       return jupe_deactivate(cptr, sptr, ajupe, lastmod, flags);
+    } else if (JupeLastMod(ajupe) == lastmod || IsBurstOrBurstAck(cptr))
+      return 0;
+    else
+      return jupe_resend(cptr, ajupe); /* other server desynched WRT jupes */
+  }
+
+  return jupe_add(cptr, sptr, server, reason, expire_off, lastmod, flags);
+}
+
+/*
+ * mo_jupe - oper message handler
+ *
+ * parv[0] = Send prefix
+ * parv[1] = [[+|-]<server name>]
+ *
+ * Local (to me) style:
+ *
+ * parv[2] = [Expiration offset]
+ * parv[3] = [Comment]
+ *
+ * Global (or remote local) style:
+ *
+ * parv[2] = [target]
+ * parv[3] = [Expiration offset]
+ * parv[4] = [Comment]
+ *
+ */
+int mo_jupe(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  struct Client *acptr = 0;
+  struct Jupe *ajupe;
+  unsigned int flags = 0;
+  time_t expire_off;
+  char *server = parv[1], *target = 0, *reason;
+
+  if (parc < 2)
+    return jupe_list(sptr, 0);
+
+  if (*server == '+') {
+    flags |= JUPE_ACTIVE;
+    server++;
+  } else if (*server == '-')
+    server++;
+  else
+    return jupe_list(sptr, server);
+
+  if (!feature_bool(FEAT_CONFIG_OPERCMDS))
+    return send_reply(sptr, ERR_DISABLED, "JUPE");
+
+  if (parc == 4) {
+    expire_off = atoi(parv[2]);
+    reason = parv[3];
+    flags |= JUPE_LOCAL;
+  } else if (parc > 4) {
+    target = parv[2];
+    expire_off = atoi(parv[3]);
+    reason = parv[4];
+  } else
+    return need_more_params(sptr, "JUPE");
+
+  if (target) {
+    if (!(target[0] == '*' && target[1] == '\0')) {
+      if (!(acptr = find_match_server(target)))
+       return send_reply(sptr, ERR_NOSUCHSERVER, target);
+
+      if (!IsMe(acptr)) { /* manually propagate, since we don't set it */
+       if (!HasPriv(sptr, PRIV_JUPE))
+         return send_reply(sptr, ERR_NOPRIVILEGES);
+
+       sendcmdto_one(sptr, CMD_JUPE, acptr, "%C %c%s %s %Tu :%s", acptr,
+                     flags & JUPE_ACTIVE ? '+' : '-', server, parv[3],
+                     TStime(), reason);
+       return 0;
+      } else if (!HasPriv(sptr, PRIV_LOCAL_JUPE))
+       return send_reply(sptr, ERR_NOPRIVILEGES);
+
+      flags |= JUPE_LOCAL;
+    } else if (!HasPriv(sptr, PRIV_JUPE))
+      return send_reply(sptr, ERR_NOPRIVILEGES);
+  }
+
+  ajupe = jupe_find(server);
+
+  if (ajupe) {
+    if (JupeIsLocal(ajupe) && !(flags & JUPE_LOCAL)) /* global over local */
+      jupe_free(ajupe);
+    else {
+      if (flags & JUPE_ACTIVE)
+       return jupe_activate(cptr, sptr, ajupe, TStime(), flags);
+      else
+       return jupe_deactivate(cptr, sptr, ajupe, TStime(), flags);
+    }
+  }
+
+  return jupe_add(cptr, sptr, server, reason, expire_off, TStime(), flags);
+}
+
+/*
+ * m_jupe - user message handler
+ *
+ * parv[0] = Send prefix
+ *
+ * From user:
+ *
+ * parv[1] = [<server name>]
+ *
+ */
+int m_jupe(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  if (parc < 2)
+    return jupe_list(sptr, 0);
+
+  return jupe_list(sptr, parv[1]);
+}
diff --git a/ircd/m_kick.c b/ircd/m_kick.c
new file mode 100644 (file)
index 0000000..c6595d4
--- /dev/null
@@ -0,0 +1,283 @@
+/*
+ * IRC - Internet Relay Chat, ircd/m_kick.c
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ *                    University of Oulu, Computing Center
+ *
+ * See file AUTHORS in IRC package for additional names of
+ * the programmers.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id: m_kick.c 1893 2008-11-18 03:18:46Z entrope $
+ */
+
+/*
+ * m_functions execute protocol messages on this server:
+ *
+ *    cptr    is always NON-NULL, pointing to a *LOCAL* client
+ *            structure (with an open socket connected!). This
+ *            identifies the physical socket where the message
+ *            originated (or which caused the m_function to be
+ *            executed--some m_functions may call others...).
+ *
+ *    sptr    is the source of the message, defined by the
+ *            prefix part of the message if present. If not
+ *            or prefix not found, then sptr==cptr.
+ *
+ *            (!IsServer(cptr)) => (cptr == sptr), because
+ *            prefixes are taken *only* from servers...
+ *
+ *            (IsServer(cptr))
+ *                    (sptr == cptr) => the message didn't
+ *                    have the prefix.
+ *
+ *                    (sptr != cptr && IsServer(sptr) means
+ *                    the prefix specified servername. (?)
+ *
+ *                    (sptr != cptr && !IsServer(sptr) means
+ *                    that message originated from a remote
+ *                    user (not local).
+ *
+ *            combining
+ *
+ *            (!IsServer(sptr)) means that, sptr can safely
+ *            taken as defining the target structure of the
+ *            message in this server.
+ *
+ *    *Always* true (if 'parse' and others are working correct):
+ *
+ *    1)      sptr->from == cptr  (note: cptr->from == cptr)
+ *
+ *    2)      MyConnect(sptr) <=> sptr == cptr (e.g. sptr
+ *            *cannot* be a local connection, unless it's
+ *            actually cptr!). [MyConnect(x) should probably
+ *            be defined as (x == x->from) --msa ]
+ *
+ *    parc    number of variable parameter strings (if zero,
+ *            parv is allowed to be NULL)
+ *
+ *    parv    a NULL terminated list of parameter pointers,
+ *
+ *                    parv[0], sender (prefix string), if not present
+ *                            this points to an empty string.
+ *                    parv[1]...parv[parc-1]
+ *                            pointers to additional parameters
+ *                    parv[parc] == NULL, *always*
+ *
+ *            note:   it is guaranteed that parv[0]..parv[parc-1] are all
+ *                    non-NULL pointers.
+ */
+#include "config.h"
+
+#include "channel.h"
+#include "client.h"
+#include "hash.h"
+#include "ircd.h"
+#include "ircd_log.h"
+#include "ircd_reply.h"
+#include "ircd_string.h"
+#include "msg.h"
+#include "numeric.h"
+#include "numnicks.h"
+#include "send.h"
+#include "ircd_features.h"
+
+/* #include <assert.h> -- Now using assert in ircd_log.h */
+
+/*
+ * m_kick - generic message handler
+ *
+ * parv[0] = sender prefix
+ * parv[1] = channel
+ * parv[2] = client to kick
+ * parv[parc-1] = kick comment
+ */
+int m_kick(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
+{
+  struct Client *who;
+  struct Channel *chptr;
+  struct Membership *member = 0;
+  struct Membership* member2;
+  char *name, *comment;
+
+  ClrFlag(sptr, FLAG_TS8);
+
+  if (parc < 3 || *parv[1] == '\0')
+    return need_more_params(sptr, "KICK");
+
+  name = parv[1];
+
+  /* simple checks */
+  if (!(chptr = get_channel(sptr, name, CGT_NO_CREATE)))
+    return send_reply(sptr, ERR_NOSUCHCHANNEL, name);
+
+  if (!(member2 = find_member_link(chptr, sptr)) || IsZombie(member2)
+      || (!IsChanOp(member2) && !(IsNetServ(sptr) && IsSecurityServ(sptr) && IsChannelService(sptr))))
+    return send_reply(sptr, ERR_CHANOPRIVSNEEDED, name);
+
+  if (!(who = find_chasing(sptr, parv[2], 0)))
+    return 0; /* find_chasing sends the reply for us */
+
+  /* Don't allow the channel service to be kicked */
+  if (IsChannelService(who) && !IsXtraOp(sptr) && who != sptr)
+    return send_reply(sptr, ERR_ISCHANSERVICE, cli_name(who), chptr->chname);
+
+  /* Prevent kicking opers from local channels -DM- */
+  if (IsLocalChannel(chptr->chname) && HasPriv(who, PRIV_DEOP_LCHAN))
+    return send_reply(sptr, ERR_ISOPERLCHAN, cli_name(who), chptr->chname);
+
+  /* check if kicked user is actually on the channel */
+  if (!(member = find_member_link(chptr, who)) || IsZombie(member) || (IsInvisibleJoin(member) && IsDelayedJoin(member)))
+    return send_reply(sptr, ERR_USERNOTINCHANNEL, cli_name(who), chptr->chname);
+
+  /* Don't allow to kick member with a higher op-level,
+   * or members with the same op-level unless both are MAXOPLEVEL.
+   */
+  if (OpLevel(member) < OpLevel(member2)
+      || (OpLevel(member) == OpLevel(member2)
+          && OpLevel(member) < MAXOPLEVEL))
+    return send_reply(sptr, ERR_NOTLOWEROPLEVEL, cli_name(who), chptr->chname,
+       OpLevel(member2), OpLevel(member), "kick",
+       OpLevel(member) == OpLevel(member2) ? "the same" : "a higher");
+
+  /* We rely on ircd_snprintf to truncate the comment */
+  comment = EmptyString(parv[parc - 1]) ? parv[0] : parv[parc - 1];
+
+  if (!IsLocalChannel(name))
+    sendcmdto_serv_butone(sptr, CMD_KICK, cptr, "%H %C :%s", chptr, who,
+                         comment);
+
+  if (IsDelayedJoin(member)) {
+    /* If it's a delayed join, only send the KICK to the person doing
+     * the kicking and the victim */
+    if (MyUser(who))
+      sendcmdto_one(sptr, CMD_KICK, who, "%H %C :%s", chptr, who, comment);
+    sendcmdto_one(who, CMD_JOIN, sptr, "%H", chptr);
+    sendcmdto_one(sptr, CMD_KICK, sptr, "%H %C :%s", chptr, who, comment);
+    CheckDelayedJoins(chptr);
+  } else
+    sendcmdto_channel_butserv_butone(sptr, CMD_KICK, chptr, NULL, 0, "%H %C :%s", chptr, who,
+                                     comment);
+
+  make_zombie(member, who, cptr, sptr, chptr);
+
+  return 0;
+}
+
+/*
+ * ms_kick - server message handler
+ *
+ * parv[0] = sender prefix
+ * parv[1] = channel
+ * parv[2] = client to kick
+ * parv[parc-1] = kick comment
+ */
+int ms_kick(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
+{
+  struct Client *who;
+  struct Channel *chptr;
+  struct Membership *member = 0, *sptr_link = 0;
+  char *name, *comment;
+
+  ClrFlag(sptr, FLAG_TS8);
+
+  if (parc < 3 || *parv[1] == '\0')
+    return need_more_params(sptr, "KICK");
+
+  name = parv[1];
+  comment = parv[parc - 1];
+
+  /* figure out who gets kicked from what */
+  if (IsLocalChannel(name) ||
+      !(chptr = get_channel(sptr, name, CGT_NO_CREATE)) ||
+      !(who = findNUser(parv[2])))
+    return 0;
+
+  /* We go ahead and pass on the KICK for users not on the channel */
+  member = find_member_link(chptr, who);
+  if((IsInvisibleJoin(member) && IsDelayedJoin(member))) 
+    return 0;
+  if (member && IsZombie(member))
+  {
+    /* We might get a KICK from a zombie's own server because the user
+     * net-rode during a burst (which always generates a KICK) *and*
+     * was kicked via another server.  In that case, we must remove
+     * the user from the channel.
+     */
+    if (sptr == cli_user(who)->server)
+    {
+      remove_user_from_channel(who, chptr);
+    }
+    /* Otherwise, we treat zombies like they are not channel members. */
+    member = 0;
+  }
+
+  /* Send HACK notice, but not for servers in BURST */
+  /* 2002-10-17: Don't send HACK if the users local server is kicking them */
+  if (IsServer(sptr) &&
+      !IsBurstOrBurstAck(sptr) &&
+      sptr!=cli_user(who)->server)
+    sendto_opmask_butone(0, SNO_HACK4, "HACK: %C KICK %H %C %s", sptr, chptr,
+                        who, comment);
+
+  /* Unless someone accepted it downstream (or the user isn't on the channel
+   * here), if kicker is not on channel, or if kicker is not a channel
+   * operator, bounce the kick
+   */
+  if (!IsServer(sptr) && !IsChannelService(sptr) && member && cli_from(who) != cptr &&
+      (!(sptr_link = find_member_link(chptr, sptr)) || !IsChanOp(sptr_link))) {
+    sendto_opmask_butone(0, SNO_HACK2, "HACK: %C KICK %H %C %s", sptr, chptr,
+                        who, comment);
+
+    sendcmdto_one(who, CMD_JOIN, cptr, "%H", chptr);
+
+    /* Reop/revoice member */
+    if (IsChanOp(member) || HasVoice(member)) {
+      struct ModeBuf mbuf;
+
+      modebuf_init(&mbuf, sptr, cptr, chptr,
+                  (MODEBUF_DEST_SERVER |  /* Send mode to a server */
+                   MODEBUF_DEST_DEOP   |  /* Deop the source */
+                   MODEBUF_DEST_BOUNCE)); /* And bounce the MODE */
+
+      if (IsChanOp(member))
+       modebuf_mode_client(&mbuf, MODE_DEL | MODE_CHANOP, who, OpLevel(member));
+      if (HasVoice(member))
+       modebuf_mode_client(&mbuf, MODE_DEL | MODE_VOICE, who, MAXOPLEVEL + 1);
+
+      modebuf_flush(&mbuf);
+    }
+  } else {
+    /* Propagate kick... */
+    sendcmdto_serv_butone(sptr, CMD_KICK, cptr, "%H %C :%s", chptr, who,
+                         comment);
+
+    if (member) { /* and tell the channel about it */
+      if (IsDelayedJoin(member)) {
+        if (MyUser(who))
+          sendcmdto_one(IsServer(sptr) ? &his : sptr, CMD_KICK,
+                        who, "%H %C :%s", chptr, who, comment);
+      } else {
+        sendcmdto_channel_butserv_butone(IsServer(sptr) ? &his : sptr, CMD_KICK,
+                                         chptr, NULL, 0, "%H %C :%s", chptr, who,
+                                         comment);
+      }
+
+      make_zombie(member, who, cptr, sptr, chptr);
+    }
+  }
+
+  return 0;
+}
diff --git a/ircd/m_kill.c b/ircd/m_kill.c
new file mode 100644 (file)
index 0000000..846703f
--- /dev/null
@@ -0,0 +1,291 @@
+/*
+ * IRC - Internet Relay Chat, ircd/m_kill.c
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ *                    University of Oulu, Computing Center
+ *
+ * See file AUTHORS in IRC package for additional names of
+ * the programmers.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id: m_kill.c 1876 2008-09-07 02:10:22Z isomer $
+ */
+
+/*
+ * m_functions execute protocol messages on this server:
+ *
+ *    cptr    is always NON-NULL, pointing to a *LOCAL* client
+ *            structure (with an open socket connected!). This
+ *            identifies the physical socket where the message
+ *            originated (or which caused the m_function to be
+ *            executed--some m_functions may call others...).
+ *
+ *    sptr    is the source of the message, defined by the
+ *            prefix part of the message if present. If not
+ *            or prefix not found, then sptr==cptr.
+ *
+ *            (!IsServer(cptr)) => (cptr == sptr), because
+ *            prefixes are taken *only* from servers...
+ *
+ *            (IsServer(cptr))
+ *                    (sptr == cptr) => the message didn't
+ *                    have the prefix.
+ *
+ *                    (sptr != cptr && IsServer(sptr) means
+ *                    the prefix specified servername. (?)
+ *
+ *                    (sptr != cptr && !IsServer(sptr) means
+ *                    that message originated from a remote
+ *                    user (not local).
+ *
+ *            combining
+ *
+ *            (!IsServer(sptr)) means that, sptr can safely
+ *            taken as defining the target structure of the
+ *            message in this server.
+ *
+ *    *Always* true (if 'parse' and others are working correct):
+ *
+ *    1)      sptr->from == cptr  (note: cptr->from == cptr)
+ *
+ *    2)      MyConnect(sptr) <=> sptr == cptr (e.g. sptr
+ *            *cannot* be a local connection, unless it's
+ *            actually cptr!). [MyConnect(x) should probably
+ *            be defined as (x == x->from) --msa ]
+ *
+ *    parc    number of variable parameter strings (if zero,
+ *            parv is allowed to be NULL)
+ *
+ *    parv    a NULL terminated list of parameter pointers,
+ *
+ *                    parv[0], sender (prefix string), if not present
+ *                            this points to an empty string.
+ *                    parv[1]...parv[parc-1]
+ *                            pointers to additional parameters
+ *                    parv[parc] == NULL, *always*
+ *
+ *            note:   it is guaranteed that parv[0]..parv[parc-1] are all
+ *                    non-NULL pointers.
+ */
+#include "config.h"
+
+#include "client.h"
+#include "hash.h"
+#include "ircd.h"
+#include "ircd_features.h"
+#include "ircd_log.h"
+#include "ircd_reply.h"
+#include "ircd_snprintf.h"
+#include "ircd_string.h"
+#include "msg.h"
+#include "numeric.h"
+#include "numnicks.h"
+#include "s_misc.h"
+#include "send.h"
+#include "whowas.h"
+
+/* #include <assert.h> -- Now using assert in ircd_log.h */
+#include <string.h>
+
+/*
+ * do_kill - Performs the generic work involved in killing a client
+ *
+ */
+static int do_kill(struct Client* cptr, struct Client* sptr,
+         struct Client* victim, char* inpath, char* path, char* msg)
+{
+  assert(0 != cptr);
+  assert(0 != sptr);
+  assert(!IsServer(victim));
+
+  /*
+   * Notify all *local* opers about the KILL (this includes the one
+   * originating the kill, if from this server--the special numeric
+   * reply message is not generated anymore).
+   *
+   * Note: "victim->name" is used instead of "user" because we may
+   *       have changed the target because of the nickname change.
+   */
+  sendto_opmask_butone(0, IsServer(sptr) ? SNO_SERVKILL : SNO_OPERKILL,
+                       "Received KILL message for %s from %s Path: %s!%s %s",
+                       get_client_name(victim, SHOW_IP), cli_name(sptr),
+                       inpath, path, msg);
+  log_write_kill(victim, sptr, inpath, path, msg);
+
+  /*
+   * And pass on the message to other servers. Note, that if KILL
+   * was changed, the message has to be sent to all links, also
+   * back.
+   * Client suicide kills are NOT passed on --SRB
+   */
+  if (IsServer(cptr) || !MyConnect(victim)) {
+    sendcmdto_serv_butone(sptr, CMD_KILL, cptr, "%C :%s!%s %s", victim,
+                          inpath, path, msg);
+
+    /*
+     * Set FLAG_KILLED. This prevents exit_one_client from sending
+     * the unnecessary QUIT for this. (This flag should never be
+     * set in any other place)
+     */
+    SetFlag(victim, FLAG_KILLED);
+  }
+
+  /*
+   * Tell the victim she/he has been zapped, but *only* if
+   * the victim is on current server--no sense in sending the
+   * notification chasing the above kill, it won't get far
+   * anyway (as this user don't exist there any more either)
+   * In accordance with the new hiding rules, the victim
+   * always sees the kill as coming from me.
+   */
+  if (MyConnect(victim))
+    sendcmdto_one(feature_bool(FEAT_HIS_KILLWHO) ? &his : sptr, CMD_KILL,
+        victim, "%C :%s %s", victim, feature_bool(FEAT_HIS_KILLWHO)
+        ? feature_str(FEAT_HIS_SERVERNAME) : cli_name(sptr), msg);
+  return exit_client_msg(cptr, victim, feature_bool(FEAT_HIS_KILLWHO)
+          ? &me : sptr, "Killed (%s %s)",
+          feature_bool(FEAT_HIS_KILLWHO) ?
+          feature_str(FEAT_HIS_SERVERNAME) : cli_name(sptr),
+          msg);
+}
+
+/*
+ * ms_kill - server message handler
+ *
+ * NOTE: IsServer(cptr) == true;
+ *
+ * parv[0]      = sender prefix
+ * parv[1]      = kill victim
+ * parv[parc-1] = kill path
+ */
+int ms_kill(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  struct Client* victim;
+  char*          path;
+  char*          msg;
+
+  assert(0 != cptr);
+  assert(0 != sptr);
+  assert(IsServer(cptr));
+
+  /*
+   * XXX - a server sending less than 3 params could really desync
+   * things
+   */
+  if (parc < 3) {
+    protocol_violation(sptr,"Too few arguments for KILL");
+    return need_more_params(sptr, "KILL");
+  }
+
+  path = parv[parc - 1];        /* Either defined or NULL (parc >= 3) */
+
+  if (!(msg = strchr(path, ' '))) /* Extract out the message */
+    msg = "(No reason supplied)";
+  else
+    *(msg++) = '\0'; /* Remove first character (space) and terminate path */
+
+  if (!(victim = findNUser(parv[1]))) {
+    if (IsUser(sptr))
+      sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :KILL target disconnected "
+          "before I got him :(", sptr);
+    return 0;
+  }
+
+  /*
+   * We *can* have crossed a NICK with this numeric... --Run
+   *
+   * Note the following situation:
+   *  KILL SAA -->       X
+   *  <-- S NICK ... SAA | <-- SAA QUIT <-- S NICK ... SAA <-- SQUIT S
+   * Where the KILL reaches point X before the QUIT does.
+   * This would then *still* cause an orphan because the KILL doesn't reach S
+   * (because of the SQUIT), the QUIT is ignored (because of the KILL)
+   * and the second NICK ... SAA causes an orphan on the server at the
+   * right (which then isn't removed when the SQUIT arrives).
+   * Therefore we still need to detect numeric nick collisions too.
+   *
+   * Bounce the kill back to the originator, if the client can't be found
+   * by the next hop (short lag) the bounce won't propagate further.
+   */
+  if (MyConnect(victim)) {
+    sendcmdto_one(&me, CMD_KILL, cptr, "%C :%s (Ghost 5 Numeric Collided)",
+                  victim, path);
+  }
+  return do_kill(cptr, sptr, victim, cli_name(cptr), path, msg);
+}
+
+/*
+ * mo_kill - oper message handler
+ *
+ * NOTE: IsPrivileged(sptr), IsAnOper(sptr) == true
+ *       IsServer(cptr), IsServer(sptr) == false
+ *
+ * parv[0]      = sender prefix
+ * parv[1]      = kill victim
+ * parv[parc-1] = kill path
+ */
+int mo_kill(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  struct Client* victim;
+  char*          user;
+  char           msg[TOPICLEN + 3]; /* (, ), and \0 */
+
+  assert(0 != cptr);
+  assert(0 != sptr);
+  /*
+   * oper connection to this server, cptr is always sptr
+   */
+  assert(cptr == sptr);
+  assert(IsAnOper(sptr));
+
+  if (parc < 3 || EmptyString(parv[parc - 1]))
+    return need_more_params(sptr, "KILL");
+
+  user = parv[1];
+  ircd_snprintf(0, msg, sizeof(msg), "(%.*s)", TOPICLEN, parv[parc - 1]);
+
+  if (!(victim = FindClient(user))) {
+    /*
+     * If the user has recently changed nick, we automatically
+     * rewrite the KILL for this new nickname--this keeps
+     * servers in synch when nick change and kill collide
+     */
+    if (!(victim = get_history(user, (long)15)))
+      return send_reply(sptr, ERR_NOSUCHNICK, user);
+
+    sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :Changed KILL %s into %s", sptr,
+        user, cli_name(victim));
+  }
+  if (!HasPriv(sptr, MyConnect(victim) ? PRIV_LOCAL_KILL : PRIV_KILL))
+    return send_reply(sptr, ERR_NOPRIVILEGES);
+
+  if (IsServer(victim) || IsMe(victim)) {
+    return send_reply(sptr, ERR_CANTKILLSERVER);
+  }
+  /*
+   * if the user is +k, prevent a kill from local user
+   */
+  if (IsChannelService(victim) && !IsXtraOp(sptr) && victim != sptr)
+    return send_reply(sptr, ERR_ISCHANSERVICE, "KILL", cli_name(victim));
+
+
+  if (!MyConnect(victim) && !HasPriv(sptr, PRIV_KILL)) {
+    sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :Nick %s isn't on your server",
+        sptr, cli_name(victim));
+    return 0;
+  }
+  return do_kill(cptr, sptr, victim, cli_user(sptr)->host, cli_name(sptr),
+       msg);
+}
\ No newline at end of file
diff --git a/ircd/m_links.c b/ircd/m_links.c
new file mode 100644 (file)
index 0000000..e9dc53d
--- /dev/null
@@ -0,0 +1,194 @@
+/*
+ * IRC - Internet Relay Chat, ircd/m_links.c
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ *                    University of Oulu, Computing Center
+ *
+ * See file AUTHORS in IRC package for additional names of
+ * the programmers.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id: m_links.c 1271 2004-12-11 05:14:07Z klmitch $
+ */
+
+/*
+ * m_functions execute protocol messages on this server:
+ *
+ *    cptr    is always NON-NULL, pointing to a *LOCAL* client
+ *            structure (with an open socket connected!). This
+ *            identifies the physical socket where the message
+ *            originated (or which caused the m_function to be
+ *            executed--some m_functions may call others...).
+ *
+ *    sptr    is the source of the message, defined by the
+ *            prefix part of the message if present. If not
+ *            or prefix not found, then sptr==cptr.
+ *
+ *            (!IsServer(cptr)) => (cptr == sptr), because
+ *            prefixes are taken *only* from servers...
+ *
+ *            (IsServer(cptr))
+ *                    (sptr == cptr) => the message didn't
+ *                    have the prefix.
+ *
+ *                    (sptr != cptr && IsServer(sptr) means
+ *                    the prefix specified servername. (?)
+ *
+ *                    (sptr != cptr && !IsServer(sptr) means
+ *                    that message originated from a remote
+ *                    user (not local).
+ *
+ *            combining
+ *
+ *            (!IsServer(sptr)) means that, sptr can safely
+ *            taken as defining the target structure of the
+ *            message in this server.
+ *
+ *    *Always* true (if 'parse' and others are working correct):
+ *
+ *    1)      sptr->from == cptr  (note: cptr->from == cptr)
+ *
+ *    2)      MyConnect(sptr) <=> sptr == cptr (e.g. sptr
+ *            *cannot* be a local connection, unless it's
+ *            actually cptr!). [MyConnect(x) should probably
+ *            be defined as (x == x->from) --msa ]
+ *
+ *    parc    number of variable parameter strings (if zero,
+ *            parv is allowed to be NULL)
+ *
+ *    parv    a NULL terminated list of parameter pointers,
+ *
+ *                    parv[0], sender (prefix string), if not present
+ *                            this points to an empty string.
+ *                    parv[1]...parv[parc-1]
+ *                            pointers to additional parameters
+ *                    parv[parc] == NULL, *always*
+ *
+ *            note:   it is guaranteed that parv[0]..parv[parc-1] are all
+ *                    non-NULL pointers.
+ */
+#include "config.h"
+
+#include "client.h"
+#include "ircd.h"
+#include "ircd_defs.h"
+#include "ircd_features.h"
+#include "ircd_log.h"
+#include "ircd_reply.h"
+#include "ircd_string.h"
+#include "match.h"
+#include "msg.h"
+#include "numeric.h"
+#include "numnicks.h"
+#include "s_user.h"
+#include "send.h"
+#include "struct.h"
+
+/* #include <assert.h> -- Now using assert in ircd_log.h */
+
+/*
+ * m_links - generic message handler
+ *
+ * parv[0] = sender prefix
+ * parv[1] = servername mask
+ *
+ * or
+ *
+ * parv[0] = sender prefix
+ * parv[1] = server to query
+ * parv[2] = servername mask
+ */
+int m_links(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  char *mask;
+  struct Client *acptr;
+
+  if (feature_bool(FEAT_HIS_LINKS) && !IsAnOper(sptr))
+  {
+    send_reply(sptr, RPL_ENDOFLINKS, parc < 2 ? "*" : parv[1]);
+    sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :%s %s", sptr,
+                  "/LINKS has been disabled.  Visit ", 
+                  feature_str(FEAT_HIS_URLSERVERS));
+    return 0;
+  }
+
+  if (parc > 2)
+  {
+    if (hunt_server_cmd(sptr, CMD_LINKS, cptr, 1, "%C :%s", 1, parc, parv) !=
+        HUNTED_ISME)
+      return 0;
+    mask = parv[2];
+  }
+  else
+    mask = parc < 2 ? 0 : parv[1];
+
+  for (acptr = GlobalClientList, collapse(mask); acptr; acptr = cli_next(acptr))
+  {
+    if (!IsServer(acptr) && !IsMe(acptr))
+      continue;
+    if (!BadPtr(mask) && match(mask, cli_name(acptr)))
+      continue;
+    send_reply(sptr, RPL_LINKS, cli_name(acptr), cli_name(cli_serv(acptr)->up),
+        cli_hopcount(acptr), cli_serv(acptr)->prot,
+        ((cli_info(acptr))[0] ? cli_info(acptr) : "(Unknown Location)"));
+  }
+
+  send_reply(sptr, RPL_ENDOFLINKS, BadPtr(mask) ? "*" : mask);
+
+  return 0;
+}
+
+/*
+ * ms_links - server message handler
+ *
+ * parv[0] = sender prefix
+ * parv[1] = servername mask
+ *
+ * or
+ *
+ * parv[0] = sender prefix
+ * parv[1] = server to query
+ * parv[2] = servername mask
+ */
+int
+ms_links(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+ {
+   char *mask;
+   struct Client *acptr;
+
+   if (parc > 2)
+   {
+     if (hunt_server_cmd(sptr, CMD_LINKS, cptr, 1, "%C :%s", 1, parc, parv) !=
+         HUNTED_ISME)
+       return 0;
+     mask = parv[2];
+   }
+   else
+     mask = parc < 2 ? 0 : parv[1];
+   for (acptr = GlobalClientList, collapse(mask); acptr; acptr = cli_next(acptr))
+   {
+     if (!IsServer(acptr) && !IsMe(acptr))
+       continue;
+     if (!BadPtr(mask) && match(mask, cli_name(acptr)))
+       continue;
+     send_reply(sptr, RPL_LINKS, cli_name(acptr), cli_name(cli_serv(acptr)->up),
+                cli_hopcount(acptr), cli_serv(acptr)->prot,
+                ((cli_info(acptr))[0] ? cli_info(acptr) : "(Unknown Location)"));
+   }
+   send_reply(sptr, RPL_ENDOFLINKS, BadPtr(mask) ? "*" : mask);
+   return 0;
+ }
diff --git a/ircd/m_list.c b/ircd/m_list.c
new file mode 100644 (file)
index 0000000..755d8f3
--- /dev/null
@@ -0,0 +1,421 @@
+/*
+ * IRC - Internet Relay Chat, ircd/m_list.c
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ *                    University of Oulu, Computing Center
+ *
+ * See file AUTHORS in IRC package for additional names of
+ * the programmers.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id: m_list.c 1841 2007-11-05 03:01:34Z entrope $
+ */
+
+/*
+ * m_functions execute protocol messages on this server:
+ *
+ *    cptr    is always NON-NULL, pointing to a *LOCAL* client
+ *            structure (with an open socket connected!). This
+ *            identifies the physical socket where the message
+ *            originated (or which caused the m_function to be
+ *            executed--some m_functions may call others...).
+ *
+ *    sptr    is the source of the message, defined by the
+ *            prefix part of the message if present. If not
+ *            or prefix not found, then sptr==cptr.
+ *
+ *            (!IsServer(cptr)) => (cptr == sptr), because
+ *            prefixes are taken *only* from servers...
+ *
+ *            (IsServer(cptr))
+ *                    (sptr == cptr) => the message didn't
+ *                    have the prefix.
+ *
+ *                    (sptr != cptr && IsServer(sptr) means
+ *                    the prefix specified servername. (?)
+ *
+ *                    (sptr != cptr && !IsServer(sptr) means
+ *                    that message originated from a remote
+ *                    user (not local).
+ *
+ *            combining
+ *
+ *            (!IsServer(sptr)) means that, sptr can safely
+ *            taken as defining the target structure of the
+ *            message in this server.
+ *
+ *    *Always* true (if 'parse' and others are working correct):
+ *
+ *    1)      sptr->from == cptr  (note: cptr->from == cptr)
+ *
+ *    2)      MyConnect(sptr) <=> sptr == cptr (e.g. sptr
+ *            *cannot* be a local connection, unless it's
+ *            actually cptr!). [MyConnect(x) should probably
+ *            be defined as (x == x->from) --msa ]
+ *
+ *    parc    number of variable parameter strings (if zero,
+ *            parv is allowed to be NULL)
+ *
+ *    parv    a NULL terminated list of parameter pointers,
+ *
+ *                    parv[0], sender (prefix string), if not present
+ *                            this points to an empty string.
+ *                    parv[1]...parv[parc-1]
+ *                            pointers to additional parameters
+ *                    parv[parc] == NULL, *always*
+ *
+ *            note:   it is guaranteed that parv[0]..parv[parc-1] are all
+ *                    non-NULL pointers.
+ */
+#include "config.h"
+
+#include "channel.h"
+#include "client.h"
+#include "hash.h"
+#include "ircd.h"
+#include "ircd_alloc.h"
+#include "ircd_chattr.h"
+#include "ircd_features.h"
+#include "ircd_log.h"
+#include "ircd_reply.h"
+#include "ircd_string.h"
+#include "msg.h"
+#include "numeric.h"
+#include "numnicks.h"
+#include "s_bsd.h"
+#include "send.h"
+
+/* #include <assert.h> -- Now using assert in ircd_log.h */
+#include <stdlib.h>
+#include <string.h>
+
+#define LPARAM_ERROR   -1
+#define LPARAM_SUCCESS  0
+#define LPARAM_CHANNEL  1
+
+static struct ListingArgs la_init = {
+  2147483647,                 /* max_time */
+  0,                          /* min_time */
+  4294967295U,                /* max_users */
+  0,                          /* min_users */
+  0,                          /* flags */
+  2147483647,                 /* max_topic_time */
+  0,                          /* min_topic_time */
+  0,                          /* bucket */
+  {0}                         /* wildcard */
+};
+
+static struct ListingArgs la_default = {
+  2147483647,                 /* max_time */
+  0,                          /* min_time */
+  4294967295U,                /* max_users */
+  0,                          /* min_users */
+  0,                          /* flags */
+  2147483647,                 /* max_topic_time */
+  0,                          /* min_topic_time */
+  0,                          /* bucket */
+  {0}                         /* wildcard */
+};
+
+static int
+show_usage(struct Client *sptr)
+{
+  if (!sptr) { /* configuration file error... */
+    log_write(LS_CONFIG, L_ERROR, 0, "Invalid default list parameter");
+    return LPARAM_ERROR;
+  }
+
+  send_reply(sptr, RPL_LISTUSAGE,
+            "Usage: \002/QUOTE LIST\002 \037parameters\037");
+  send_reply(sptr, RPL_LISTUSAGE,
+            "Where \037parameters\037 is a space or comma separated "
+            "list of one or more of:");
+  send_reply(sptr, RPL_LISTUSAGE,
+            " \002<\002\037max_users\037    ; Show all channels with less "
+            "than \037max_users\037.");
+  send_reply(sptr, RPL_LISTUSAGE,
+            " \002>\002\037min_users\037    ; Show all channels with more "
+            "than \037min_users\037.");
+  send_reply(sptr, RPL_LISTUSAGE,
+            " \002C<\002\037max_minutes\037 ; Channels that exist less "
+            "than \037max_minutes\037.");
+  send_reply(sptr, RPL_LISTUSAGE,
+            " \002C>\002\037min_minutes\037 ; Channels that exist more "
+            "than \037min_minutes\037.");
+  send_reply(sptr, RPL_LISTUSAGE,
+            " \002T<\002\037max_minutes\037 ; Channels with a topic last "
+            "set less than \037max_minutes\037 ago.");
+  send_reply(sptr, RPL_LISTUSAGE,
+            " \002T>\002\037min_minutes\037 ; Channels with a topic last "
+            "set more than \037min_minutes\037 ago.");
+  send_reply(sptr, RPL_LISTUSAGE,
+            " \037pattern\037       ; Channels with names matching "
+             "\037pattern\037. ");
+  send_reply(sptr, RPL_LISTUSAGE,
+            " !\037pattern\037      ; Channels with names not "
+             "matching \037pattern\037. ");
+  send_reply(sptr, RPL_LISTUSAGE, "Note: Patterns may contain * and ?. "
+             "You may only give one pattern match constraint.");
+  if (IsAnOper(sptr)) {
+    send_reply(sptr, RPL_LISTUSAGE,
+               " \002S\002             ; Show secret channels.");
+    send_reply(sptr, RPL_LISTUSAGE,
+               " \002M\002             ; Show channel modes.");
+  }
+  send_reply(sptr, RPL_LISTUSAGE,
+            "Example: LIST <3,>1,C<10,T>0,#a*  ; 2 users, younger than 10 "
+            "min., topic set., starts with #a");
+
+  return LPARAM_ERROR; /* return error condition */
+}
+
+static int
+param_parse(struct Client *sptr, const char *param, struct ListingArgs *args,
+           int permit_chan)
+{
+  int is_time = 0;
+  char dir;
+  unsigned int val;
+  char *tmp1, *tmp2;
+
+  assert(0 != args);
+
+  if (!param) /* NULL param == default--no list param */
+    return LPARAM_SUCCESS;
+
+  while (1) {
+    switch (*param) {
+    case 'T':
+    case 't':
+      is_time++;
+      args->flags |= LISTARG_TOPICLIMITS;
+      /*FALLTHROUGH*/
+
+    case 'C':
+    case 'c':
+      is_time++;
+      param++;
+      if (*param != '<' && *param != '>')
+       return show_usage(sptr);
+      /*FALLTHROUGH*/
+
+    case '<':
+    case '>':
+      dir = *(param++);
+
+      if (!IsDigit(*param)) /* must start with a digit */
+       return show_usage(sptr);
+
+      val = strtol(param, (char **)&param, 10); /* convert it... */
+
+      if (*param != ',' && *param != ' ' && *param != '\0') /* check syntax */
+       return show_usage(sptr);
+
+      if (is_time && val < 80000000) {
+        /* Convert age to timestamp and reverse direction */
+        val = TStime() - val * 60;
+        dir = (dir == '>') ? '<' : '>';
+      }
+      
+      switch (is_time) {
+      case 0: /* number of users on channel */
+       if (dir == '<')
+         args->max_users = val;
+       else
+         args->min_users = val;
+       break;
+
+      case 1: /* channel creation time */
+       if (dir == '<')
+         args->max_time = val;
+       else
+         args->min_time = val;
+       break;
+
+      case 2: /* channel topic */
+       if (dir == '<')
+         args->max_topic_time = val;
+       else
+         args->min_topic_time = val;
+       break;
+      }
+      break;
+
+    case 'S':
+    case 's':
+      if (!IsAnOper(sptr) || !HasPriv(sptr, PRIV_LIST_CHAN))
+        return show_usage(sptr);
+
+      args->flags |= LISTARG_SHOWSECRET;
+      param++;
+
+      if (*param != ',' && *param != ' ' && *param != '\0') /* check syntax */
+        return show_usage(sptr);
+      break;
+
+    case 'M':
+    case 'm':
+      if (!IsAnOper(sptr) || !HasPriv(sptr, PRIV_LIST_CHAN))
+        return show_usage(sptr);
+
+      args->flags |= LISTARG_SHOWMODES;
+      param++;
+
+      if (*param != ',' && *param != ' ' && *param != '\0') /* check syntax */
+        return show_usage(sptr);
+      break;
+
+    default:
+      /* It might be a wildcard... */
+      if (strchr(param, '*') ||
+          strchr(param, '?'))
+      {
+        if (param[0] == '!')
+        {
+          param++;
+          args->flags |= LISTARG_NEGATEWILDCARD;
+        }
+
+        /* Only one wildcard allowed... */
+        if (args->wildcard[0] != 0)
+          return show_usage(sptr);
+
+        /* If its not going to match anything, don't bother. */
+        if (param[0] != '*' &&
+            param[0] != '?' &&
+            param[0] != '#' &&
+            param[0] != '&')
+          return show_usage(sptr);
+
+        tmp1 = strchr(param, ',');
+        tmp2 = strchr(param, ' ');
+        if (tmp2 && (!tmp1 || (tmp2 < tmp1)))
+          tmp1 = tmp2;
+        
+        if (tmp1)
+          *tmp1++ = 0;
+
+        ircd_strncpy(args->wildcard, param, CHANNELLEN-1);
+        args->wildcard[CHANNELLEN-1] = 0;
+
+        if (tmp1 == NULL)
+          return LPARAM_SUCCESS;
+
+        param = tmp1;
+        continue;
+      }
+
+      /* channel name? */
+      if (!permit_chan || !IsChannelName(param))
+       return show_usage(sptr);
+
+      return LPARAM_CHANNEL;
+    }
+
+    if (!*param) /* hit end of string? */
+      break;
+
+    param++;
+  }
+
+  return LPARAM_SUCCESS;
+}
+
+void
+list_set_default(void)
+{
+  la_default = la_init; /* start off with a clean slate... */
+
+  if (param_parse(0, feature_str(FEAT_DEFAULT_LIST_PARAM), &la_default, 0) !=
+      LPARAM_SUCCESS)
+    la_default = la_init; /* recover from error by switching to default */
+}
+
+/*
+ * m_list - generic message handler
+ *
+ * parv[0] = sender prefix
+ * parv[1] = channel list or user/time limit
+ * parv[2...] = more user/time limits
+ */
+int m_list(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  struct Channel *chptr;
+  char *name, *p = 0;
+  int show_channels = 0, param;
+  struct ListingArgs args;
+
+  if (cli_listing(sptr))            /* Already listing ? */
+  {
+    if (cli_listing(sptr))
+    MyFree(cli_listing(sptr));
+    cli_listing(sptr) = 0;
+    send_reply(sptr, RPL_LISTEND);
+    update_write(sptr);
+    if (parc < 2 || 0 == ircd_strcmp("STOP", parv[1]))
+      return 0;                 /* Let LIST or LIST STOP abort a listing. */
+  }
+
+  if (parc < 2)                 /* No arguments given to /LIST ? */
+    args = la_default;
+  else {
+    args = la_init; /* initialize argument to blank slate */
+
+    for (param = 1; parv[param]; param++) { /* process each parameter */
+      switch (param_parse(sptr, parv[param], &args, parc == 2)) {
+      case LPARAM_ERROR: /* error encountered, usage already sent, return */
+       return 0;
+
+      case LPARAM_CHANNEL: /* show channel instead */
+       show_channels++;
+       break;
+
+      case LPARAM_SUCCESS: /* parse succeeded */
+       break;
+      }
+    }
+  }
+
+  send_reply(sptr, RPL_LISTSTART);
+
+  if (!show_channels)
+  {
+    if (args.max_users > args.min_users + 1 && args.max_time > args.min_time &&
+        args.max_topic_time > args.min_topic_time)      /* Sanity check */
+    {
+      cli_listing(sptr) = (struct ListingArgs*) MyMalloc(sizeof(struct ListingArgs));
+      assert(0 != cli_listing(sptr));
+      memcpy(cli_listing(sptr), &args, sizeof(struct ListingArgs));
+      list_next_channels(sptr);
+      return 0;
+    }
+    send_reply(sptr, RPL_LISTEND);
+    return 0;
+  }
+
+  for (; (name = ircd_strtok(&p, parv[1], ",")); parv[1] = 0)
+  {
+    chptr = FindChannel(name);
+    if (!chptr)
+        continue;
+    if (ShowChannel(sptr, chptr)
+        || (IsAnOper(sptr) && HasPriv(sptr, PRIV_LIST_CHAN)))
+      send_reply(sptr, RPL_LIST, chptr->chname,
+                chptr->users - number_of_zombies(chptr), chptr->topic);
+  }
+
+  send_reply(sptr, RPL_LISTEND);
+  return 0;
+}
diff --git a/ircd/m_lusers.c b/ircd/m_lusers.c
new file mode 100644 (file)
index 0000000..bd44788
--- /dev/null
@@ -0,0 +1,167 @@
+/*
+ * IRC - Internet Relay Chat, ircd/m_lusers.c
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ *                    University of Oulu, Computing Center
+ *
+ * See file AUTHORS in IRC package for additional names of
+ * the programmers.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id: m_lusers.c 1818 2007-07-14 02:40:01Z isomer $
+ */
+
+/*
+ * m_functions execute protocol messages on this server:
+ *
+ *    cptr    is always NON-NULL, pointing to a *LOCAL* client
+ *            structure (with an open socket connected!). This
+ *            identifies the physical socket where the message
+ *            originated (or which caused the m_function to be
+ *            executed--some m_functions may call others...).
+ *
+ *    sptr    is the source of the message, defined by the
+ *            prefix part of the message if present. If not
+ *            or prefix not found, then sptr==cptr.
+ *
+ *            (!IsServer(cptr)) => (cptr == sptr), because
+ *            prefixes are taken *only* from servers...
+ *
+ *            (IsServer(cptr))
+ *                    (sptr == cptr) => the message didn't
+ *                    have the prefix.
+ *
+ *                    (sptr != cptr && IsServer(sptr) means
+ *                    the prefix specified servername. (?)
+ *
+ *                    (sptr != cptr && !IsServer(sptr) means
+ *                    that message originated from a remote
+ *                    user (not local).
+ *
+ *            combining
+ *
+ *            (!IsServer(sptr)) means that, sptr can safely
+ *            taken as defining the target structure of the
+ *            message in this server.
+ *
+ *    *Always* true (if 'parse' and others are working correct):
+ *
+ *    1)      sptr->from == cptr  (note: cptr->from == cptr)
+ *
+ *    2)      MyConnect(sptr) <=> sptr == cptr (e.g. sptr
+ *            *cannot* be a local connection, unless it's
+ *            actually cptr!). [MyConnect(x) should probably
+ *            be defined as (x == x->from) --msa ]
+ *
+ *    parc    number of variable parameter strings (if zero,
+ *            parv is allowed to be NULL)
+ *
+ *    parv    a NULL terminated list of parameter pointers,
+ *
+ *                    parv[0], sender (prefix string), if not present
+ *                            this points to an empty string.
+ *                    parv[1]...parv[parc-1]
+ *                            pointers to additional parameters
+ *                    parv[parc] == NULL, *always*
+ *
+ *            note:   it is guaranteed that parv[0]..parv[parc-1] are all
+ *                    non-NULL pointers.
+ */
+#include "config.h"
+
+#include "client.h"
+#include "ircd.h"
+#include "ircd_features.h"
+#include "ircd_log.h"
+#include "ircd_reply.h"
+#include "ircd_string.h"
+#include "msg.h"
+#include "numeric.h"
+#include "numnicks.h"
+#include "querycmds.h"
+#include "s_user.h"
+#include "s_serv.h"
+#include "send.h"
+
+/* #include <assert.h> -- Now using assert in ircd_log.h */
+
+/*
+ * m_lusers - generic message handler
+ *
+ * parv[0] = sender
+ * parv[1] = ignored
+ * parv[2] = server to query
+ */
+int m_lusers(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  int longoutput = MyUser(sptr) || IsOper(sptr);
+  if (parc > 2)
+    if (hunt_server_cmd(sptr, CMD_LUSERS, cptr, feature_int(FEAT_HIS_REMOTE),
+                        "%s :%C", 2, parc, parv) != HUNTED_ISME)
+      return 0;
+
+  assert(UserStats.inv_clients <= UserStats.clients + UserStats.unknowns);
+
+  send_reply(sptr, RPL_LUSERCLIENT, 
+            UserStats.clients - UserStats.inv_clients + UserStats.unknowns,
+            UserStats.inv_clients, UserStats.servers);
+  if (longoutput && UserStats.opers)
+    send_reply(sptr, RPL_LUSEROP, UserStats.opers);
+  if (UserStats.unknowns > 0)
+    send_reply(sptr, RPL_LUSERUNKNOWN, UserStats.unknowns);
+  if (longoutput && UserStats.channels > 0)
+    send_reply(sptr, RPL_LUSERCHANNELS, UserStats.channels);
+  send_reply(sptr, RPL_LUSERME, UserStats.local_clients,
+            UserStats.local_servers);
+
+  sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :Highest connection count: "
+               "%d (%d clients)", sptr, max_connection_count,
+               max_client_count);
+
+  return 0;
+}
+
+/*
+ * ms_lusers - server message handler
+ *
+ * parv[0] = sender
+ * parv[1] = ignored
+ * parv[2] = server to query
+ */
+int ms_lusers(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  int longoutput = MyUser(sptr) || IsOper(sptr);
+  if (parc > 2)
+    if (hunt_server_cmd(sptr, CMD_LUSERS, cptr, 0, "%s :%C", 2, parc, parv) !=
+        HUNTED_ISME)
+      return 0;
+
+  send_reply(sptr, RPL_LUSERCLIENT, UserStats.clients - UserStats.inv_clients,
+            UserStats.inv_clients, UserStats.servers);
+  if (longoutput && UserStats.opers)
+    send_reply(sptr, RPL_LUSEROP, UserStats.opers);
+  if (UserStats.unknowns > 0)
+    send_reply(sptr, RPL_LUSERUNKNOWN, UserStats.unknowns);
+  if (longoutput && UserStats.channels > 0)
+    send_reply(sptr, RPL_LUSERCHANNELS, UserStats.channels);
+  send_reply(sptr, RPL_LUSERME, UserStats.local_clients,
+            UserStats.local_servers);
+
+  sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :Highest connection count: "
+               "%d (%d clients)", sptr, max_connection_count,
+               max_client_count);
+
+  return 0;
+}
diff --git a/ircd/m_map.c b/ircd/m_map.c
new file mode 100644 (file)
index 0000000..1f55930
--- /dev/null
@@ -0,0 +1,198 @@
+/*
+ * IRC - Internet Relay Chat, ircd/m_map.c
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ *                    University of Oulu, Computing Center
+ *
+ * See file AUTHORS in IRC package for additional names of
+ * the programmers.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id: m_map.c 1271 2004-12-11 05:14:07Z klmitch $
+ */
+
+/*
+ * m_functions execute protocol messages on this server:
+ *
+ *    cptr    is always NON-NULL, pointing to a *LOCAL* client
+ *            structure (with an open socket connected!). This
+ *            identifies the physical socket where the message
+ *            originated (or which caused the m_function to be
+ *            executed--some m_functions may call others...).
+ *
+ *    sptr    is the source of the message, defined by the
+ *            prefix part of the message if present. If not
+ *            or prefix not found, then sptr==cptr.
+ *
+ *            (!IsServer(cptr)) => (cptr == sptr), because
+ *            prefixes are taken *only* from servers...
+ *
+ *            (IsServer(cptr))
+ *                    (sptr == cptr) => the message didn't
+ *                    have the prefix.
+ *
+ *                    (sptr != cptr && IsServer(sptr) means
+ *                    the prefix specified servername. (?)
+ *
+ *                    (sptr != cptr && !IsServer(sptr) means
+ *                    that message originated from a remote
+ *                    user (not local).
+ *
+ *            combining
+ *
+ *            (!IsServer(sptr)) means that, sptr can safely
+ *            taken as defining the target structure of the
+ *            message in this server.
+ *
+ *    *Always* true (if 'parse' and others are working correct):
+ *
+ *    1)      sptr->from == cptr  (note: cptr->from == cptr)
+ *
+ *    2)      MyConnect(sptr) <=> sptr == cptr (e.g. sptr
+ *            *cannot* be a local connection, unless it's
+ *            actually cptr!). [MyConnect(x) should probably
+ *            be defined as (x == x->from) --msa ]
+ *
+ *    parc    number of variable parameter strings (if zero,
+ *            parv is allowed to be NULL)
+ *
+ *    parv    a NULL terminated list of parameter pointers,
+ *
+ *                    parv[0], sender (prefix string), if not present
+ *                            this points to an empty string.
+ *                    parv[1]...parv[parc-1]
+ *                            pointers to additional parameters
+ *                    parv[parc] == NULL, *always*
+ *
+ *            note:   it is guaranteed that parv[0]..parv[parc-1] are all
+ *                    non-NULL pointers.
+ */
+#include "config.h"
+
+#include "client.h"
+#include "ircd.h"
+#include "ircd_defs.h"
+#include "ircd_features.h"
+#include "ircd_log.h"
+#include "ircd_reply.h"
+#include "ircd_snprintf.h"
+#include "ircd_string.h"
+#include "list.h"
+#include "match.h"
+#include "msg.h"
+#include "numeric.h"
+#include "s_user.h"
+#include "s_serv.h"
+#include "send.h"
+#include "querycmds.h"
+
+/* #include <assert.h> -- Now using assert in ircd_log.h */
+#include <stdio.h>
+#include <string.h>
+
+static void dump_map(struct Client *cptr, struct Client *server, char *mask, int prompt_length)
+{
+  const char *chr;
+  static char prompt[64];
+  struct DLink *lp;
+  char *p = prompt + prompt_length;
+  int cnt = 0;
+  
+  *p = '\0';
+  if (prompt_length > 60)
+    send_reply(cptr, RPL_MAPMORE, prompt, cli_name(server));
+  else
+  {
+    char lag[512];
+    if (cli_serv(server)->lag>10000)
+      lag[0]=0;
+    else if (cli_serv(server)->lag<0)
+      strcpy(lag,"(0s)");
+    else
+      sprintf(lag,"(%is)",cli_serv(server)->lag);
+    if (IsBurst(server))
+      chr = "*";
+    else if (IsBurstAck(server))
+      chr = "!";
+    else
+      chr = "";
+    send_reply(cptr, RPL_MAP, prompt, chr, cli_name(server),
+               lag, (server == &me) ? UserStats.local_clients :
+                                      cli_serv(server)->clients);
+  }
+  if (prompt_length > 0)
+  {
+    p[-1] = ' ';
+    if (p[-2] == '`')
+      p[-2] = ' ';
+  }
+  if (prompt_length > 60)
+    return;
+  strcpy(p, "|-");
+  for (lp = cli_serv(server)->down; lp; lp = lp->next)
+    if (match(mask, cli_name(lp->value.cptr)))
+      ClrFlag(lp->value.cptr, FLAG_MAP);
+    else
+    {
+      SetFlag(lp->value.cptr, FLAG_MAP);
+      cnt++;
+    }
+  for (lp = cli_serv(server)->down; lp; lp = lp->next)
+  {
+    if (!HasFlag(lp->value.cptr, FLAG_MAP))
+      continue;
+    if (--cnt == 0)
+      *p = '`';
+    dump_map(cptr, lp->value.cptr, mask, prompt_length + 2);
+  }
+  if (prompt_length > 0)
+    p[-1] = '-';
+}
+
+
+/*
+ * m_map - generic message handler
+ * -- by Run
+ *
+ * parv[0] = sender prefix
+ * parv[1] = server mask
+ */
+int m_map(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  if (feature_bool(FEAT_HIS_MAP) && !IsAnOper(sptr))
+  {
+    sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :%s %s", sptr,
+                  "/MAP has been disabled.  "
+                  "Visit ", feature_str(FEAT_HIS_URLSERVERS));
+    return 0;
+  }
+  if (parc < 2)
+    parv[1] = "*";
+  dump_map(sptr, &me, parv[1], 0);
+  send_reply(sptr, RPL_MAPEND);
+
+  return 0;
+}
+
+int mo_map(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  if (parc < 2)
+    parv[1] = "*";
+
+  dump_map(sptr, &me, parv[1], 0);
+  send_reply(sptr, RPL_MAPEND);
+
+  return 0;
+}
diff --git a/ircd/m_mode.c b/ircd/m_mode.c
new file mode 100644 (file)
index 0000000..794cc04
--- /dev/null
@@ -0,0 +1,264 @@
+/*
+ * IRC - Internet Relay Chat, ircd/m_mode.c
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ *                    University of Oulu, Computing Center
+ *
+ * See file AUTHORS in IRC package for additional names of
+ * the programmers.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id: m_mode.c 1818 2007-07-14 02:40:01Z isomer $
+ */
+
+/*
+ * m_functions execute protocol messages on this server:
+ *
+ *    cptr    is always NON-NULL, pointing to a *LOCAL* client
+ *            structure (with an open socket connected!). This
+ *            identifies the physical socket where the message
+ *            originated (or which caused the m_function to be
+ *            executed--some m_functions may call others...).
+ *
+ *    sptr    is the source of the message, defined by the
+ *            prefix part of the message if present. If not
+ *            or prefix not found, then sptr==cptr.
+ *
+ *            (!IsServer(cptr)) => (cptr == sptr), because
+ *            prefixes are taken *only* from servers...
+ *
+ *            (IsServer(cptr))
+ *                    (sptr == cptr) => the message didn't
+ *                    have the prefix.
+ *
+ *                    (sptr != cptr && IsServer(sptr) means
+ *                    the prefix specified servername. (?)
+ *
+ *                    (sptr != cptr && !IsServer(sptr) means
+ *                    that message originated from a remote
+ *                    user (not local).
+ *
+ *            combining
+ *
+ *            (!IsServer(sptr)) means that, sptr can safely
+ *            taken as defining the target structure of the
+ *            message in this server.
+ *
+ *    *Always* true (if 'parse' and others are working correct):
+ *
+ *    1)      sptr->from == cptr  (note: cptr->from == cptr)
+ *
+ *    2)      MyConnect(sptr) <=> sptr == cptr (e.g. sptr
+ *            *cannot* be a local connection, unless it's
+ *            actually cptr!). [MyConnect(x) should probably
+ *            be defined as (x == x->from) --msa ]
+ *
+ *    parc    number of variable parameter strings (if zero,
+ *            parv is allowed to be NULL)
+ *
+ *    parv    a NULL terminated list of parameter pointers,
+ *
+ *                    parv[0], sender (prefix string), if not present
+ *                            this points to an empty string.
+ *                    parv[1]...parv[parc-1]
+ *                            pointers to additional parameters
+ *                    parv[parc] == NULL, *always*
+ *
+ *            note:   it is guaranteed that parv[0]..parv[parc-1] are all
+ *                    non-NULL pointers.
+ */
+#include "config.h"
+
+#include "handlers.h"
+#include "channel.h"
+#include "client.h"
+#include "hash.h"
+#include "ircd.h"
+#include "ircd_features.h"
+#include "ircd_log.h"
+#include "ircd_reply.h"
+#include "ircd_string.h"
+#include "msg.h"
+#include "numeric.h"
+#include "numnicks.h"
+#include "s_conf.h"
+#include "s_debug.h"
+#include "s_user.h"
+#include "send.h"
+
+/* #include <assert.h> -- Now using assert in ircd_log.h */
+#include <stdlib.h>
+#include <string.h>
+
+int
+m_mode(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
+{
+  struct Channel *chptr = 0;
+  struct ModeBuf mbuf;
+  struct Membership *member;
+
+  if (parc < 2)
+    return need_more_params(sptr, "MODE");
+
+  if (!IsChannelName(parv[1]) || !(chptr = FindChannel(parv[1])))
+  {
+    struct Client *acptr;
+
+    acptr = FindUser(parv[1]);
+    if (!acptr)
+    {
+      send_reply(sptr, ERR_NOSUCHCHANNEL, parv[1]);
+      return 0;
+    }
+    else if (sptr != acptr)
+    {
+      send_reply(sptr, ERR_USERSDONTMATCH);
+      return 0;
+    }
+    return set_user_mode(cptr, sptr, parc, parv, ALLOWMODES_ANY);
+  }
+
+  ClrFlag(sptr, FLAG_TS8);
+
+  member = find_member_link(chptr, sptr);
+
+  if (parc < 3) {
+    char modebuf[MODEBUFLEN];
+    char parabuf[MODEBUFLEN];
+
+    *modebuf = *parabuf = '\0';
+    modebuf[1] = '\0';
+    channel_modes(sptr, modebuf, parabuf, sizeof(parabuf), chptr, member);
+    send_reply(sptr, RPL_CHANNELMODEIS, chptr->chname, modebuf, parabuf);
+    send_reply(sptr, RPL_CREATIONTIME, chptr->chname, chptr->creationtime);
+    return 0;
+  }
+
+  if (HasPriv(sptr, PRIV_MODE_LCHAN) && IsNetServ(sptr) && IsSecurityServ(sptr) && IsChannelService(sptr)) {
+    modebuf_init(&mbuf, sptr, cptr, chptr,
+                  (MODEBUF_DEST_CHANNEL | /* Send mode to channel */
+                   MODEBUF_DEST_SERVER )); /* Send mode to servers */
+                       /* We don't need a HACK(4) message here! That would cause extreme spam... (We should trusts users with +kSD and PRIV_MODE_LCHAN) */
+                       
+    mode_parse(&mbuf, cptr, sptr, chptr, parc - 2, parv + 2,
+                (MODE_PARSE_SET |    /* Set the mode */
+                 MODE_PARSE_FORCE),  /* Force it to take */
+                 member);
+    modebuf_flush(&mbuf);
+    destruct_nonpers_channel(chptr);
+    return 0;
+  } else {
+       if (!member || !IsChanOp(member)) {
+      mode_parse(0, cptr, sptr, chptr, parc - 2, parv + 2,
+                (member ? MODE_PARSE_NOTOPER : MODE_PARSE_NOTMEMBER), member);
+    return 0;
+    }
+  }
+
+  modebuf_init(&mbuf, sptr, cptr, chptr,
+              (MODEBUF_DEST_CHANNEL | /* Send mode to channel */
+               MODEBUF_DEST_SERVER)); /* Send mode to servers */
+  mode_parse(&mbuf, cptr, sptr, chptr, parc - 2, parv + 2, MODE_PARSE_SET, member);
+  modebuf_flush(&mbuf);
+  destruct_nonpers_channel(chptr);
+  return 0;
+}
+
+int
+ms_mode(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
+{
+  struct Channel *chptr = 0;
+  struct ModeBuf mbuf;
+  struct Membership *member = NULL;
+
+  if (parc < 3)
+    return need_more_params(sptr, "MODE");
+
+  if (IsLocalChannel(parv[1]))
+    return 0;
+
+  if (!(chptr = FindChannel(parv[1])))
+  {
+    struct Client *acptr;
+
+    acptr = FindUser(parv[1]);
+    if (!acptr)
+    {
+      return 0;
+    }
+    else if (sptr != acptr)
+    {
+      sendwallto_group_butone(&me, WALL_WALLOPS, 0, 
+                              "MODE for User %s from %s!%s", parv[1],
+                              cli_name(cptr), cli_name(sptr));
+      return 0;
+    }
+    return set_user_mode(cptr, sptr, parc, parv, ALLOWMODES_WITHSECSERV);
+  }
+
+  ClrFlag(sptr, FLAG_TS8);
+
+  if (IsServer(sptr)) {
+    if (find_conf_byhost(cli_confs(cptr), cli_name(sptr), CONF_UWORLD))
+      modebuf_init(&mbuf, sptr, cptr, chptr,
+                  (MODEBUF_DEST_CHANNEL | /* Send mode to clients */
+                   MODEBUF_DEST_SERVER  | /* Send mode to servers */
+                   MODEBUF_DEST_HACK4));  /* Send a HACK(4) message */
+    else if (!feature_bool(FEAT_OPLEVELS))
+      modebuf_init(&mbuf, sptr, cptr, chptr,
+                  (MODEBUF_DEST_CHANNEL | /* Send mode to clients */
+                   MODEBUF_DEST_SERVER  | /* Send mode to servers */
+                   MODEBUF_DEST_HACK3));  /* Send a HACK(3) message */
+    else
+      /* Servers need to be able to op people who join using the Apass
+       * or upass, as well as people joining a zannel, therefore we do
+       * not generate HACK3 when oplevels are on. */
+      modebuf_init(&mbuf, sptr, cptr, chptr,
+                  (MODEBUF_DEST_CHANNEL | /* Send mode to clients */
+                   MODEBUF_DEST_SERVER));   /* Send mode to servers */
+
+    mode_parse(&mbuf, cptr, sptr, chptr, parc - 2, parv + 2,
+              (MODE_PARSE_SET    | /* Set the mode */
+               MODE_PARSE_STRICT | /* Interpret it strictly */
+               MODE_PARSE_FORCE),  /* And force it to be accepted */
+               NULL);
+  } else {
+    /* services don't cause hack messages */
+    if(!IsChannelService(sptr) && (!(member = find_member_link(chptr, sptr)) || !IsChanOp(member))) {
+      modebuf_init(&mbuf, sptr, cptr, chptr,
+                  (MODEBUF_DEST_SERVER |  /* Send mode to server */
+                   MODEBUF_DEST_HACK2  |  /* Send a HACK(2) message */
+                   MODEBUF_DEST_DEOP   |  /* Deop the source */
+                   MODEBUF_DEST_BOUNCE)); /* And bounce the MODE */
+      mode_parse(&mbuf, cptr, sptr, chptr, parc - 2, parv + 2,
+                (MODE_PARSE_STRICT |  /* Interpret it strictly */
+                 MODE_PARSE_BOUNCE),  /* And bounce the MODE */
+                 member);
+    } else {
+      modebuf_init(&mbuf, sptr, cptr, chptr,
+                  (MODEBUF_DEST_CHANNEL | /* Send mode to clients */
+                   MODEBUF_DEST_SERVER)); /* Send mode to servers */
+      mode_parse(&mbuf, cptr, sptr, chptr, parc - 2, parv + 2,
+                (MODE_PARSE_SET    | /* Set the mode */
+                 MODE_PARSE_STRICT | /* Interpret it strictly */
+                 MODE_PARSE_FORCE),  /* And force it to be accepted */
+                 member);
+    }
+  }
+
+  modebuf_flush(&mbuf);
+  destruct_nonpers_channel(chptr);
+  return 0;
+}
diff --git a/ircd/m_motd.c b/ircd/m_motd.c
new file mode 100644 (file)
index 0000000..0172419
--- /dev/null
@@ -0,0 +1,147 @@
+/*
+ * IRC - Internet Relay Chat, ircd/m_motd.c
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ *                    University of Oulu, Computing Center
+ *
+ * See file AUTHORS in IRC package for additional names of
+ * the programmers.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id: m_motd.c 1271 2004-12-11 05:14:07Z klmitch $
+ */
+
+/*
+ * m_functions execute protocol messages on this server:
+ *
+ *    cptr    is always NON-NULL, pointing to a *LOCAL* client
+ *            structure (with an open socket connected!). This
+ *            identifies the physical socket where the message
+ *            originated (or which caused the m_function to be
+ *            executed--some m_functions may call others...).
+ *
+ *    sptr    is the source of the message, defined by the
+ *            prefix part of the message if present. If not
+ *            or prefix not found, then sptr==cptr.
+ *
+ *            (!IsServer(cptr)) => (cptr == sptr), because
+ *            prefixes are taken *only* from servers...
+ *
+ *            (IsServer(cptr))
+ *                    (sptr == cptr) => the message didn't
+ *                    have the prefix.
+ *
+ *                    (sptr != cptr && IsServer(sptr) means
+ *                    the prefix specified servername. (?)
+ *
+ *                    (sptr != cptr && !IsServer(sptr) means
+ *                    that message originated from a remote
+ *                    user (not local).
+ *
+ *            combining
+ *
+ *            (!IsServer(sptr)) means that, sptr can safely
+ *            taken as defining the target structure of the
+ *            message in this server.
+ *
+ *    *Always* true (if 'parse' and others are working correct):
+ *
+ *    1)      sptr->from == cptr  (note: cptr->from == cptr)
+ *
+ *    2)      MyConnect(sptr) <=> sptr == cptr (e.g. sptr
+ *            *cannot* be a local connection, unless it's
+ *            actually cptr!). [MyConnect(x) should probably
+ *            be defined as (x == x->from) --msa ]
+ *
+ *    parc    number of variable parameter strings (if zero,
+ *            parv is allowed to be NULL)
+ *
+ *    parv    a NULL terminated list of parameter pointers,
+ *
+ *                    parv[0], sender (prefix string), if not present
+ *                            this points to an empty string.
+ *                    parv[1]...parv[parc-1]
+ *                            pointers to additional parameters
+ *                    parv[parc] == NULL, *always*
+ *
+ *            note:   it is guaranteed that parv[0]..parv[parc-1] are all
+ *                    non-NULL pointers.
+ */
+#include "config.h"
+
+#include "client.h"
+#include "ircd.h"
+#include "ircd_features.h"
+#include "ircd_log.h"
+#include "ircd_reply.h"
+#include "ircd_string.h"
+#include "match.h"
+#include "motd.h"
+#include "msg.h"
+#include "numeric.h"
+#include "numnicks.h"
+#include "s_conf.h"
+#include "class.h"
+#include "s_user.h"
+#include "send.h"
+
+#include <stdlib.h>
+/* #include <assert.h> -- Now using assert in ircd_log.h */
+
+/*
+ * m_motd - generic message handler
+ *
+ * parv[0] - sender prefix
+ * parv[1] - servername
+ *
+ * modified 30 mar 1995 by flux (cmlambertus@ucdavis.edu)
+ * T line patch - display motd based on hostmask
+ * modified again 7 sep 97 by Ghostwolf with code and ideas 
+ * stolen from comstud & Xorath.  All motd files are read into
+ * memory in read_motd() in s_conf.c
+ *
+ * Now using the motd_* family of functions defined in motd.c
+ */
+int m_motd(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  if (hunt_server_cmd(sptr, CMD_MOTD, cptr, feature_int(FEAT_HIS_REMOTE), "%C", 1,
+                     parc, parv) != HUNTED_ISME)
+    return 0;
+
+  return motd_send(sptr);
+}
+
+/*
+ * ms_motd - server message handler
+ *
+ * parv[0] - sender prefix
+ * parv[1] - servername
+ *
+ * modified 30 mar 1995 by flux (cmlambertus@ucdavis.edu)
+ * T line patch - display motd based on hostmask
+ * modified again 7 sep 97 by Ghostwolf with code and ideas 
+ * stolen from comstud & Xorath.  All motd files are read into
+ * memory in read_motd() in s_conf.c
+ *
+ * Now using the motd_* family of functions defined in motd.c
+ */
+int ms_motd(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  if (hunt_server_cmd(sptr, CMD_MOTD, cptr, 0, "%C", 1, parc, parv) !=
+      HUNTED_ISME)
+    return 0;
+
+  return motd_send(sptr);
+}
diff --git a/ircd/m_names.c b/ircd/m_names.c
new file mode 100644 (file)
index 0000000..16cee5c
--- /dev/null
@@ -0,0 +1,326 @@
+/*
+ * IRC - Internet Relay Chat, ircd/m_names.c
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ *                    University of Oulu, Computing Center
+ *
+ * See file AUTHORS in IRC package for additional names of
+ * the programmers.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id: m_names.c 1845 2007-11-25 02:42:54Z entrope $
+ */
+
+/*
+ * m_functions execute protocol messages on this server:
+ *
+ *    cptr    is always NON-NULL, pointing to a *LOCAL* client
+ *            structure (with an open socket connected!). This
+ *            identifies the physical socket where the message
+ *            originated (or which caused the m_function to be
+ *            executed--some m_functions may call others...).
+ *
+ *    sptr    is the source of the message, defined by the
+ *            prefix part of the message if present. If not
+ *            or prefix not found, then sptr==cptr.
+ *
+ *            (!IsServer(cptr)) => (cptr == sptr), because
+ *            prefixes are taken *only* from servers...
+ *
+ *            (IsServer(cptr))
+ *                    (sptr == cptr) => the message didn't
+ *                    have the prefix.
+ *
+ *                    (sptr != cptr && IsServer(sptr) means
+ *                    the prefix specified servername. (?)
+ *
+ *                    (sptr != cptr && !IsServer(sptr) means
+ *                    that message originated from a remote
+ *                    user (not local).
+ *
+ *            combining
+ *
+ *            (!IsServer(sptr)) means that, sptr can safely
+ *            taken as defining the target structure of the
+ *            message in this server.
+ *
+ *    *Always* true (if 'parse' and others are working correct):
+ *
+ *    1)      sptr->from == cptr  (note: cptr->from == cptr)
+ *
+ *    2)      MyConnect(sptr) <=> sptr == cptr (e.g. sptr
+ *            *cannot* be a local connection, unless it's
+ *            actually cptr!). [MyConnect(x) should probably
+ *            be defined as (x == x->from) --msa ]
+ *
+ *    parc    number of variable parameter strings (if zero,
+ *            parv is allowed to be NULL)
+ *
+ *    parv    a NULL terminated list of parameter pointers,
+ *
+ *                    parv[0], sender (prefix string), if not present
+ *                            this points to an empty string.
+ *                    parv[1]...parv[parc-1]
+ *                            pointers to additional parameters
+ *                    parv[parc] == NULL, *always*
+ *
+ *            note:   it is guaranteed that parv[0]..parv[parc-1] are all
+ *                    non-NULL pointers.
+ */
+#include "config.h"
+
+#include "channel.h"
+#include "client.h"
+#include "hash.h"
+#include "ircd.h"
+#include "ircd_log.h"
+#include "ircd_reply.h"
+#include "ircd_string.h"
+#include "msg.h"
+#include "numeric.h"
+#include "numnicks.h"
+#include "s_user.h"
+#include "send.h"
+/* #include <assert.h> -- Now using assert in ircd_log.h */
+#include <string.h>
+
+/*
+ *  Sends a suitably formatted 'names' reply to 'sptr' consisting of nicks within
+ *  'chptr', depending on 'filter'.
+ *
+ *  NAMES_ALL - Lists all users on channel.
+ *  NAMES_VIS - Only list visible (-i) users. --Gte (04/06/2000).
+ *  NAMES_DEL - Show join-delayed names list.
+ *  NAMES_EON - When OR'd with the other two, adds an 'End of Names' numeric
+ *              used by m_join
+ *
+ */
+
+void do_names(struct Client* sptr, struct Channel* chptr, int filter)
+{ 
+  int mlen;
+  int idx;
+  int flag;
+  int needs_space; 
+  int len; 
+  char buf[BUFSIZE];
+  struct Client *c2ptr;
+  struct Membership* member;
+  
+  assert(chptr);
+  assert(sptr);
+  assert((filter&NAMES_ALL) != (filter&NAMES_VIS));
+
+  /* Tag Pub/Secret channels accordingly. */
+
+  strcpy(buf, "* ");
+  if (PubChannel(chptr))
+    *buf = '=';
+  else if (SecretChannel(chptr))
+    *buf = '@';
+  len = strlen(chptr->chname);
+  strcpy(buf + 2, chptr->chname);
+  strcpy(buf + 2 + len, " :");
+
+  idx = len + 4;
+  flag = 1;
+  needs_space = 0;
+
+  if (!ShowChannel(sptr, chptr)) /* Don't list private channels unless we are on them. */
+    return;
+
+  /* Iterate over all channel members, and build up the list. */
+
+  mlen = strlen(cli_name(&me)) + 10 + strlen(cli_name(sptr));
+  
+  for (member = chptr->members; member; member = member->next_member)
+  {
+    c2ptr = member->user;
+
+    if (((filter&NAMES_VIS)!=0) && IsInvisible(c2ptr))
+      continue;
+
+    if (IsZombie(member) && member->user != sptr)
+      continue;
+
+    if (IsDelayedJoin(member) && (member->user != sptr) && !(filter & NAMES_DEL))
+        continue;
+
+    if ((!IsDelayedJoin(member) || (member->user == sptr)) && (filter & NAMES_DEL))
+        continue;
+               
+       if (IsInvisibleJoin(member) && member->user != sptr)
+               continue;
+
+    if (needs_space)
+      buf[idx++] = ' ';
+    needs_space=1;
+    if (IsZombie(member))
+      buf[idx++] = '!';
+    else if (IsChanOp(member))
+      buf[idx++] = '@';
+    else if (HasVoice(member))
+      buf[idx++] = '+';
+    strcpy(buf + idx, cli_name(c2ptr));
+    idx += strlen(cli_name(c2ptr));
+    flag = 1;
+    if (mlen + idx + NICKLEN + 5 > BUFSIZE)
+      /* space, modifier, nick, \r \n \0 */
+    {
+      send_reply(sptr, (filter & NAMES_DEL) ? RPL_DELNAMREPLY : RPL_NAMREPLY, buf);
+      idx = len + 4;
+      flag = 0;
+      needs_space=0;
+    }
+  }
+  if (flag)
+    send_reply(sptr, (filter & NAMES_DEL) ? RPL_DELNAMREPLY : RPL_NAMREPLY, buf); 
+  if (filter&NAMES_EON)
+    send_reply(sptr, RPL_ENDOFNAMES, chptr->chname);
+}
+
+/*
+ * m_names - generic message handler
+ *
+ * parv[0] = sender prefix
+ * parv[1] = channel
+ */
+
+int m_names(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  struct Channel *chptr; 
+  struct Channel *ch2ptr; 
+  struct Client *c2ptr;
+  struct Membership* member; 
+  char* s;
+  char* para = parc > 1 ? parv[1] : 0; 
+  int showingdelayed = 0;
+
+  if (parc > 1 && !ircd_strcmp(parv[1], "-D")) {
+    para = (parc > 2) ? parv[2] : 0;
+    showingdelayed = NAMES_DEL;
+    if (parc > 3 && hunt_server_cmd(sptr, CMD_NAMES, cptr, 1, "%s %s %C", 3, parc, parv))
+      return 0;
+  } else if (parc > 2 && hunt_server_cmd(sptr, CMD_NAMES, cptr, 1, "%s %C", 2, parc, parv))
+    return 0;
+
+  if (EmptyString(para)) {
+    send_reply(sptr, RPL_ENDOFNAMES, "*");
+    return 0;
+  }
+
+  do {
+    s = strchr(para, ',');
+    if (s)
+      *s++ = '\0';
+    /*
+     * Special Case 1: "/names 0". 
+     * Full list as per RFC. 
+     */
+    if ((*para == '0') || (*para == '\0'))
+    {
+      int idx; 
+      int mlen;
+      int flag;
+      struct Channel *ch3ptr;
+      char buf[BUFSIZE]; 
+
+      mlen = strlen(cli_name(&me)) + 10 + strlen(cli_name(sptr));
+
+      /* List all visible channels/visible members */ 
+
+      for (ch2ptr = GlobalChannelList; ch2ptr; ch2ptr = ch2ptr->next)
+      { 
+        if (!ShowChannel(sptr, ch2ptr))
+          continue;                 /* Don't show secret chans. */ 
+        else if (find_channel_member(sptr, ch2ptr))
+          do_names(sptr, ch2ptr, showingdelayed|NAMES_ALL); /* Full list if we're in this chan. */
+        else
+          do_names(sptr, ch2ptr, showingdelayed|NAMES_VIS);
+      } 
+
+      /* List all remaining users on channel '*' */
+
+      strcpy(buf, "* * :");
+      idx = 5;
+      flag = 0;
+
+      for (c2ptr = GlobalClientList; c2ptr; c2ptr = cli_next(c2ptr))
+      {
+        int showflag = 0;
+
+        if (!IsUser(c2ptr) || (sptr != c2ptr && IsInvisible(c2ptr)))
+          continue;
+
+        member = cli_user(c2ptr)->channel;
+
+        while (member)
+        {
+          ch3ptr = member->channel;
+  
+          if (PubChannel(ch3ptr) || find_channel_member(sptr, ch3ptr))
+            showflag = 1;
+          member = member->next_channel;
+        }
+
+        if (showflag)               /* Have we already shown them? */
+          continue;
+        strcpy(buf + idx, cli_name(c2ptr));
+        idx += strlen(cli_name(c2ptr));
+        buf[idx++] = ' ';
+        flag = 1;
+
+        if (mlen + idx + NICKLEN + 3 > BUFSIZE)     /* space, \r\n\0 */
+        {
+          send_reply(sptr, RPL_NAMREPLY, buf);
+          strcpy(buf, "* * :");
+          idx = 5;
+          flag = 0;
+        }
+      }
+      if (flag)
+        send_reply(sptr, RPL_NAMREPLY, buf);
+      send_reply(sptr, RPL_ENDOFNAMES, "*");
+    }
+    else if ((chptr = FindChannel(para)) != NULL)
+    {
+      member = find_member_link(chptr, sptr);
+      if (member)
+      {
+        /*
+         *  Special Case 2: User is on this channel, requesting full names list.
+         *  (As performed with each /join) - ** High frequency usage **
+         */
+        do_names(sptr, chptr, showingdelayed|NAMES_ALL|NAMES_EON);
+      }
+      else
+      {
+        /*
+         *  Special Case 3: User isn't on this channel, show all visible users, in 
+         *  non secret channels.
+         */ 
+        do_names(sptr, chptr, showingdelayed|NAMES_VIS|NAMES_EON);
+      } 
+    }
+    else
+        send_reply(sptr, RPL_ENDOFNAMES, para);
+  } while ((para = s) != NULL);
+
+  return 1;
+}
diff --git a/ircd/m_nick.c b/ircd/m_nick.c
new file mode 100644 (file)
index 0000000..3c069f7
--- /dev/null
@@ -0,0 +1,501 @@
+/*
+ * IRC - Internet Relay Chat, ircd/m_nick.c
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ *                    University of Oulu, Computing Center
+ *
+ * See file AUTHORS in IRC package for additional names of
+ * the programmers.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id: m_nick.c 1729 2006-11-04 21:42:00Z entrope $
+ */
+
+/*
+ * m_functions execute protocol messages on this server:
+ *
+ *    cptr    is always NON-NULL, pointing to a *LOCAL* client
+ *            structure (with an open socket connected!). This
+ *            identifies the physical socket where the message
+ *            originated (or which caused the m_function to be
+ *            executed--some m_functions may call others...).
+ *
+ *    sptr    is the source of the message, defined by the
+ *            prefix part of the message if present. If not
+ *            or prefix not found, then sptr==cptr.
+ *
+ *            (!IsServer(cptr)) => (cptr == sptr), because
+ *            prefixes are taken *only* from servers...
+ *
+ *            (IsServer(cptr))
+ *                    (sptr == cptr) => the message didn't
+ *                    have the prefix.
+ *
+ *                    (sptr != cptr && IsServer(sptr) means
+ *                    the prefix specified servername. (?)
+ *
+ *                    (sptr != cptr && !IsServer(sptr) means
+ *                    that message originated from a remote
+ *                    user (not local).
+ *
+ *            combining
+ *
+ *            (!IsServer(sptr)) means that, sptr can safely
+ *            taken as defining the target structure of the
+ *            message in this server.
+ *
+ *    *Always* true (if 'parse' and others are working correct):
+ *
+ *    1)      sptr->from == cptr  (note: cptr->from == cptr)
+ *
+ *    2)      MyConnect(sptr) <=> sptr == cptr (e.g. sptr
+ *            *cannot* be a local connection, unless it's
+ *            actually cptr!). [MyConnect(x) should probably
+ *            be defined as (x == x->from) --msa ]
+ *
+ *    parc    number of variable parameter strings (if zero,
+ *            parv is allowed to be NULL)
+ *
+ *    parv    a NULL terminated list of parameter pointers,
+ *
+ *                    parv[0], sender (prefix string), if not present
+ *                            this points to an empty string.
+ *                    parv[1]...parv[parc-1]
+ *                            pointers to additional parameters
+ *                    parv[parc] == NULL, *always*
+ *
+ *            note:   it is guaranteed that parv[0]..parv[parc-1] are all
+ *                    non-NULL pointers.
+ */
+#include "config.h"
+
+#include "IPcheck.h"
+#include "client.h"
+#include "hash.h"
+#include "ircd.h"
+#include "ircd_chattr.h"
+#include "ircd_features.h"
+#include "ircd_log.h"
+#include "ircd_reply.h"
+#include "ircd_string.h"
+#include "msg.h"
+#include "numeric.h"
+#include "numnicks.h"
+#include "s_debug.h"
+#include "s_misc.h"
+#include "s_user.h"
+#include "send.h"
+#include "sys.h"
+
+/* #include <assert.h> -- Now using assert in ircd_log.h */
+#include <stdlib.h>
+#include <string.h>
+
+ /*
+* 'do_nick_name' ensures that the given parameter (nick) is really a proper
+* string for a nickname (note, the 'nick' may be modified in the process...)
+*
+* RETURNS the length of the final NICKNAME (0, if nickname is invalid)
+*
+* Nickname characters are in range 'A'..'}', '_', '-', '0'..'9'
+*  anything outside the above set will terminate nickname.
+* In addition, the first character cannot be '-' or a Digit.
+*
+* Note:
+*  The '~'-character should be allowed, but a change should be global,
+*  some confusion would result if only few servers allowed it...
+*/
+static int do_nick_name(char* nick)
+{
+  char* ch  = nick;
+  char* end = ch + NICKLEN;
+  assert(0 != ch);
+  
+  /* first character in [0..9-] */
+  if (*ch == '-' || IsDigit(*ch))
+    return 0;
+  for ( ; (ch < end) && *ch; ++ch)
+    if (!IsNickChar(*ch))
+      break;
+
+  *ch = '\0';
+
+  return (ch - nick);
+}
+
+/*
+ * m_nick - message handler for local clients
+ * parv[0] = sender prefix
+ * parv[1] = nickname
+ */
+int m_nick(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  struct Client* acptr;
+  char           nick[NICKLEN + 2];
+  char*          arg;
+  char*          s;
+  const char*    client_name;
+
+  assert(0 != cptr);
+  assert(cptr == sptr);
+
+  if (IsServerPort(cptr))
+    return exit_client(cptr, cptr, &me, "Use a different port");
+
+  /*
+   * parv[0] will be empty for clients connecting for the first time
+   */
+  client_name = (*(cli_name(sptr))) ? cli_name(sptr) : "*";
+
+  if (parc < 2) {
+    send_reply(sptr, ERR_NONICKNAMEGIVEN);
+    return 0;
+  }
+
+  /*
+   * Don't let them send make us send back a really long string of
+   * garbage
+   */
+  arg = parv[1];
+  if (strlen(arg) > IRCD_MIN(NICKLEN, feature_int(FEAT_NICKLEN)))
+    arg[IRCD_MIN(NICKLEN, feature_int(FEAT_NICKLEN))] = '\0';
+
+  if ((s = strchr(arg, '~')))
+    *s = '\0';
+
+  strcpy(nick, arg);
+
+  /*
+   * If do_nick_name() returns a null name then reject it.
+   */
+  if (0 == do_nick_name(nick)) {
+    send_reply(sptr, ERR_ERRONEUSNICKNAME, arg);
+    return 0;
+  }
+
+  /* 
+   * Check if this is a LOCAL user trying to use a reserved (Juped)
+   * nick, if so tell him that it's a nick in use...
+   */
+  if (isNickJuped(nick) && !HasPriv(sptr, PRIV_UMODE_CHSERV)) {
+    send_reply(sptr, ERR_NICKNAMEINUSE, nick);
+    return 0;                        /* NICK message ignored */
+  }
+
+  if (!(acptr = FindClient(nick))) {
+    /*
+     * No collisions, all clear...
+     */
+    return set_nick_name(cptr, sptr, nick, parc, parv, 0);
+  }
+  if (IsServer(acptr)) {
+    send_reply(sptr, ERR_NICKNAMEINUSE, nick);
+    return 0;                        /* NICK message ignored */
+  }
+  /*
+   * If acptr == sptr, then we have a client doing a nick
+   * change between *equivalent* nicknames as far as server
+   * is concerned (user is changing the case of his/her
+   * nickname or somesuch)
+   */
+  if (acptr == sptr) {
+    /*
+     * If acptr == sptr, then we have a client doing a nick
+     * change between *equivalent* nicknames as far as server
+     * is concerned (user is changing the case of his/her
+     * nickname or somesuch)
+     */
+    if (0 != strcmp(cli_name(acptr), nick)) {
+      /*
+       * Allows change of case in his/her nick
+       */
+      return set_nick_name(cptr, sptr, nick, parc, parv, 0);
+    }
+    /*
+     * This is just ':old NICK old' type thing.
+     * Just forget the whole thing here. There is
+     * no point forwarding it to anywhere,
+     * especially since servers prior to this
+     * version would treat it as nick collision.
+     */
+    return 0;
+  }
+  /*
+   * Note: From this point forward it can be assumed that
+   * acptr != sptr (point to different client structures).
+   */
+  assert(acptr != sptr);
+  /*
+   * If the older one is "non-person", the new entry is just
+   * allowed to overwrite it. Just silently drop non-person,
+   * and proceed with the nick. This should take care of the
+   * "dormant nick" way of generating collisions...
+   *
+   * XXX - hmmm can this happen after one is registered?
+   *
+   * Yes, client 1 connects to IRC and registers, client 2 connects and
+   * sends "NICK foo" but doesn't send anything more.  client 1 now does
+   * /nick foo, they should succeed and client 2 gets disconnected with
+   * the message below.
+   */
+  if (IsUnknown(acptr) && MyConnect(acptr)) {
+    ServerStats->is_ref++;
+    IPcheck_connect_fail(acptr);
+    exit_client(cptr, acptr, &me, "Overridden by other sign on");
+    return set_nick_name(cptr, sptr, nick, parc, parv, 0);
+  }
+  /*
+   * NICK is coming from local client connection. Just
+   * send error reply and ignore the command.
+   */
+  send_reply(sptr, ERR_NICKNAMEINUSE, nick);
+  return 0;                        /* NICK message ignored */
+}
+
+
+/*
+ * ms_nick - server message handler for nicks
+ * parv[0] = sender prefix
+ * parv[1] = nickname
+ *
+ * If from server, source is client:
+ *   parv[2] = timestamp
+ *
+ * Source is server:
+ *   parv[2] = hopcount
+ *   parv[3] = timestamp
+ *   parv[4] = username
+ *   parv[5] = hostname
+ *   parv[6] = umode (optional)
+ *   parv[parc-3] = IP#                 <- Only Protocol >= 10
+ *   parv[parc-2] = YXX, numeric nick   <- Only Protocol >= 10
+ *   parv[parc-1] = info
+ *   parv[0] = server
+ */
+int ms_nick(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  struct Client *acptr;
+  char nick[NICKLEN + 2];
+  time_t lastnick = 0;
+  int differ = 1;
+  const char *type;
+
+  assert(0 != cptr);
+  assert(0 != sptr);
+  assert(IsServer(cptr));
+
+  if ((IsServer(sptr) && parc < 8) || parc < 3)
+  {
+    sendto_opmask_butone(0, SNO_OLDSNO, "bad NICK param count for %s from %C",
+                        parv[1], cptr);
+    return need_more_params(sptr, "NICK");
+  }
+
+  ircd_strncpy(nick, parv[1], NICKLEN);
+  nick[NICKLEN] = '\0';
+
+  if (IsServer(sptr))
+  {
+    lastnick = atoi(parv[3]);
+    if (lastnick > OLDEST_TS && !IsBurstOrBurstAck(sptr)) 
+      cli_serv(sptr)->lag = TStime() - lastnick;
+  }
+  else
+  {
+    lastnick = atoi(parv[2]); 
+    if (lastnick > OLDEST_TS && !IsBurstOrBurstAck(sptr))
+      cli_serv(cli_user(sptr)->server)->lag = TStime() - lastnick;
+  }
+  /*
+   * If do_nick_name() returns a null name OR if the server sent a nick
+   * name and do_nick_name() changed it in some way (due to rules of nick
+   * creation) then reject it. If from a server and we reject it,
+   * and KILL it. -avalon 4/4/92
+   */
+  if (!do_nick_name(nick) || strcmp(nick, parv[1]))
+  {
+    send_reply(sptr, ERR_ERRONEUSNICKNAME, parv[1]);
+    
+    ++ServerStats->is_kill;
+    sendto_opmask_butone(0, SNO_OLDSNO, "Bad Nick: %s From: %s %C", parv[1],
+                        parv[0], cptr);
+    sendcmdto_one(&me, CMD_KILL, cptr, "%s :%s (%s <- %s[%s])",
+                 IsServer(sptr) ? parv[parc - 2] : parv[0], cli_name(&me), parv[1],
+                 nick, cli_name(cptr));
+    if (!IsServer(sptr))
+    {
+      /*
+       * bad nick _change_
+       */
+      sendcmdto_serv_butone(&me, CMD_KILL, 0, "%s :%s (%s <- %s!%s@%s)",
+                           parv[0], cli_name(&me), cli_name(cptr), parv[0],
+                           cli_user(sptr) ? cli_username(sptr) : "",
+                           cli_user(sptr) ? cli_name(cli_user(sptr)->server) :
+                           cli_name(cptr));
+    }
+    return 0;
+  }
+  /* Check against nick name collisions. */
+  if ((acptr = FindClient(nick)) == NULL)
+    /* No collisions, all clear... */
+    return set_nick_name(cptr, sptr, nick, parc, parv, 0);
+
+  /*
+   * If acptr == sptr, then we have a client doing a nick
+   * change between *equivalent* nicknames as far as server
+   * is concerned (user is changing the case of his/her
+   * nickname or somesuch)
+   */
+  if (acptr == sptr)
+  {
+    if (strcmp(cli_name(acptr), nick) != 0)
+      /* Allows change of case in his/her nick */
+      return set_nick_name(cptr, sptr, nick, parc, parv, 0);
+    else
+      /* Setting their nick to what it already is? Ignore it. */
+      return 0;
+  }
+  /* now we know we have a real collision. */
+  /*
+   * Note: From this point forward it can be assumed that
+   * acptr != sptr (point to different client structures).
+   */
+  assert(acptr != sptr);
+  /*
+   * If the older one is "non-person", the new entry is just
+   * allowed to overwrite it. Just silently drop non-person,
+   * and proceed with the nick. This should take care of the
+   * "dormant nick" way of generating collisions...
+   */
+  if (IsUnknown(acptr) && MyConnect(acptr))
+  {
+    ServerStats->is_ref++;
+    IPcheck_connect_fail(acptr);
+    exit_client(cptr, acptr, &me, "Overridden by other sign on");
+    return set_nick_name(cptr, sptr, nick, parc, parv, 0);
+  }
+  /*
+   * Decide, we really have a nick collision and deal with it
+   */
+  /*
+   * NICK was coming from a server connection.
+   * This means we have a race condition (two users signing on
+   * at the same time), or two net fragments reconnecting with the same nick.
+   * The latter can happen because two different users connected
+   * or because one and the same user switched server during a net break.
+   * If the TimeStamps are equal, we kill both (or only 'new'
+   * if it was a ":server NICK new ...").
+   * Otherwise we kill the youngest when user@host differ,
+   * or the oldest when they are the same.
+   * We treat user and ~user as different, because if it wasn't
+   * a faked ~user the AUTH wouldn't have added the '~'.
+   * --Run
+   *
+   */
+  if (IsServer(sptr))
+  {
+    struct irc_in_addr ip;
+    /*
+     * A new NICK being introduced by a neighbouring
+     * server (e.g. message type ":server NICK new ..." received)
+     *
+     * compare IP address and username
+     */
+    base64toip(parv[parc - 3], &ip);
+    differ =  (0 != memcmp(&cli_ip(acptr), &ip, sizeof(cli_ip(acptr)))) ||
+              (0 != ircd_strcmp(cli_user(acptr)->username, parv[4]));
+    sendto_opmask_butone(0, SNO_OLDSNO, "Nick collision on %C (%C %Tu <- "
+                        "%C %Tu (%s user@host))", acptr, cli_from(acptr),
+                        cli_lastnick(acptr), cptr, lastnick,
+                        differ ? "Different" : "Same");
+  }
+  else
+  {
+    /*
+     * A NICK change has collided (e.g. message type ":old NICK new").
+     *
+     * compare IP address and username
+     */
+    differ =  (0 != memcmp(&cli_ip(acptr), &cli_ip(sptr), sizeof(cli_ip(acptr)))) ||
+              (0 != ircd_strcmp(cli_user(acptr)->username, cli_user(sptr)->username));
+    sendto_opmask_butone(0, SNO_OLDSNO, "Nick change collision from %C to "
+                        "%C (%C %Tu <- %C %Tu)", sptr, acptr, cli_from(acptr),
+                        cli_lastnick(acptr), cptr, lastnick);
+  }
+  type = differ ? "overruled by older nick" : "nick collision from same user@host";
+  /*
+   * Now remove (kill) the nick on our side if it is the youngest.
+   * If no timestamp was received, we ignore the incoming nick
+   * (and expect a KILL for our legit nick soon ):
+   * When the timestamps are equal we kill both nicks. --Run
+   * acptr->from != cptr should *always* be true (?).
+   *
+   * This exits the client sending the NICK message
+   */
+  if ((differ && lastnick >= cli_lastnick(acptr)) ||
+      (!differ && lastnick <= cli_lastnick(acptr)))
+  {
+    ServerStats->is_kill++;
+    if (!IsServer(sptr))
+    {
+      /* If this was a nick change and not a nick introduction, we
+       * need to ensure that we remove our record of the client, and
+       * send a KILL to the whole network.
+       */
+      assert(!MyConnect(sptr));
+      /* Inform the rest of the net... */
+      sendcmdto_serv_butone(&me, CMD_KILL, 0, "%C :%s (%s)",
+                            sptr, cli_name(&me), type);
+      /* Don't go sending off a QUIT message... */
+      SetFlag(sptr, FLAG_KILLED);
+      /* Remove them locally. */
+      exit_client_msg(cptr, sptr, &me,
+                      "Killed (%s (%s))",
+                      feature_str(FEAT_HIS_SERVERNAME), type);
+    }
+    else
+    {
+      /* If the origin is a server, this was a new client, so we only
+       * send the KILL in the direction it came from.  We have no
+       * client record that we would have to clean up.
+       */
+      sendcmdto_one(&me, CMD_KILL, cptr, "%s :%s (%s)",
+                    parv[parc - 2], cli_name(&me), type);
+    }
+    /* If the timestamps differ and we just killed sptr, we don't need to kill
+     * acptr as well.
+     */
+    if (lastnick != cli_lastnick(acptr))
+      return 0;
+  }
+  /* Tell acptr why we are killing it. */
+  send_reply(acptr, ERR_NICKCOLLISION, nick);
+
+  ServerStats->is_kill++;
+  SetFlag(acptr, FLAG_KILLED);
+  /*
+   * This exits the client we had before getting the NICK message
+   */
+  sendcmdto_serv_butone(&me, CMD_KILL, NULL, "%C :%s (%s)",
+                        acptr, feature_str(FEAT_HIS_SERVERNAME),
+                        type);
+  exit_client_msg(cptr, acptr, &me, "Killed (%s (%s))",
+                  feature_str(FEAT_HIS_SERVERNAME), type);
+  if (lastnick == cli_lastnick(acptr))
+    return 0;
+  if (sptr == NULL)
+    return 0;
+  return set_nick_name(cptr, sptr, nick, parc, parv, 0);
+}
diff --git a/ircd/m_notice.c b/ircd/m_notice.c
new file mode 100644 (file)
index 0000000..ab060d9
--- /dev/null
@@ -0,0 +1,246 @@
+/*
+ * IRC - Internet Relay Chat, ircd/m_notice.c
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ *                    University of Oulu, Computing Center
+ *
+ * See file AUTHORS in IRC package for additional names of
+ * the programmers.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id: m_notice.c 1271 2004-12-11 05:14:07Z klmitch $
+ */
+
+/*
+ * m_functions execute protocol messages on this server:
+ *
+ *    cptr    is always NON-NULL, pointing to a *LOCAL* client
+ *            structure (with an open socket connected!). This
+ *            identifies the physical socket where the message
+ *            originated (or which caused the m_function to be
+ *            executed--some m_functions may call others...).
+ *
+ *    sptr    is the source of the message, defined by the
+ *            prefix part of the message if present. If not
+ *            or prefix not found, then sptr==cptr.
+ *
+ *            (!IsServer(cptr)) => (cptr == sptr), because
+ *            prefixes are taken *only* from servers...
+ *
+ *            (IsServer(cptr))
+ *                    (sptr == cptr) => the message didn't
+ *                    have the prefix.
+ *
+ *                    (sptr != cptr && IsServer(sptr) means
+ *                    the prefix specified servername. (?)
+ *
+ *                    (sptr != cptr && !IsServer(sptr) means
+ *                    that message originated from a remote
+ *                    user (not local).
+ *
+ *            combining
+ *
+ *            (!IsServer(sptr)) means that, sptr can safely
+ *            taken as defining the target structure of the
+ *            message in this server.
+ *
+ *    *Always* true (if 'parse' and others are working correct):
+ *
+ *    1)      sptr->from == cptr  (note: cptr->from == cptr)
+ *
+ *    2)      MyConnect(sptr) <=> sptr == cptr (e.g. sptr
+ *            *cannot* be a local connection, unless it's
+ *            actually cptr!). [MyConnect(x) should probably
+ *            be defined as (x == x->from) --msa ]
+ *
+ *    parc    number of variable parameter strings (if zero,
+ *            parv is allowed to be NULL)
+ *
+ *    parv    a NULL terminated list of parameter pointers,
+ *
+ *                    parv[0], sender (prefix string), if not present
+ *                            this points to an empty string.
+ *                    parv[1]...parv[parc-1]
+ *                            pointers to additional parameters
+ *                    parv[parc] == NULL, *always*
+ *
+ *            note:   it is guaranteed that parv[0]..parv[parc-1] are all
+ *                    non-NULL pointers.
+ */
+#include "config.h"
+
+#include "client.h"
+#include "ircd_chattr.h"
+#include "ircd_log.h"
+#include "ircd_relay.h"
+#include "ircd_reply.h"
+#include "ircd_string.h"
+#include "match.h"
+#include "msg.h"
+#include "numeric.h"
+#include "send.h"
+
+/* #include <assert.h> -- Now using assert in ircd_log.h */
+#include <string.h>
+
+#if !defined(XXX_BOGUS_TEMP_HACK)
+#include "handlers.h"
+#endif
+
+/*
+ * m_notice - generic message handler
+ */
+int m_notice(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  char*           name;
+  char*           server;
+  int             i;
+  int             count;
+  int             ccount;
+  char*           vector[MAXTARGETS];
+
+  assert(0 != cptr);
+  assert(cptr == sptr);
+
+  ClrFlag(sptr, FLAG_TS8);
+
+  if (parc < 2 || EmptyString(parv[1]))
+    return send_reply(sptr, ERR_NORECIPIENT, MSG_NOTICE);
+
+  if (parc < 3 || EmptyString(parv[parc - 1]))
+    return send_reply(sptr, ERR_NOTEXTTOSEND);
+
+  if (parv[1][0] == '@' && IsChannelPrefix(parv[1][1])) {
+    parv[1]++;                        /* Get rid of '@' */
+    return m_wallchops(cptr, sptr, parc, parv);
+  }
+
+  count = unique_name_vector(parv[1], ',', vector, MAXTARGETS);
+
+  ccount = 0;
+  for (i = 0; i < count; ++i) {
+    name = vector[i];
+    if (IsChannelPrefix(*name)) ++ccount;
+  }
+
+  for (i = 0; i < count; ++i) {
+    name = vector[i];
+    /*
+     * channel msg?
+     */
+    if (IsChannelPrefix(*name)) {
+      relay_channel_notice(sptr, name, parv[parc - 1], ccount);
+    }
+    /*
+     * we have to check for the '@' at least once no matter what we do
+     * handle it first so we don't have to do it twice
+     */
+    else if ((server = strchr(name, '@')))
+      relay_directed_notice(sptr, name, server, parv[parc - 1]);
+    else 
+      relay_private_notice(sptr, name, parv[parc - 1]);
+  }
+  return 0;
+}
+
+/*
+ * ms_notice - server message handler
+ */
+int ms_notice(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  char* name;
+  char* server;
+
+  ClrFlag(sptr, FLAG_TS8);
+
+  if (parc < 3) {
+    /*
+     * we can't deliver it, sending an error back is pointless
+     */
+    return protocol_violation(sptr,"Not enough params for NOTICE");
+  }
+  name = parv[1];
+  /*
+   * channel msg?
+   */
+  if (IsChannelPrefix(*name)) {
+    server_relay_channel_notice(sptr, name, parv[parc - 1]);
+  }
+  /*
+   * coming from another server, we have to check this here
+   */
+  else if ('$' == *name && IsOper(sptr)) {
+    server_relay_masked_notice(sptr, name, parv[parc - 1]);
+  }
+  else if ((server = strchr(name, '@'))) {
+    /*
+     * XXX - can't get away with not doing everything
+     * relay_directed_notice has to do
+     */
+    relay_directed_notice(sptr, name, server, parv[parc - 1]);
+  }
+  else {
+    server_relay_private_notice(sptr, name, parv[parc - 1]);
+  }
+  return 0;
+}
+
+/*
+ * mo_notice - oper message handler
+ */
+int mo_notice(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  char*           name;
+  char*           server;
+  int             i;
+  int             count;
+  char*           vector[MAXTARGETS];
+  assert(0 != cptr);
+  assert(cptr == sptr);
+
+  ClrFlag(sptr, FLAG_TS8);
+
+  if (parc < 2 || EmptyString(parv[1]))
+    return send_reply(sptr, ERR_NORECIPIENT, MSG_NOTICE);
+
+  if (parc < 3 || EmptyString(parv[parc - 1]))
+    return send_reply(sptr, ERR_NOTEXTTOSEND);
+
+  if (parv[1][0] == '@' && IsChannelPrefix(parv[1][1])) {
+    parv[1]++;                        /* Get rid of '@' */
+    return m_wallchops(cptr, sptr, parc, parv);
+  }
+
+  count = unique_name_vector(parv[1], ',', vector, MAXTARGETS);
+
+  for (i = 0; i < count; ++i) {
+    name = vector[i];
+    /*
+     * channel msg?
+     */
+    if (IsChannelPrefix(*name))
+      relay_channel_notice(sptr, name, parv[parc - 1], 1);
+
+    else if (*name == '$')
+      relay_masked_notice(sptr, name, parv[parc - 1]);
+
+    else if ((server = strchr(name, '@')))
+      relay_directed_notice(sptr, name, server, parv[parc - 1]);
+
+    else 
+      relay_private_notice(sptr, name, parv[parc - 1]);
+  }
+  return 0;
+}
diff --git a/ircd/m_oper.c b/ircd/m_oper.c
new file mode 100644 (file)
index 0000000..171b61b
--- /dev/null
@@ -0,0 +1,234 @@
+/*
+ * IRC - Internet Relay Chat, ircd/m_oper.c
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ *                    University of Oulu, Computing Center
+ *
+ * See file AUTHORS in IRC package for additional names of
+ * the programmers.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id: m_oper.c 1327 2005-03-19 22:52:33Z entrope $
+ */
+
+/*
+ * m_functions execute protocol messages on this server:
+ *
+ *    cptr    is always NON-NULL, pointing to a *LOCAL* client
+ *            structure (with an open socket connected!). This
+ *            identifies the physical socket where the message
+ *            originated (or which caused the m_function to be
+ *            executed--some m_functions may call others...).
+ *
+ *    sptr    is the source of the message, defined by the
+ *            prefix part of the message if present. If not
+ *            or prefix not found, then sptr==cptr.
+ *
+ *            (!IsServer(cptr)) => (cptr == sptr), because
+ *            prefixes are taken *only* from servers...
+ *
+ *            (IsServer(cptr))
+ *                    (sptr == cptr) => the message didn't
+ *                    have the prefix.
+ *
+ *                    (sptr != cptr && IsServer(sptr) means
+ *                    the prefix specified servername. (?)
+ *
+ *                    (sptr != cptr && !IsServer(sptr) means
+ *                    that message originated from a remote
+ *                    user (not local).
+ *
+ *            combining
+ *
+ *            (!IsServer(sptr)) means that, sptr can safely
+ *            taken as defining the target structure of the
+ *            message in this server.
+ *
+ *    *Always* true (if 'parse' and others are working correct):
+ *
+ *    1)      sptr->from == cptr  (note: cptr->from == cptr)
+ *
+ *    2)      MyConnect(sptr) <=> sptr == cptr (e.g. sptr
+ *            *cannot* be a local connection, unless it's
+ *            actually cptr!). [MyConnect(x) should probably
+ *            be defined as (x == x->from) --msa ]
+ *
+ *    parc    number of variable parameter strings (if zero,
+ *            parv is allowed to be NULL)
+ *
+ *    parv    a NULL terminated list of parameter pointers,
+ *
+ *                    parv[0], sender (prefix string), if not present
+ *                            this points to an empty string.
+ *                    parv[1]...parv[parc-1]
+ *                            pointers to additional parameters
+ *                    parv[parc] == NULL, *always*
+ *
+ *            note:   it is guaranteed that parv[0]..parv[parc-1] are all
+ *                    non-NULL pointers.
+ */
+#include "config.h"
+
+#include "client.h"
+#include "hash.h"
+#include "ircd.h"
+#include "ircd_alloc.h"
+#include "ircd_features.h"
+#include "ircd_log.h"
+#include "ircd_reply.h"
+#include "ircd_string.h"
+#include "ircd_crypt.h"
+#include "msg.h"
+#include "numeric.h"
+#include "numnicks.h"
+#include "querycmds.h"
+#include "s_conf.h"
+#include "s_debug.h"
+#include "s_user.h"
+#include "s_misc.h"
+#include "send.h"
+
+/* #include <assert.h> -- Now using assert in ircd_log.h */
+#include <stdlib.h>
+#include <string.h>
+
+int oper_password_match(const char* to_match, const char* passwd)
+{
+  char *crypted;
+  int res;
+  /*
+   * use first two chars of the password they send in as salt
+   *
+   * passwd may be NULL. Head it off at the pass...
+   */
+  if (!to_match || !passwd)
+    return 0;
+
+  /* we no longer do a CRYPT_OPER_PASSWORD check because a clear 
+     text passwords just handled by a fallback mechanism called 
+     crypt_clear if it's enabled -- hikari */
+  crypted = ircd_crypt(to_match, passwd);
+
+  if (!crypted)
+   return 0;
+  res = strcmp(crypted, passwd);
+  MyFree(crypted);
+  return 0 == res;
+}
+
+/*
+ * m_oper - generic message handler
+ */
+int m_oper(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  struct ConfItem* aconf;
+  char*            name;
+  char*            password;
+
+  assert(0 != cptr);
+  assert(cptr == sptr);
+
+  name     = parc > 1 ? parv[1] : 0;
+  password = parc > 2 ? parv[2] : 0;
+
+  if (EmptyString(name) || EmptyString(password))
+    return need_more_params(sptr, "OPER");
+
+  aconf = find_conf_exact(name, sptr, CONF_OPERATOR);
+  if (!aconf || IsIllegal(aconf))
+  {
+    send_reply(sptr, ERR_NOOPERHOST);
+    sendto_opmask_butone(0, SNO_OLDREALOP, "Failed OPER attempt by %s (%s@%s)",
+                        parv[0], cli_user(sptr)->username, cli_sockhost(sptr));
+    return 0;
+  }
+  assert(0 != (aconf->status & CONF_OPERATOR));
+
+  if (oper_password_match(password, aconf->passwd))
+  {
+    struct Flags old_mode = cli_flags(sptr);
+
+    if (ACR_OK != attach_conf(sptr, aconf)) {
+      send_reply(sptr, ERR_NOOPERHOST);
+      sendto_opmask_butone(0, SNO_OLDREALOP, "Failed OPER attempt by %s "
+                          "(%s@%s)", parv[0], cli_user(sptr)->username,
+                          cli_sockhost(sptr));
+      return 0;
+    }
+    SetLocOp(sptr);
+    client_set_privs(sptr, aconf);
+    if (HasPriv(sptr, PRIV_PROPAGATE))
+    {
+      ClearLocOp(sptr);
+      SetOper(sptr);
+      ++UserStats.opers;
+    }
+    cli_handler(cptr) = OPER_HANDLER;
+
+    SetFlag(sptr, FLAG_WALLOP);
+    SetFlag(sptr, FLAG_SERVNOTICE);
+    SetFlag(sptr, FLAG_DEBUG);
+    if (HasPriv(sptr, PRIV_SEE_IDLETIME))
+      SetFlag(sptr, FLAG_SEE_IDLETIME);
+    
+    set_snomask(sptr, SNO_OPERDEFAULT, SNO_ADD);
+    cli_max_sendq(sptr) = 0; /* Get the sendq from the oper's class */
+    send_umode_out(cptr, sptr, &old_mode, HasPriv(sptr, PRIV_PROPAGATE));
+    send_reply(sptr, RPL_YOUREOPER);
+
+    sendto_opmask_butone(0, SNO_OLDSNO, "%s (%s@%s) is now operator (%c) - Logged in as: %s",
+                        parv[0], cli_user(sptr)->username, cli_sockhost(sptr),
+                        IsOper(sptr) ? 'O' : 'o',name);
+
+    log_write(LS_OPER, L_INFO, 0, "OPER (%s) by (%#C)", name, sptr);
+  }
+  else
+  {
+    send_reply(sptr, ERR_PASSWDMISMATCH);
+    sendto_opmask_butone(0, SNO_OLDREALOP, "Failed OPER attempt by %s (%s@%s)",
+                        parv[0], cli_user(sptr)->username, cli_sockhost(sptr));
+  }
+  return 0;
+}
+
+/*
+ * ms_oper - server message handler
+ */
+int ms_oper(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  assert(0 != cptr);
+  assert(IsServer(cptr));
+  /*
+   * if message arrived from server, trust it, and set to oper
+   */
+  if (!IsServer(sptr) && !IsOper(sptr))
+  {
+    ++UserStats.opers;
+    SetFlag(sptr, FLAG_OPER);
+    sendcmdto_serv_butone(sptr, CMD_MODE, cptr, "%s :+o", parv[0]);
+  }
+  return 0;
+}
+
+/*
+ * mo_oper - oper message handler
+ */
+int mo_oper(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  assert(0 != cptr);
+  assert(cptr == sptr);
+  send_reply(sptr, RPL_YOUREOPER);
+  return 0;
+}
diff --git a/ircd/m_opmode.c b/ircd/m_opmode.c
new file mode 100644 (file)
index 0000000..2e9d525
--- /dev/null
@@ -0,0 +1,189 @@
+/*
+ * IRC - Internet Relay Chat, ircd/m_opmode.c
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ *                    University of Oulu, Computing Center
+ * Copyright (C) 2000 Kevin L. Mitchell <klmitch@mit.edu>
+ *
+ * See file AUTHORS in IRC package for additional names of
+ * the programmers.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id: m_opmode.c 1485 2005-09-13 15:17:46Z entrope $
+ */
+
+/*
+ * m_functions execute protocol messages on this server:
+ *
+ *    cptr    is always NON-NULL, pointing to a *LOCAL* client
+ *            structure (with an open socket connected!). This
+ *            identifies the physical socket where the message
+ *            originated (or which caused the m_function to be
+ *            executed--some m_functions may call others...).
+ *
+ *    sptr    is the source of the message, defined by the
+ *            prefix part of the message if present. If not
+ *            or prefix not found, then sptr==cptr.
+ *
+ *            (!IsServer(cptr)) => (cptr == sptr), because
+ *            prefixes are taken *only* from servers...
+ *
+ *            (IsServer(cptr))
+ *                    (sptr == cptr) => the message didn't
+ *                    have the prefix.
+ *
+ *                    (sptr != cptr && IsServer(sptr) means
+ *                    the prefix specified servername. (?)
+ *
+ *                    (sptr != cptr && !IsServer(sptr) means
+ *                    that message originated from a remote
+ *                    user (not local).
+ *
+ *            combining
+ *
+ *            (!IsServer(sptr)) means that, sptr can safely
+ *            taken as defining the target structure of the
+ *            message in this server.
+ *
+ *    *Always* true (if 'parse' and others are working correct):
+ *
+ *    1)      sptr->from == cptr  (note: cptr->from == cptr)
+ *
+ *    2)      MyConnect(sptr) <=> sptr == cptr (e.g. sptr
+ *            *cannot* be a local connection, unless it's
+ *            actually cptr!). [MyConnect(x) should probably
+ *            be defined as (x == x->from) --msa ]
+ *
+ *    parc    number of variable parameter strings (if zero,
+ *            parv is allowed to be NULL)
+ *
+ *    parv    a NULL terminated list of parameter pointers,
+ *
+ *                    parv[0], sender (prefix string), if not present
+ *                            this points to an empty string.
+ *                    parv[1]...parv[parc-1]
+ *                            pointers to additional parameters
+ *                    parv[parc] == NULL, *always*
+ *
+ *            note:   it is guaranteed that parv[0]..parv[parc-1] are all
+ *                    non-NULL pointers.
+ */
+#include "config.h"
+
+#include "client.h"
+#include "channel.h"
+#include "hash.h"
+#include "ircd.h"
+#include "ircd_features.h"
+#include "ircd_log.h"
+#include "ircd_reply.h"
+#include "ircd_string.h"
+#include "msg.h"
+#include "numeric.h"
+#include "numnicks.h"
+#include "send.h"
+#include "s_conf.h"
+
+/* #include <assert.h> -- Now using assert in ircd_log.h */
+
+/*
+ * ms_opmode - server message handler
+ */
+int ms_opmode(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  struct Channel *chptr = 0;
+  struct ModeBuf mbuf;
+
+  if (parc < 3)
+    return need_more_params(sptr, "OPMODE");
+
+  if (IsLocalChannel(parv[1]))
+    return 0;
+
+  if ('#' != *parv[1] || !(chptr = FindChannel(parv[1])))
+    return send_reply(sptr, ERR_NOSUCHCHANNEL, parv[1]);
+
+  modebuf_init(&mbuf, sptr, cptr, chptr,
+              (MODEBUF_DEST_CHANNEL | /* Send MODE to channel */
+               MODEBUF_DEST_SERVER  | /* And to server */
+               MODEBUF_DEST_OPMODE  | /* Use OPMODE */
+               MODEBUF_DEST_HACK4   | /* Generate a HACK(4) notice */
+               MODEBUF_DEST_LOG));    /* Log the mode changes to OPATH */
+
+  mode_parse(&mbuf, cptr, sptr, chptr, parc - 2, parv + 2,
+            (MODE_PARSE_SET    | /* Set the modes on the channel */
+             MODE_PARSE_STRICT | /* Be strict about it */
+             MODE_PARSE_FORCE),  /* And force them to be accepted */
+             NULL);
+
+  modebuf_flush(&mbuf); /* flush the modes */
+  destruct_nonpers_channel(chptr);
+  return 0;
+}
+
+/*
+ * mo_opmode - oper message handler
+ */
+int mo_opmode(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  struct Channel *chptr = 0;
+  struct ModeBuf mbuf;
+  char *chname;
+  const char *qreason;
+  int force = 0;
+
+  if (!feature_bool(FEAT_CONFIG_OPERCMDS))
+    return send_reply(sptr, ERR_DISABLED, "OPMODE");
+
+  if (parc < 3)
+    return need_more_params(sptr, "OPMODE");
+
+  chname = parv[1];
+  if (*chname == '!')
+  {
+    chname++;
+    if (!HasPriv(sptr, IsLocalChannel(chname) ? PRIV_FORCE_LOCAL_OPMODE
+                                              : PRIV_FORCE_OPMODE))
+      return send_reply(sptr, ERR_NOPRIVILEGES);
+    force = 1;
+  }
+
+  if (!HasPriv(sptr,
+              IsLocalChannel(chname) ? PRIV_LOCAL_OPMODE : PRIV_OPMODE))
+    return send_reply(sptr, ERR_NOPRIVILEGES);
+
+  if (!IsChannelName(chname) || !(chptr = FindChannel(chname)))
+    return send_reply(sptr, ERR_NOSUCHCHANNEL, chname);
+
+  if (!force && ((qreason = find_quarantine(chptr->chname)) || ((chptr->mode.mode & MODE_QUARANTINE) && (qreason = "mode +Q"))))
+    return send_reply(sptr, ERR_QUARANTINED, chptr->chname, qreason);
+
+  modebuf_init(&mbuf, sptr, cptr, chptr,
+              (MODEBUF_DEST_CHANNEL | /* Send MODE to channel */
+               MODEBUF_DEST_SERVER  | /* And to server */
+               MODEBUF_DEST_OPMODE  | /* Use OPMODE */
+               MODEBUF_DEST_HACK4   | /* Generate a HACK(4) notice */
+               MODEBUF_DEST_LOG));    /* Log the mode changes to OPATH */
+
+  mode_parse(&mbuf, cptr, sptr, chptr, parc - 2, parv + 2,
+            (MODE_PARSE_SET |    /* set the modes on the channel */
+             MODE_PARSE_FORCE),  /* And force them to be accepted */
+             NULL);
+
+  modebuf_flush(&mbuf); /* flush the modes */
+  destruct_nonpers_channel(chptr);
+  return 0;
+}
+
diff --git a/ircd/m_part.c b/ircd/m_part.c
new file mode 100644 (file)
index 0000000..b5153c0
--- /dev/null
@@ -0,0 +1,209 @@
+/*
+ * IRC - Internet Relay Chat, ircd/m_part.c
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ *                    University of Oulu, Computing Center
+ *
+ * See file AUTHORS in IRC package for additional names of
+ * the programmers.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id: m_part.c 1344 2005-03-30 04:01:17Z entrope $
+ */
+
+/*
+ * m_functions execute protocol messages on this server:
+ *
+ *    cptr    is always NON-NULL, pointing to a *LOCAL* client
+ *            structure (with an open socket connected!). This
+ *            identifies the physical socket where the message
+ *            originated (or which caused the m_function to be
+ *            executed--some m_functions may call others...).
+ *
+ *    sptr    is the source of the message, defined by the
+ *            prefix part of the message if present. If not
+ *            or prefix not found, then sptr==cptr.
+ *
+ *            (!IsServer(cptr)) => (cptr == sptr), because
+ *            prefixes are taken *only* from servers...
+ *
+ *            (IsServer(cptr))
+ *                    (sptr == cptr) => the message didn't
+ *                    have the prefix.
+ *
+ *                    (sptr != cptr && IsServer(sptr) means
+ *                    the prefix specified servername. (?)
+ *
+ *                    (sptr != cptr && !IsServer(sptr) means
+ *                    that message originated from a remote
+ *                    user (not local).
+ *
+ *            combining
+ *
+ *            (!IsServer(sptr)) means that, sptr can safely
+ *            taken as defining the target structure of the
+ *            message in this server.
+ *
+ *    *Always* true (if 'parse' and others are working correct):
+ *
+ *    1)      sptr->from == cptr  (note: cptr->from == cptr)
+ *
+ *    2)      MyConnect(sptr) <=> sptr == cptr (e.g. sptr
+ *            *cannot* be a local connection, unless it's
+ *            actually cptr!). [MyConnect(x) should probably
+ *            be defined as (x == x->from) --msa ]
+ *
+ *    parc    number of variable parameter strings (if zero,
+ *            parv is allowed to be NULL)
+ *
+ *    parv    a NULL terminated list of parameter pointers,
+ *
+ *                    parv[0], sender (prefix string), if not present
+ *                            this points to an empty string.
+ *                    parv[1]...parv[parc-1]
+ *                            pointers to additional parameters
+ *                    parv[parc] == NULL, *always*
+ *
+ *            note:   it is guaranteed that parv[0]..parv[parc-1] are all
+ *                    non-NULL pointers.
+ */
+#include "config.h"
+
+#include "channel.h"
+#include "client.h"
+#include "hash.h"
+#include "ircd.h"
+#include "ircd_log.h"
+#include "ircd_reply.h"
+#include "ircd_string.h"
+#include "numeric.h"
+#include "numnicks.h"
+#include "send.h"
+
+/* #include <assert.h> -- Now using assert in ircd_log.h */
+#include <string.h>
+
+/*
+ * m_part - generic message handler
+ *
+ * parv[0] = sender prefix
+ * parv[1] = channel
+ * parv[parc - 1] = comment
+ */
+int m_part(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  struct Channel *chptr;
+  struct Membership *member;
+  struct JoinBuf parts;
+  unsigned int flags = 0;
+  char *p = 0;
+  char *name;
+
+  ClrFlag(sptr, FLAG_TS8);
+
+  /* check number of arguments */
+  if (parc < 2 || parv[1][0] == '\0')
+    return need_more_params(sptr, "PART");
+
+  /* init join/part buffer */
+  joinbuf_init(&parts, sptr, cptr, JOINBUF_TYPE_PART,
+              (parc > 2 && !EmptyString(parv[parc - 1])) ? parv[parc - 1] : 0,
+              0);
+
+  /* scan through channel list */
+  for (name = ircd_strtok(&p, parv[1], ","); name;
+       name = ircd_strtok(&p, 0, ",")) {
+
+    chptr = get_channel(sptr, name, CGT_NO_CREATE); /* look up channel */
+
+    if (!chptr) { /* complain if there isn't such a channel */
+      send_reply(sptr, ERR_NOSUCHCHANNEL, name);
+      continue;
+    }
+
+    if (!(member = find_member_link(chptr, sptr))) { /* complain if not on */
+      send_reply(sptr, ERR_NOTONCHANNEL, chptr->chname);
+      continue;
+    }
+
+    assert(!IsZombie(member)); /* Local users should never zombie */
+
+    if (!member_can_send_to_channel(member, 0))
+    {
+      flags |= CHFL_BANNED;
+      /* Remote clients don't want to see a comment either. */
+      parts.jb_comment = 0;
+    }
+
+    if (IsDelayedJoin(member))
+      flags |= CHFL_DELAYED;
+
+    joinbuf_join(&parts, chptr, flags); /* part client from channel */
+  }
+
+  return joinbuf_flush(&parts); /* flush channel parts */
+}
+
+/*
+ * ms_part - server message handler
+ *
+ * parv[0] = sender prefix
+ * parv[1] = channel
+ * parv[parc - 1] = comment
+ */
+int ms_part(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  struct Channel *chptr;
+  struct Membership *member;
+  struct JoinBuf parts;
+  unsigned int flags;
+  char *p = 0;
+  char *name;
+
+  ClrFlag(sptr, FLAG_TS8);
+
+  /* check number of arguments */
+  if (parc < 2 || parv[1][0] == '\0')
+    return need_more_params(sptr, "PART");
+
+  /* init join/part buffer */
+  joinbuf_init(&parts, sptr, cptr, JOINBUF_TYPE_PART,
+              (parc > 2 && !EmptyString(parv[parc - 1])) ? parv[parc - 1] : 0,
+              0);
+
+  /* scan through channel list */
+  for (name = ircd_strtok(&p, parv[1], ","); name;
+       name = ircd_strtok(&p, 0, ",")) {
+
+    flags = 0;
+
+    chptr = get_channel(sptr, name, CGT_NO_CREATE); /* look up channel */
+
+    if (!chptr || IsLocalChannel(name) ||
+       !(member = find_member_link(chptr, sptr)))
+      continue; /* ignore from remote clients */
+
+    if (IsZombie(member)) /* figure out special flags... */
+      flags |= CHFL_ZOMBIE;
+
+    if (IsDelayedJoin(member))
+      flags |= CHFL_DELAYED;
+
+    /* part user from channel */
+    joinbuf_join(&parts, chptr, flags);
+  }
+
+  return joinbuf_flush(&parts); /* flush channel parts */
+}
diff --git a/ircd/m_pass.c b/ircd/m_pass.c
new file mode 100644 (file)
index 0000000..8c284c7
--- /dev/null
@@ -0,0 +1,124 @@
+/*
+ * IRC - Internet Relay Chat, ircd/m_pass.c
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ *                    University of Oulu, Computing Center
+ *
+ * See file AUTHORS in IRC package for additional names of
+ * the programmers.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id: m_pass.c 1668 2006-06-17 13:09:14Z entrope $
+ */
+
+/*
+ * m_functions execute protocol messages on this server:
+ *
+ *    cptr    is always NON-NULL, pointing to a *LOCAL* client
+ *            structure (with an open socket connected!). This
+ *            identifies the physical socket where the message
+ *            originated (or which caused the m_function to be
+ *            executed--some m_functions may call others...).
+ *
+ *    sptr    is the source of the message, defined by the
+ *            prefix part of the message if present. If not
+ *            or prefix not found, then sptr==cptr.
+ *
+ *            (!IsServer(cptr)) => (cptr == sptr), because
+ *            prefixes are taken *only* from servers...
+ *
+ *            (IsServer(cptr))
+ *                    (sptr == cptr) => the message didn't
+ *                    have the prefix.
+ *
+ *                    (sptr != cptr && IsServer(sptr) means
+ *                    the prefix specified servername. (?)
+ *
+ *                    (sptr != cptr && !IsServer(sptr) means
+ *                    that message originated from a remote
+ *                    user (not local).
+ *
+ *            combining
+ *
+ *            (!IsServer(sptr)) means that, sptr can safely
+ *            taken as defining the target structure of the
+ *            message in this server.
+ *
+ *    *Always* true (if 'parse' and others are working correct):
+ *
+ *    1)      sptr->from == cptr  (note: cptr->from == cptr)
+ *
+ *    2)      MyConnect(sptr) <=> sptr == cptr (e.g. sptr
+ *            *cannot* be a local connection, unless it's
+ *            actually cptr!). [MyConnect(x) should probably
+ *            be defined as (x == x->from) --msa ]
+ *
+ *    parc    number of variable parameter strings (if zero,
+ *            parv is allowed to be NULL)
+ *
+ *    parv    a NULL terminated list of parameter pointers,
+ *
+ *                    parv[0], sender (prefix string), if not present
+ *                            this points to an empty string.
+ *                    parv[1]...parv[parc-1]
+ *                            pointers to additional parameters
+ *                    parv[parc] == NULL, *always*
+ *
+ *            note:   it is guaranteed that parv[0]..parv[parc-1] are all
+ *                    non-NULL pointers.
+ */
+#include "config.h"
+
+#include "client.h"
+#include "ircd_log.h"
+#include "ircd_reply.h"
+#include "ircd_string.h"
+#include "s_auth.h"
+#include "send.h"
+
+/* #include <assert.h> -- Now using assert in ircd_log.h */
+
+/*
+ * mr_pass - registration message handler
+ */
+int mr_pass(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  char password[BUFSIZE];
+  int arg, len;
+
+  assert(0 != cptr);
+  assert(cptr == sptr);
+  assert(!IsRegistered(sptr));
+
+  /* Some clients (brokenly) send "PASS x y" rather than "PASS :x y"
+   * when the user enters "x y" as the password.  Unsplit arguments to
+   * work around this.
+   */
+  for (arg = 1, len = 0; arg < parc; ++arg)
+  {
+    ircd_strncpy(password + len, parv[arg], sizeof(password) - len);
+    len += strlen(parv[arg]);
+    password[len++] = ' ';
+  }
+  if (len > 0)
+    --len;
+  password[len] = '\0';
+
+  if (EmptyPassString(password))
+    return need_more_params(cptr, "PASS");
+
+  ircd_strncpy(cli_passwd(cptr), password, PASSWDLEN);
+  return cli_auth(cptr) ? auth_set_password(cli_auth(cptr), password) : 0;
+}
diff --git a/ircd/m_ping.c b/ircd/m_ping.c
new file mode 100644 (file)
index 0000000..414bc47
--- /dev/null
@@ -0,0 +1,278 @@
+/*
+ * IRC - Internet Relay Chat, ircd/m_ping.c
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ *                    University of Oulu, Computing Center
+ *
+ * See file AUTHORS in IRC package for additional names of
+ * the programmers.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id: m_ping.c 1477 2005-09-11 17:40:21Z decampos $
+ */
+
+/*
+ * Stupid ircd Tricks
+ * Excerpt from conversation on #coder-com:
+ *  > the number horks it
+ *  <Gte-> yea
+ *  > thinks it's a numeric?
+ *  > no
+ *  <Gte-> hm
+ *  > why would the number hork it
+ *  <Gte-> why is it even looking up servers in a client ping :)
+ *  > it's a server ping
+ *  <Gte-> true
+ *  > oh
+ *  > I know why :)
+ *  >   origin = parv[1];
+ *  >   destination = parv[2];
+ *  >   acptr = FindClient(origin);
+ *  >   if (acptr && acptr != sptr)
+ *  >     origin = cptr->name;
+ *  > heh, that's a bug :)
+ *  <Gte-> yea, client/server handling in the same function sucks :P
+ *  > blindly pass a bogus origin around, and where do you send the reply to?
+ *  <Gte-> I tried /quote ping 12345 uworld.blah.net locally, and uworld
+ *  +recieved -> ":Gte- PING N :Uworld.blah.net"
+ *  <Gte-> oh no, sorry, I did ping N :)
+ *  > right, it's broken
+ *  <Gte-> good thing it doesn't have a fit replying to it
+ *  > hmm
+ *  *** plano.tx.us.undernet.org: PONG received from plano.tx.us.undernet.org
+ *  > you can send a number for the first ping .. but if you ping a remote server
+ *  +it goes to the remote end where it's received as a unsolicited pong by the
+ *  +server closest to the target
+ *  > hahaha
+ *  <Gte-> cool
+ *  <Gte-> Parsing: :Gte PING 12345 :widnes.uk.eu.blah.net
+ *  <Gte-> Sending [:widnes.uk.eu.blah.net PONG widnes.uk.eu.blah.net
+ *  +:12345] to alphatest.blah.net
+ *  <Gte-> Parsing: :alphatest.blah.net 402 widnes.uk.eu.blah.net
+ *  +12345 :No such server
+ *  > oh even better, the pongee sends no such server :)
+ *  > bwhahahah
+ *  <Gte-> for a second, I thought you could trigger a loop, which would be
+ *  +hideously nasty, but it doesn't look like
+ *  > it goes a ------ > b ------- > c ------- > d then c <------- d then c -----
+ *  +> d :)
+ *  <Gte-> weeee
+ *  <Gte-> [04:15] -> Server: ping Gte- Dallas-R.Tx.US.Undernet.org
+ *  <Gte-> *** PONG from Dallas-R.Tx.US.Undernet.org: Gte-
+ *  <Gte-> there we go
+ *  <Gte-> I can get a ping reply from a server I'm not on :)
+ */
+/*
+ * m_functions execute protocol messages on this server:
+ *
+ *    cptr    is always NON-NULL, pointing to a *LOCAL* client
+ *            structure (with an open socket connected!). This
+ *            identifies the physical socket where the message
+ *            originated (or which caused the m_function to be
+ *            executed--some m_functions may call others...).
+ *
+ *    sptr    is the source of the message, defined by the
+ *            prefix part of the message if present. If not
+ *            or prefix not found, then sptr==cptr.
+ *
+ *            (!IsServer(cptr)) => (cptr == sptr), because
+ *            prefixes are taken *only* from servers...
+ *
+ *            (IsServer(cptr))
+ *                    (sptr == cptr) => the message didn't
+ *                    have the prefix.
+ *
+ *                    (sptr != cptr && IsServer(sptr) means
+ *                    the prefix specified servername. (?)
+ *
+ *                    (sptr != cptr && !IsServer(sptr) means
+ *                    that message originated from a remote
+ *                    user (not local).
+ *
+ *            combining
+ *
+ *            (!IsServer(sptr)) means that, sptr can safely
+ *            taken as defining the target structure of the
+ *            message in this server.
+ *
+ *    *Always* true (if 'parse' and others are working correct):
+ *
+ *    1)      sptr->from == cptr  (note: cptr->from == cptr)
+ *
+ *    2)      MyConnect(sptr) <=> sptr == cptr (e.g. sptr
+ *            *cannot* be a local connection, unless it's
+ *            actually cptr!). [MyConnect(x) should probably
+ *            be defined as (x == x->from) --msa ]
+ *
+ *    parc    number of variable parameter strings (if zero,
+ *            parv is allowed to be NULL)
+ *
+ *    parv    a NULL terminated list of parameter pointers,
+ *
+ *                    parv[0], sender (prefix string), if not present
+ *                            this points to an empty string.
+ *                    parv[1]...parv[parc-1]
+ *                            pointers to additional parameters
+ *                    parv[parc] == NULL, *always*
+ *
+ *            note:   it is guaranteed that parv[0]..parv[parc-1] are all
+ *                    non-NULL pointers.
+ */
+#include "config.h"
+
+#include "client.h"
+#include "hash.h"
+#include "ircd_log.h"
+#include "ircd_reply.h"
+#include "ircd_string.h"
+#include "ircd.h"
+#include "msg.h"
+#include "numeric.h"
+#include "numnicks.h"
+#include "opercmds.h"
+#include "s_debug.h"
+#include "send.h"
+
+/* #include <assert.h> -- Now using assert in ircd_log.h */
+#include <stdlib.h>
+#include <string.h>
+
+/*
+ * m_ping - generic message handler
+ *
+ * parv[0] = sender prefix
+ * parv[1] = origin
+ * parv[2] = destination
+ */
+int m_ping(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  assert(0 != cptr);
+  assert(cptr == sptr);
+
+  if (parc < 2 || EmptyString(parv[1]))
+    return send_reply(sptr, ERR_NOORIGIN);
+
+  sendcmdto_one(&me, CMD_PONG, sptr, "%C :%s", &me, parv[1]);
+  return 0;
+}
+
+/*
+ * mo_ping - oper message handler
+ *
+ * parv[0] = sender prefix
+ * parv[1] = origin
+ * parv[2] = destination
+ */
+int mo_ping(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  struct Client* acptr;
+  char *destination, *origin;
+  assert(0 != cptr);
+  assert(cptr == sptr);
+
+  if (parc < 2 || EmptyString(parv[1]))
+    return send_reply(sptr, ERR_NOORIGIN);
+
+  origin = parv[1];
+  destination = parv[2];        /* Will get NULL or pointer (parc >= 2!!) */
+
+  if (!EmptyString(destination) && 0 != ircd_strcmp(destination, cli_name(&me))) {
+    if ((acptr = FindServer(destination)))
+      sendcmdto_one(sptr, CMD_PING, acptr, "%C :%s", sptr, destination);
+    else
+      send_reply(sptr, ERR_NOSUCHSERVER, destination);
+  }
+  else {
+    /*
+     * NOTE: clients rely on this to return the origin string.
+     * it's pointless to send more than 64 bytes back tho'
+     */
+    char* origin = parv[1];
+    
+    /* Is this supposed to be here? */
+    acptr = FindClient(origin);
+    if (acptr && acptr != sptr)
+      origin = cli_name(cptr);
+    
+    if (strlen(origin) > 64)
+      origin[64] = '\0';
+    sendcmdto_one(&me, CMD_PONG, sptr, "%C :%s", &me, origin);
+  }
+  return 0;
+}
+
+/*
+ * Extension notes
+ *
+ * <Vek> bleep:  here's the change you make to PING:
+ * <Vek> F TOK_PING F G 7777777777.7777777
+ * <Vek> then optional parameter for further enhancement
+ * <Vek> G TOK_PONG G F 7777777777.7777777 0.1734637
+ */
+
+/*
+ * ms_ping - server message handler
+ */
+int ms_ping(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  struct Client* acptr;
+  char*          origin;
+  char*          destination;
+
+  assert(0 != cptr);
+  assert(0 != sptr);
+  assert(IsServer(cptr));
+
+  if (parc < 2 || EmptyString(parv[1])) {
+    /*
+     * don't bother sending the error back
+     */
+    return 0;
+  }
+  origin      = parv[1];
+  destination = parv[2];        /* Will get NULL or pointer (parc >= 2!!) */
+
+  if (parc > 3)
+  {
+    /* AsLL ping, send reply back */
+    int diff = atoi(militime_float(parv[3]));
+    sendcmdto_one(&me, CMD_PONG, sptr, "%C %s %s %i %s", &me, origin,
+                  parv[3], diff, militime_float(NULL));
+    return 0;
+  }
+  if (!EmptyString(destination) && 0 != ircd_strcmp(destination, cli_name(&me))) {
+    if ((acptr = FindServer(destination))) {
+      /*
+       * Servers can just forward the origin
+       */
+      sendcmdto_one(sptr, CMD_PING, acptr, "%s :%s", origin, destination);
+    }
+    else {
+      /*
+       * this can happen if server split before the ping got here
+       */
+      send_reply(sptr, ERR_NOSUCHSERVER, destination);
+    }
+  }
+  else {
+    /*
+     * send pong back
+     * NOTE:  sptr is never local so if pong handles numerics everywhere we
+     * could send a numeric here.
+     */
+    sendcmdto_one(&me, CMD_PONG, sptr, "%C :%s", &me, origin);
+  }
+  return 0;
+}
diff --git a/ircd/m_pong.c b/ircd/m_pong.c
new file mode 100644 (file)
index 0000000..08b036e
--- /dev/null
@@ -0,0 +1,185 @@
+/*
+ * IRC - Internet Relay Chat, ircd/m_pong.c
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ *                    University of Oulu, Computing Center
+ *
+ * See file AUTHORS in IRC package for additional names of
+ * the programmers.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id: m_pong.c 1746 2007-01-15 03:08:23Z entrope $
+ */
+
+/*
+ * m_functions execute protocol messages on this server:
+ *
+ *    cptr    is always NON-NULL, pointing to a *LOCAL* client
+ *            structure (with an open socket connected!). This
+ *            identifies the physical socket where the message
+ *            originated (or which caused the m_function to be
+ *            executed--some m_functions may call others...).
+ *
+ *    sptr    is the source of the message, defined by the
+ *            prefix part of the message if present. If not
+ *            or prefix not found, then sptr==cptr.
+ *
+ *            (!IsServer(cptr)) => (cptr == sptr), because
+ *            prefixes are taken *only* from servers...
+ *
+ *            (IsServer(cptr))
+ *                    (sptr == cptr) => the message didn't
+ *                    have the prefix.
+ *
+ *                    (sptr != cptr && IsServer(sptr) means
+ *                    the prefix specified servername. (?)
+ *
+ *                    (sptr != cptr && !IsServer(sptr) means
+ *                    that message originated from a remote
+ *                    user (not local).
+ *
+ *            combining
+ *
+ *            (!IsServer(sptr)) means that, sptr can safely
+ *            taken as defining the target structure of the
+ *            message in this server.
+ *
+ *    *Always* true (if 'parse' and others are working correct):
+ *
+ *    1)      sptr->from == cptr  (note: cptr->from == cptr)
+ *
+ *    2)      MyConnect(sptr) <=> sptr == cptr (e.g. sptr
+ *            *cannot* be a local connection, unless it's
+ *            actually cptr!). [MyConnect(x) should probably
+ *            be defined as (x == x->from) --msa ]
+ *
+ *    parc    number of variable parameter strings (if zero,
+ *            parv is allowed to be NULL)
+ *
+ *    parv    a NULL terminated list of parameter pointers,
+ *
+ *                    parv[0], sender (prefix string), if not present
+ *                            this points to an empty string.
+ *                    parv[1]...parv[parc-1]
+ *                            pointers to additional parameters
+ *                    parv[parc] == NULL, *always*
+ *
+ *            note:   it is guaranteed that parv[0]..parv[parc-1] are all
+ *                    non-NULL pointers.
+ */
+#include "config.h"
+
+#include "client.h"
+#include "hash.h"
+#include "ircd.h"
+#include "ircd_log.h"
+#include "ircd_reply.h"
+#include "ircd_string.h"
+#include "msg.h"
+#include "numeric.h"
+#include "numnicks.h"
+#include "opercmds.h"
+#include "s_auth.h"
+#include "s_user.h"
+#include "send.h"
+
+/* #include <assert.h> -- Now using assert in ircd_log.h */
+#include <string.h>
+#include <stdlib.h>
+
+/*
+ * ms_pong - server message handler
+ *
+ * parv[0] = sender prefix
+ * parv[1] = origin
+ * parv[2] = destination
+ */
+int ms_pong(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  char*          origin;
+  char*          destination;
+  assert(0 != cptr);
+  assert(0 != sptr);
+  assert(IsServer(cptr));
+
+  if (parc < 2 || EmptyString(parv[1])) {
+    return protocol_violation(sptr,"No Origin on PONG");
+  }
+  origin      = parv[1];
+  destination = parv[2];
+  ClearPingSent(cptr);
+  ClearPingSent(sptr);
+  cli_lasttime(cptr) = CurrentTime;
+
+  if (parc > 5)
+  {
+    /* AsLL pong */
+    cli_serv(cptr)->asll_rtt = atoi(militime_float(parv[3]));
+    cli_serv(cptr)->asll_to = atoi(parv[4]);
+    cli_serv(cptr)->asll_from = atoi(militime_float(parv[5]));
+    cli_serv(cptr)->asll_last = CurrentTime;
+    return 0;
+  }
+  
+  if (EmptyString(destination))
+    return 0;
+  
+  if (*destination == '!')
+  {
+    /* AsLL ping reply from a non-AsLL server */
+    cli_serv(cptr)->asll_rtt = atoi(militime_float(destination + 1));
+  }
+  else if (0 != ircd_strcmp(destination, cli_name(&me)))
+  {
+    struct Client* acptr;
+    if ((acptr = FindClient(destination)))
+      sendcmdto_one(sptr, CMD_PONG, acptr, "%s %s", origin, destination);
+  }
+  return 0;
+}
+
+/*
+ * mr_pong - registration message handler
+ *
+ * parv[0] = sender prefix
+ * parv[1] = pong response echo
+ * NOTE: cptr is always unregistered here
+ */
+int mr_pong(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  assert(0 != cptr);
+  assert(cptr == sptr);
+  assert(!IsRegistered(sptr));
+
+  ClearPingSent(cptr);
+  return (parc > 1) ? auth_set_pong(cli_auth(sptr), strtoul(parv[parc - 1], NULL, 10)) : 0;
+}
+
+/*
+ * m_pong - normal message handler
+ *
+ * parv[0] = sender prefix
+ * parv[1] = origin
+ * parv[2] = destination
+ */
+int m_pong(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  assert(0 != cptr);
+  assert(cptr == sptr);
+
+  ClearPingSent(cptr);
+  cli_lasttime(cptr) = CurrentTime;
+  return 0;
+}
diff --git a/ircd/m_privmsg.c b/ircd/m_privmsg.c
new file mode 100644 (file)
index 0000000..c2b09ae
--- /dev/null
@@ -0,0 +1,243 @@
+/*
+ * IRC - Internet Relay Chat, ircd/m_privmsg.c
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ *                    University of Oulu, Computing Center
+ *
+ * See file AUTHORS in IRC package for additional names of
+ * the programmers.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id: m_privmsg.c 1271 2004-12-11 05:14:07Z klmitch $
+ */
+
+/*
+ * m_functions execute protocol messages on this server:
+ *
+ *    cptr    is always NON-NULL, pointing to a *LOCAL* client
+ *            structure (with an open socket connected!). This
+ *            identifies the physical socket where the message
+ *            originated (or which caused the m_function to be
+ *            executed--some m_functions may call others...).
+ *
+ *    sptr    is the source of the message, defined by the
+ *            prefix part of the message if present. If not
+ *            or prefix not found, then sptr==cptr.
+ *
+ *            (!IsServer(cptr)) => (cptr == sptr), because
+ *            prefixes are taken *only* from servers...
+ *
+ *            (IsServer(cptr))
+ *                    (sptr == cptr) => the message didn't
+ *                    have the prefix.
+ *
+ *                    (sptr != cptr && IsServer(sptr) means
+ *                    the prefix specified servername. (?)
+ *
+ *                    (sptr != cptr && !IsServer(sptr) means
+ *                    that message originated from a remote
+ *                    user (not local).
+ *
+ *            combining
+ *
+ *            (!IsServer(sptr)) means that, sptr can safely
+ *            taken as defining the target structure of the
+ *            message in this server.
+ *
+ *    *Always* true (if 'parse' and others are working correct):
+ *
+ *    1)      sptr->from == cptr  (note: cptr->from == cptr)
+ *
+ *    2)      MyConnect(sptr) <=> sptr == cptr (e.g. sptr
+ *            *cannot* be a local connection, unless it's
+ *            actually cptr!). [MyConnect(x) should probably
+ *            be defined as (x == x->from) --msa ]
+ *
+ *    parc    number of variable parameter strings (if zero,
+ *            parv is allowed to be NULL)
+ *
+ *    parv    a NULL terminated list of parameter pointers,
+ *
+ *                    parv[0], sender (prefix string), if not present
+ *                            this points to an empty string.
+ *                    parv[1]...parv[parc-1]
+ *                            pointers to additional parameters
+ *                    parv[parc] == NULL, *always*
+ *
+ *            note:   it is guaranteed that parv[0]..parv[parc-1] are all
+ *                    non-NULL pointers.
+ */
+#include "config.h"
+
+#include "client.h"
+#include "ircd.h"
+#include "ircd_chattr.h"
+#include "ircd_features.h"
+#include "ircd_log.h"
+#include "ircd_relay.h"
+#include "ircd_reply.h"
+#include "ircd_string.h"
+#include "match.h"
+#include "msg.h"
+#include "numeric.h"
+#include "send.h"
+
+/* #include <assert.h> -- Now using assert in ircd_log.h */
+#include <string.h>
+
+/*
+ * m_privmsg - generic message handler
+ */
+int m_privmsg(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  char*           name;
+  char*           server;
+  int             i;
+  int             count;
+  int             ccount;
+  char*           vector[MAXTARGETS];
+
+  assert(0 != cptr);
+  assert(cptr == sptr);
+  assert(0 != cli_user(sptr));
+
+  ClrFlag(sptr, FLAG_TS8);
+
+  if (feature_bool(FEAT_IDLE_FROM_MSG))
+    cli_user(sptr)->last = CurrentTime;
+
+  if (parc < 2 || EmptyString(parv[1]))
+    return send_reply(sptr, ERR_NORECIPIENT, MSG_PRIVATE);
+
+  if (parc < 3 || EmptyString(parv[parc - 1]))
+    return send_reply(sptr, ERR_NOTEXTTOSEND);
+
+  count = unique_name_vector(parv[1], ',', vector, MAXTARGETS);
+
+  ccount = 0;
+  for (i = 0; i < count; ++i) {
+    name = vector[i];
+    if (IsChannelPrefix(*name)) ++ccount;
+  }
+
+  for (i = 0; i < count; ++i) {
+    name = vector[i];
+    /*
+     * channel msg?
+     */
+    if (IsChannelPrefix(*name)) {
+      relay_channel_message(sptr, name, parv[parc - 1], ccount);
+    }
+    /*
+     * we have to check for the '@' at least once no matter what we do
+     * handle it first so we don't have to do it twice
+     */
+    else if ((server = strchr(name, '@')))
+      relay_directed_message(sptr, name, server, parv[parc - 1]);
+    else 
+      relay_private_message(sptr, name, parv[parc - 1]);
+  }
+  return 0;
+}
+
+/*
+ * ms_privmsg - server message handler
+ */
+int ms_privmsg(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  char* name;
+  char* server;
+
+  ClrFlag(sptr, FLAG_TS8);
+
+  if (parc < 3) {
+    /*
+     * we can't deliver it, sending an error back is pointless
+     */
+    return 0;
+  }
+  name = parv[1];
+  /*
+   * channel msg?
+   */
+  if (IsChannelPrefix(*name)) {
+    server_relay_channel_message(sptr, name, parv[parc - 1]);
+  }
+  /*
+   * coming from another server, we have to check this here
+   */
+  else if ('$' == *name && IsOper(sptr)) {
+    server_relay_masked_message(sptr, name, parv[parc - 1]);
+  }
+  else if ((server = strchr(name, '@'))) {
+    /*
+     * XXX - can't get away with not doing everything
+     * relay_directed_message has to do
+     */
+    relay_directed_message(sptr, name, server, parv[parc - 1]);
+  }
+  else {
+    server_relay_private_message(sptr, name, parv[parc - 1]);
+  }
+  return 0;
+}
+
+
+/*
+ * mo_privmsg - oper message handler
+ */
+int mo_privmsg(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  char*           name;
+  char*           server;
+  int             i;
+  int             count;
+  char*           vector[MAXTARGETS];
+  assert(0 != cptr);
+  assert(cptr == sptr);
+  assert(0 != cli_user(sptr));
+
+  ClrFlag(sptr, FLAG_TS8);
+
+  if (feature_bool(FEAT_IDLE_FROM_MSG))
+    cli_user(sptr)->last = CurrentTime;
+
+  if (parc < 2 || EmptyString(parv[1]))
+    return send_reply(sptr, ERR_NORECIPIENT, MSG_PRIVATE);
+
+  if (parc < 3 || EmptyString(parv[parc - 1]))
+    return send_reply(sptr, ERR_NOTEXTTOSEND);
+
+  count = unique_name_vector(parv[1], ',', vector, MAXTARGETS);
+
+  for (i = 0; i < count; ++i) {
+    name = vector[i];
+    /*
+     * channel msg?
+     */
+    if (IsChannelPrefix(*name))
+      relay_channel_message(sptr, name, parv[parc - 1], 1);
+
+    else if (*name == '$')
+      relay_masked_message(sptr, name, parv[parc - 1]);
+
+    else if ((server = strchr(name, '@')))
+      relay_directed_message(sptr, name, server, parv[parc - 1]);
+
+    else 
+      relay_private_message(sptr, name, parv[parc - 1]);
+  }
+  return 0;
+}
diff --git a/ircd/m_privs.c b/ircd/m_privs.c
new file mode 100644 (file)
index 0000000..c7e8044
--- /dev/null
@@ -0,0 +1,102 @@
+/*
+ * IRC - Internet Relay Chat, ircd/m_privs.c
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ *                    University of Oulu, Computing Center
+ *
+ * See file AUTHORS in IRC package for additional names of
+ * the programmers.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+/** @file
+ * @brief Report operators' privileges to others
+ * @version $Id: m_privs.c 1810 2007-05-20 14:15:58Z entrope $
+ */
+
+#include "config.h"
+
+#include "client.h"
+#include "hash.h"
+#include "ircd.h"
+#include "ircd_log.h"
+#include "ircd_reply.h"
+#include "ircd_string.h"
+#include "msg.h"
+#include "numeric.h"
+#include "numnicks.h"
+#include "send.h"
+
+/** Handle a local operator's privilege query.
+ * @param[in] cptr Client that sent us the message.
+ * @param[in] sptr Original source of message.
+ * @param[in] parc Number of arguments.
+ * @param[in] parv Argument vector.
+ * @see \ref m_functions
+ */
+int m_privs(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  struct Client *acptr;
+  char *name;
+  char *p = 0;
+  int i;
+
+  if (parc < 2 || !IsAnOper(sptr))
+    return client_report_privs(sptr, sptr);
+
+  for (i = 1; i < parc; i++) {
+    for (name = ircd_strtok(&p, parv[i], " "); name;
+        name = ircd_strtok(&p, 0, " ")) {
+      if (!(acptr = FindUser(name)))
+        send_reply(sptr, ERR_NOSUCHNICK, name);
+      else if (MyUser(acptr))
+       client_report_privs(sptr, acptr);
+      else
+        sendcmdto_one(cptr, CMD_PRIVS, acptr, "%s%s", NumNick(acptr));
+    }
+  }
+
+  return 0;
+}
+
+/** Handle a remote user's privilege query.
+ * @param[in] cptr Client that sent us the message.
+ * @param[in] sptr Original source of message.
+ * @param[in] parc Number of arguments.
+ * @param[in] parv Argument vector.
+ * @see \ref m_functions
+ */
+int ms_privs(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  struct Client *acptr;
+  char *numnick, *p = 0;
+  int i;
+
+  if (parc < 2)
+    return protocol_violation(cptr, "PRIVS with no arguments");
+
+  for (i = 1; i < parc; i++) {
+    for (numnick = ircd_strtok(&p, parv[i], " "); numnick;
+        numnick = ircd_strtok(&p, 0, " ")) {
+      if (!(acptr = findNUser(numnick)))
+        continue;
+      else if (MyUser(acptr))
+       client_report_privs(sptr, acptr);
+      else
+        sendcmdto_one(sptr, CMD_PRIVS, acptr, "%s%s", NumNick(acptr));
+    }
+  }
+
+  return 0;
+}
diff --git a/ircd/m_proto.c b/ircd/m_proto.c
new file mode 100644 (file)
index 0000000..e48ed4e
--- /dev/null
@@ -0,0 +1,156 @@
+/*
+ * IRC - Internet Relay Chat, ircd/m_proto.c
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ *                    University of Oulu, Computing Center
+ *
+ * See file AUTHORS in IRC package for additional names of
+ * the programmers.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id: m_proto.c 1271 2004-12-11 05:14:07Z klmitch $
+ */
+#include "config.h"
+
+#include "client.h"
+#include "ircd.h"
+#include "ircd_alloc.h"
+#include "ircd_chattr.h"
+#include "ircd_log.h"
+#include "ircd_reply.h"
+#include "ircd_string.h"
+#include "msg.h"
+#include "numeric.h"
+#include "numnicks.h"
+#include "s_debug.h"
+#include "s_misc.h"
+#include "send.h"
+#include "supported.h"
+#include "version.h"
+
+/* #include <assert.h> -- Now using assert in ircd_log.h */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+/*
+ * m_functions execute protocol messages on this server:
+ *
+ *    cptr    is always NON-NULL, pointing to a *LOCAL* client
+ *            structure (with an open socket connected!). This
+ *            identifies the physical socket where the message
+ *            originated (or which caused the m_function to be
+ *            executed--some m_functions may call others...).
+ *
+ *    sptr    is the source of the message, defined by the
+ *            prefix part of the message if present. If not
+ *            or prefix not found, then sptr==cptr.
+ *
+ *            (!IsServer(cptr)) => (cptr == sptr), because
+ *            prefixes are taken *only* from servers...
+ *
+ *            (IsServer(cptr))
+ *                    (sptr == cptr) => the message didn't
+ *                    have the prefix.
+ *
+ *                    (sptr != cptr && IsServer(sptr) means
+ *                    the prefix specified servername. (?)
+ *
+ *                    (sptr != cptr && !IsServer(sptr) means
+ *                    that message originated from a remote
+ *                    user (not local).
+ *
+ *            combining
+ *
+ *            (!IsServer(sptr)) means that, sptr can safely
+ *            taken as defining the target structure of the
+ *            message in this server.
+ *
+ *    *Always* true (if 'parse' and others are working correct):
+ *
+ *    1)      sptr->from == cptr  (note: cptr->from == cptr)
+ *
+ *    2)      MyConnect(sptr) <=> sptr == cptr (e.g. sptr
+ *            *cannot* be a local connection, unless it's
+ *            actually cptr!). [MyConnect(x) should probably
+ *            be defined as (x == x->from) --msa ]
+ *
+ *    parc    number of variable parameter strings (if zero,
+ *            parv is allowed to be NULL)
+ *
+ *    parv    a NULL terminated list of parameter pointers,
+ *
+ *                    parv[0], sender (prefix string), if not present
+ *                            this points to an empty string.
+ *                    parv[1]...parv[parc-1]
+ *                            pointers to additional parameters
+ *                    parv[parc] == NULL, *always*
+ *
+ *            note:   it is guaranteed that parv[0]..parv[parc-1] are all
+ *                    non-NULL pointers.
+ */
+
+static const char* const PROTO_REQ = "REQ";
+static const char* const PROTO_ACK = "ACK";
+static const char* const PROTO_SUP = "SUP";
+
+int proto_handle_ack(struct Client* cptr, const char* msg)
+{
+  /*
+   * handle ack here, if option and args supported
+   * start option
+   */ 
+  return 0;
+}
+
+int proto_handle_req(struct Client* cptr, const char* msg)
+{
+  /*
+   * handle request here if not supported args send
+   * option info. otherwise send ack
+   */
+  return 0;
+}
+
+int proto_send_supported(struct Client* cptr)
+{
+  /*
+   * send_reply(cptr, RPL_PROTOLIST, "stuff");
+   */
+  sendcmdto_one(&me,CMD_PROTO,cptr,"%s unet1 1 1",PROTO_SUP);
+  return 0;
+}
+
+int m_proto(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  if (0 == parc)
+    return proto_send_supported(cptr);
+
+  if (parc < 3) 
+    return need_more_params(sptr, "PROTO");
+
+  if (0 == ircd_strcmp(PROTO_REQ, parv[1]))
+    return proto_handle_req(cptr, parv[2]);
+
+  else if (0 == ircd_strcmp(PROTO_ACK, parv[1]))
+    return proto_handle_ack(cptr, parv[2]);
+    
+  else if (0 == ircd_strcmp(PROTO_SUP, parv[1]))
+    return 0; /* ignore it */
+
+  return 0;
+}
+
+  
diff --git a/ircd/m_pseudo.c b/ircd/m_pseudo.c
new file mode 100644 (file)
index 0000000..e463caf
--- /dev/null
@@ -0,0 +1,141 @@
+/*
+ * IRC - Internet Relay Chat, ircd/m_pseudo.c
+ * Copyright (C) 2002 - 2003 Zoot <zoot@gamesurge.net>
+ *
+ * See file AUTHORS in IRC package for additional names of
+ * the programmers.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id: m_pseudo.c 1271 2004-12-11 05:14:07Z klmitch $
+ */
+
+/*
+ * m_functions execute protocol messages on this server:
+ *
+ *    cptr    is always NON-NULL, pointing to a *LOCAL* client
+ *            structure (with an open socket connected!). This
+ *            identifies the physical socket where the message
+ *            originated (or which caused the m_function to be
+ *            executed--some m_functions may call others...).
+ *
+ *    sptr    is the source of the message, defined by the
+ *            prefix part of the message if present. If not
+ *            or prefix not found, then sptr==cptr.
+ *
+ *            (!IsServer(cptr)) => (cptr == sptr), because
+ *            prefixes are taken *only* from servers...
+ *
+ *            (IsServer(cptr))
+ *                    (sptr == cptr) => the message didn't
+ *                    have the prefix.
+ *
+ *                    (sptr != cptr && IsServer(sptr) means
+ *                    the prefix specified servername. (?)
+ *
+ *                    (sptr != cptr && !IsServer(sptr) means
+ *                    that message originated from a remote
+ *                    user (not local).
+ *
+ *            combining
+ *
+ *            (!IsServer(sptr)) means that, sptr can safely
+ *            taken as defining the target structure of the
+ *            message in this server.
+ *
+ *    *Always* true (if 'parse' and others are working correct):
+ *
+ *    1)      sptr->from == cptr  (note: cptr->from == cptr)
+ *
+ *    2)      MyConnect(sptr) <=> sptr == cptr (e.g. sptr
+ *            *cannot* be a local connection, unless it's
+ *            actually cptr!). [MyConnect(x) should probably
+ *            be defined as (x == x->from) --msa ]
+ *
+ *    parc    number of variable parameter strings (if zero,
+ *            parv is allowed to be NULL)
+ *
+ *    parv    a NULL terminated list of parameter pointers,
+ *
+ *                    parv[0], sender (prefix string), if not present
+ *                            this points to an empty string.
+ *                    parv[1], pointer to "extra" data (service mapping)
+ *                    parv[2]...parv[parc-1]
+ *                            pointers to additional parameters
+ *                    parv[parc] == NULL, *always*
+ *
+ *            note:   it is guaranteed that parv[0]..parv[parc-1] are all
+ *                    non-NULL pointers.
+ */
+#include "config.h"
+
+#include "client.h"
+#include "hash.h"
+#include "ircd.h"
+#include "ircd_features.h"
+#include "ircd_log.h"
+#include "ircd_relay.h"
+#include "ircd_reply.h"
+#include "ircd_string.h"
+#include "ircd_snprintf.h"
+#include "msg.h"
+#include "numeric.h"
+#include "numnicks.h"
+#include "s_conf.h"
+#include "s_user.h"
+
+/* #include <assert.h> -- Now using assert in ircd_log.h */
+
+/*
+ * m_pseudo - generic service message handler
+ *
+ * parv[0] = sender prefix
+ * parv[1] = service mapping (s_map * disguised as char *)
+ * parv[2] = message
+ */
+int m_pseudo(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  char *text, buffer[BUFSIZE];
+  struct s_map *map;
+  struct nick_host *nh;
+
+  assert(0 != cptr);
+  assert(cptr == sptr);
+  assert(0 != cli_user(sptr));
+
+  /* By default, relay the message straight through. */
+  text = parv[parc - 1];
+
+  if (parc < 3 || EmptyString(text))
+    return send_reply(sptr, ERR_NOTEXTTOSEND);
+
+  /* HACK! HACK! HACK! HACK! Yes. It's icky, but
+   * it's the only way. */
+  map = (struct s_map *)parv[1];
+  assert(0 != map);
+
+  if (map->prepend) {
+    ircd_snprintf(0, buffer, sizeof(buffer) - 1, "%s%s", map->prepend, text);
+    buffer[sizeof(buffer) - 1] = 0;
+    text = buffer;
+  }
+
+  for (nh = map->services; nh; nh = nh->next) {
+    if(relay_directed_account_server_message(sptr, nh->nick, nh->nick + nh->nicklen, text))
+      return 0;
+  }
+
+  return send_reply(sptr, ERR_SERVICESDOWN, map->name);
+}
diff --git a/ircd/m_quit.c b/ircd/m_quit.c
new file mode 100644 (file)
index 0000000..16376e4
--- /dev/null
@@ -0,0 +1,140 @@
+/*
+ * IRC - Internet Relay Chat, ircd/m_quit.c
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ *                    University of Oulu, Computing Center
+ *
+ * See file AUTHORS in IRC package for additional names of
+ * the programmers.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id: m_quit.c 1271 2004-12-11 05:14:07Z klmitch $
+ */
+
+/*
+ * m_functions execute protocol messages on this server:
+ *
+ *    cptr    is always NON-NULL, pointing to a *LOCAL* client
+ *            structure (with an open socket connected!). This
+ *            identifies the physical socket where the message
+ *            originated (or which caused the m_function to be
+ *            executed--some m_functions may call others...).
+ *
+ *    sptr    is the source of the message, defined by the
+ *            prefix part of the message if present. If not
+ *            or prefix not found, then sptr==cptr.
+ *
+ *            (!IsServer(cptr)) => (cptr == sptr), because
+ *            prefixes are taken *only* from servers...
+ *
+ *            (IsServer(cptr))
+ *                    (sptr == cptr) => the message didn't
+ *                    have the prefix.
+ *
+ *                    (sptr != cptr && IsServer(sptr) means
+ *                    the prefix specified servername. (?)
+ *
+ *                    (sptr != cptr && !IsServer(sptr) means
+ *                    that message originated from a remote
+ *                    user (not local).
+ *
+ *            combining
+ *
+ *            (!IsServer(sptr)) means that, sptr can safely
+ *            taken as defining the target structure of the
+ *            message in this server.
+ *
+ *    *Always* true (if 'parse' and others are working correct):
+ *
+ *    1)      sptr->from == cptr  (note: cptr->from == cptr)
+ *
+ *    2)      MyConnect(sptr) <=> sptr == cptr (e.g. sptr
+ *            *cannot* be a local connection, unless it's
+ *            actually cptr!). [MyConnect(x) should probably
+ *            be defined as (x == x->from) --msa ]
+ *
+ *    parc    number of variable parameter strings (if zero,
+ *            parv is allowed to be NULL)
+ *
+ *    parv    a NULL terminated list of parameter pointers,
+ *
+ *                    parv[0], sender (prefix string), if not present
+ *                            this points to an empty string.
+ *                    parv[1]...parv[parc-1]
+ *                            pointers to additional parameters
+ *                    parv[parc] == NULL, *always*
+ *
+ *            note:   it is guaranteed that parv[0]..parv[parc-1] are all
+ *                    non-NULL pointers.
+ */
+#include "config.h"
+
+#include "channel.h"
+#include "client.h"
+#include "ircd.h"
+#include "ircd_log.h"
+#include "ircd_string.h"
+#include "struct.h"
+#include "s_misc.h"
+#include "ircd_reply.h"
+
+/* #include <assert.h> -- Now using assert in ircd_log.h */
+#include <string.h>
+
+/*
+ * m_quit - client message handler 
+ *
+ * parv[0]        = sender prefix
+ * parv[parc - 1] = comment
+ */
+int m_quit(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  assert(0 != cptr);
+  assert(0 != sptr);
+  assert(cptr == sptr);
+
+  if (cli_user(sptr)) {
+    struct Membership* chan;
+    for (chan = cli_user(sptr)->channel; chan; chan = chan->next_channel) {
+        if (!IsZombie(chan) && !IsDelayedJoin(chan) && !member_can_send_to_channel(chan, 0))
+        return exit_client(cptr, sptr, sptr, "Signed off");
+    }
+  }
+  if (parc > 1 && !BadPtr(parv[parc - 1]))
+    return exit_client_msg(cptr, sptr, sptr, "Quit: %s", parv[parc - 1]);
+  else
+    return exit_client(cptr, sptr, sptr, "Quit");
+}
+
+
+/*
+ * ms_quit - server message handler
+ *
+ * parv[0] = sender prefix
+ * parv[parc - 1] = comment
+ */
+int ms_quit(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  assert(0 != sptr);
+  assert(parc > 0);
+  if (IsServer(sptr)) {
+       protocol_violation(sptr,"Server QUIT, not SQUIT?");
+       return 0;
+  }
+  /*
+   * ignore quit from servers
+   */
+  return exit_client(cptr, sptr, sptr, parv[parc - 1]);
+}
diff --git a/ircd/m_rehash.c b/ircd/m_rehash.c
new file mode 100644 (file)
index 0000000..bd3e00a
--- /dev/null
@@ -0,0 +1,209 @@
+/*
+ * IRC - Internet Relay Chat, ircd/m_rehash.c
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ *                    University of Oulu, Computing Center
+ *
+ * See file AUTHORS in IRC package for additional names of
+ * the programmers.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id: m_rehash.c 1271 2004-12-11 05:14:07Z klmitch $
+ */
+
+/*
+ * m_functions execute protocol messages on this server:
+ *
+ *    cptr    is always NON-NULL, pointing to a *LOCAL* client
+ *            structure (with an open socket connected!). This
+ *            identifies the physical socket where the message
+ *            originated (or which caused the m_function to be
+ *            executed--some m_functions may call others...).
+ *
+ *    sptr    is the source of the message, defined by the
+ *            prefix part of the message if present. If not
+ *            or prefix not found, then sptr==cptr.
+ *
+ *            (!IsServer(cptr)) => (cptr == sptr), because
+ *            prefixes are taken *only* from servers...
+ *
+ *            (IsServer(cptr))
+ *                    (sptr == cptr) => the message didn't
+ *                    have the prefix.
+ *
+ *                    (sptr != cptr && IsServer(sptr) means
+ *                    the prefix specified servername. (?)
+ *
+ *                    (sptr != cptr && !IsServer(sptr) means
+ *                    that message originated from a remote
+ *                    user (not local).
+ *
+ *            combining
+ *
+ *            (!IsServer(sptr)) means that, sptr can safely
+ *            taken as defining the target structure of the
+ *            message in this server.
+ *
+ *    *Always* true (if 'parse' and others are working correct):
+ *
+ *    1)      sptr->from == cptr  (note: cptr->from == cptr)
+ *
+ *    2)      MyConnect(sptr) <=> sptr == cptr (e.g. sptr
+ *            *cannot* be a local connection, unless it's
+ *            actually cptr!). [MyConnect(x) should probably
+ *            be defined as (x == x->from) --msa ]
+ *
+ *    parc    number of variable parameter strings (if zero,
+ *            parv is allowed to be NULL)
+ *
+ *    parv    a NULL terminated list of parameter pointers,
+ *
+ *                    parv[0], sender (prefix string), if not present
+ *                            this points to an empty string.
+ *                    parv[1]...parv[parc-1]
+ *                            pointers to additional parameters
+ *                    parv[parc] == NULL, *always*
+ *
+ *            note:   it is guaranteed that parv[0]..parv[parc-1] are all
+ *                    non-NULL pointers.
+ */
+#include "config.h"
+
+#include "client.h"
+#include "hash.h"
+#include "ircd.h"
+#include "ircd_log.h"
+#include "ircd_reply.h"
+#include "ircd_string.h"
+#include "motd.h"
+#include "msg.h"
+#include "numeric.h"
+#include "numnicks.h"
+#include "s_conf.h"
+#include "send.h"
+
+/* #include <assert.h> -- Now using assert in ircd_log.h */
+
+/* Removes all chars except 'm' 'l' 'q' and 'r'. */
+static void clean_rehash_string(char *str) {
+    unsigned int i, dest;
+
+    for(i = 0, dest = 0; str[i]; ++i) {
+        switch(str[i]) {
+            case 'm':
+            case 'l':
+            case 'q':
+            case 'r':
+                str[dest++] = str[i];
+                break;
+        }
+    }
+    str[dest] = 0;
+}
+
+/* Executes a rehash. */
+static void execute_rehash(struct Client *sptr, char *opt) {
+    unsigned int i, fresh = 0;
+
+    if(!opt) {
+        send_reply(sptr, RPL_REHASHING, configfile);
+        rehash(sptr, 0);
+    }
+    else {
+        for(i = 0; opt[i]; ++i) {
+            switch(opt[i]) {
+                case 'm':
+                    send_reply(sptr, SND_EXPLICIT | RPL_REHASHING, ":Flushing MOTD cache");
+                    motd_recache(); /* flush MOTD cache */
+                    break;
+                case 'l':
+                    send_reply(sptr, SND_EXPLICIT | RPL_REHASHING, ":Reopening log files");
+                    log_reopen(); /* reopen log files */
+                    break;
+                case 'q':
+                    fresh = 2;
+                    break;
+                case 'r':
+                    fresh = 1;
+                    break;
+            }
+        }
+        if(fresh) {
+            send_reply(sptr, RPL_REHASHING, configfile);
+            rehash(sptr, (fresh == 2)?2:0);
+        }
+    }
+    sendto_opmask_butone(0, SNO_OLDSNO, "%C is rehashing Server config files (opt='%s')", sptr, opt?opt:"r");
+    log_write(LS_SYSTEM, L_INFO, 0, "REHASH From %#C (opt='%s')", sptr, opt?opt:"r");
+}
+
+/*
+ * mo_rehash - oper message handler
+ *
+ * parv[1] = String containing:
+ *           'm' flushes the MOTD cache
+ *           'l' reopens the log files
+ *           'q' to not rehash the resolver (optional)
+ *           'r' rehashes the config file
+ * parv[2] = Optional: Remote server where to send the rehash command to.
+ */
+int mo_rehash(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  struct Client *acptr;
+
+  if (!HasPriv(sptr, PRIV_REHASH))
+    return send_reply(sptr, ERR_NOPRIVILEGES);
+
+  if(parc > 1) {
+    clean_rehash_string(parv[1]);
+
+    if(*parv[1]) {
+      if(parc > 2) {
+        if(!(acptr = FindServer(parv[2]))) return send_reply(sptr, SND_EXPLICIT | RPL_REHASHING, ":Unknown Server");
+        if(!IsMe(acptr)) {
+            sendcmdto_one(sptr, CMD_REHASH, acptr, "%s %s", cli_yxx(acptr), parv[1]);
+            return 0;
+        }
+      }
+      execute_rehash(sptr, parv[1]);
+    }
+  }
+  else execute_rehash(sptr, NULL);
+
+  return 0;
+}
+
+int ms_rehash(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) {
+    struct Client *acptr;
+
+    if(parc < 3) {
+        return protocol_violation(cptr, "Too few arguments for REHASH");
+    }
+
+    /* Ignore unknown servers. */
+    if(!(acptr = FindNServer(parv[1]))) return 0;
+
+    /* Ignore invalid parameter strings. */
+    clean_rehash_string(parv[2]);
+    if(!*parv[2]) return 0;
+
+    if(!IsMe(acptr)) {
+        sendcmdto_one(sptr, CMD_REHASH, acptr, "%s %s", cli_yxx(acptr), parv[2]);
+        return 0;
+    }
+
+    execute_rehash(sptr, parv[2]);
+    return 0;
+}
diff --git a/ircd/m_relay.c b/ircd/m_relay.c
new file mode 100644 (file)
index 0000000..12bf741
--- /dev/null
@@ -0,0 +1,202 @@
+/*
+ * IRC - Internet Relay Chat, ircd/m_relay.c
+ * Written by David Herrmann.
+ */
+
+#include "config.h"
+
+#include "channel.h"
+#include "client.h"
+#include "handlers.h"
+#include "hash.h"
+#include "parse.h"
+#include "ircd.h"
+#include "ircd_chattr.h"
+#include "ircd_features.h"
+#include "ircd_reply.h"
+#include "ircd_string.h"
+#include "msg.h"
+#include "numeric.h"
+#include "numnicks.h"
+#include "s_auth.h"
+#include "s_debug.h"
+#include "s_user.h"
+#include "send.h"
+#include "sys.h"
+
+#include <string.h>
+#include <ctype.h>
+#include <stdlib.h>
+
+static void loc_handler_LR(const char *num, char *parv[], signed int parc) {
+    if(num[0] != '!') return;
+       if(parc > 0)
+               auth_loc_reply(&num[3], NULL, NULL, NULL, 0);
+       else
+               auth_loc_reply(&num[3], NULL, NULL, &parv[0] , parc);
+}
+
+static void loc_handler_LA(const char *num, char *parv[], signed int parc) {
+    if(num[0] != '!' || parc < 1) return;
+       char *fakehost = NULL;
+       if (parc > 1 && parv[1] != "0")
+               fakehost=parv[1];
+               
+    if(parc > 2)
+        auth_loc_reply(&num[3], parv[0], fakehost, &parv[2] , parc - 2);
+    else if(parc > 1)
+        auth_loc_reply(&num[3], parv[0], fakehost, NULL, 0);
+    else
+        auth_loc_reply(&num[3], parv[0], NULL, NULL, 0);
+}
+
+
+static void mode_a_join(struct Client* cptr, char *channel, int flags) {
+    struct Channel *chptr;
+    if (!(chptr = FindChannel(channel))) {
+        if (((channel[0] == '&') && !feature_bool(FEAT_LOCAL_CHANNELS)) || strlen(channel) > IRCD_MIN(CHANNELLEN, feature_int(FEAT_CHANNELLEN))) {
+         //we don't send an error message here - that would be very strange for the user, because they normaly don't know that mode +F is set
+        } else if ((chptr = get_channel(cptr, channel, CGT_CREATE))) {
+           struct JoinBuf create;
+           joinbuf_init(&create, cptr, cptr, JOINBUF_TYPE_CREATE, 0, TStime());
+           joinbuf_join(&create, chptr, CHFL_CHANOP | CHFL_CHANNEL_MANAGER);
+                  do_names(cptr, chptr, NAMES_ALL|NAMES_EON);
+           joinbuf_flush(&create);
+               }
+       } else {
+        struct JoinBuf join;
+        joinbuf_init(&join, cptr, cptr, JOINBUF_TYPE_JOIN, 0, 0);
+               joinbuf_join(&join, chptr, flags);
+               del_invite(cptr, chptr);
+        if (chptr->topic[0]) {
+            send_reply(cptr, RPL_TOPIC, chptr->chname, chptr->topic);
+            send_reply(cptr, RPL_TOPICWHOTIME, chptr->chname, chptr->topic_nick, chptr->topic_time);
+        }
+        do_names(cptr, chptr, NAMES_ALL|NAMES_EON); /* send /names list */
+        joinbuf_flush(&join);
+       }
+}
+
+
+static void mode_a_check_altchan(struct Client* cptr, char *channel) {
+    struct Channel *chptr;
+    if (!(chptr = FindChannel(channel)))
+        return;
+    
+    if(chptr->mode.altchan && IsChannelName(chptr->mode.altchan) && strIsIrcCh(chptr->mode.altchan)) {
+               mode_a_join(cptr,chptr->mode.altchan,CHFL_DEOPPED);
+       }
+}
+
+/** RELAY
+ * The RELAY command has a special purpose. It is always built the following way:
+ *  <sender> RELAY <destination> <command>[ <list of parameters>]
+ * The <sender> is a single numeric nick of a server or user. <destination> can be:
+ * - a numeric-nick of a server (2 characters long): eg., AD
+ * - a numeric-nick of a user (5 characters long): eg., ADAAB
+ * - a numeric-nick of an unregistered user (6 characters long): eg., !ADAAB
+ * <command> is a subcommdn of RELAY.
+ *
+ * If we receive such a message, we relay the message to the server of <destination>.
+ * If we are the target, we check <command> and call the related subcommand handler.
+ *
+ * Therefore, this interface can be used to relay messages through the network without
+ * specifying new commands.
+ */
+/* ms_relay - server message handler
+ *
+ * parv[0] = sender prefix
+ * parv[1] = target
+ * parv[2] = subcommand
+ * parv[3-X] = NULL or a list of parameters.
+ */
+signed int ms_relay(struct Client* cptr, struct Client* sptr, signed int parc, char* parv[]) {
+    struct Client *server;
+    unsigned int len, i;
+    char buf[3], *act, *m, buffer[513];
+
+    if(parc < 3) {
+        return protocol_violation(cptr, "Too few arguments for RELAY");
+    }
+
+    /* Check <destination>. */
+    len = strlen(parv[1]);
+    buf[2] = 0;
+    switch(len) {
+        case 2:
+            server = FindNServer(parv[1]);
+            break;
+        case 5:
+            buf[0] = parv[1][0];
+            buf[1] = parv[1][1];
+            server = FindNServer(buf);
+            break;
+        case 6:
+            buf[0] = parv[1][1];
+            buf[1] = parv[1][2];
+            server = FindNServer(buf);
+            break;
+        default:
+            /* Invalid destination. Ignore. */
+            return 0;
+    }
+
+    if(server != &me) {
+        if(parc > 3) {
+            act = buffer;
+            for(i = 3; i < (parc - 1); ++i) {
+                m = parv[i];
+                while((*act++ = *m++)) /* empty loop */ ;
+                *(act - 1) = ' ';
+            }
+            m = parv[i];
+            *act++ = ':';
+            while((*act++ = *m++)) /* empty loop */ ;
+            sendcmdto_one(sptr, CMD_RELAY, server, "%s %s %s", parv[1], parv[2], buffer);
+        }
+        else sendcmdto_one(sptr, CMD_RELAY, server, "%s %s", parv[1], parv[2]);
+        return 0;
+    }
+
+    /* Call subcommand handler. */
+    if(strcmp("LR", parv[2]) == 0) loc_handler_LR(parv[1], &parv[3], parc - 3);
+    else if(strcmp("LA", parv[2]) == 0 && parc > 3) loc_handler_LA(parv[1], &parv[3], parc - 3);
+       else if(strcmp("SM", parv[2]) == 0 && parc > 3) {
+     #ifndef UNRESTRICTED_SERV
+        struct Client *acptr;
+        if(acptr = findNUser(parv[3])) {
+         if (IsChannelPrefix(*parv[4])) {
+       relay_channel_message(acptr, parv[4], parv[parc - 1], 1);
+      } else {
+          relay_private_message(acptr, parv[4], parv[parc - 1]);
+         }
+        }
+     #endif
+       } else if(strcmp("UC", parv[2]) == 0 && parc > 3) {
+        struct Client *acptr;
+        if(acptr = findNUser(parv[3])) {
+         send_reply(acptr, ERR_UNKNOWNCOMMAND, parv[4]);
+        }
+       } else if(strcmp("SI", parv[2]) == 0 && parc > 3) {
+     #ifndef UNRESTRICTED_SERV
+        struct Client *acptr;
+        if(acptr = findNUser(parv[3])) {
+         parse_simul_client(acptr, parv[parc - 1]);
+        }
+     #endif
+       } else if(strcmp("JAA", parv[2]) == 0 && parc > 2) {
+        struct Client *acptr;
+        if(acptr = findNUser(parv[1])) {
+         mode_a_join(acptr,parv[3],strtoul(parv[4], 0, 10));
+        }
+       } else if(strcmp("JAR", parv[2]) == 0 && parc > 2) {
+        struct Client *acptr;
+        if(acptr = findNUser(parv[1])) {
+      mode_a_check_altchan(acptr,parv[3]);
+         send_reply(acptr, ERR_JOINACCESS, parv[3]);
+        }
+       }
+
+    return 0;
+}
+
diff --git a/ircd/m_reset.c b/ircd/m_reset.c
new file mode 100644 (file)
index 0000000..2cb4b48
--- /dev/null
@@ -0,0 +1,103 @@
+/*
+ * IRC - Internet Relay Chat, ircd/m_reset.c
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ *                    University of Oulu, Computing Center
+ *
+ * See file AUTHORS in IRC package for additional names of
+ * the programmers.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id: m_reset.c 1271 2004-12-11 05:14:07Z klmitch $
+ */
+
+/*
+ * m_functions execute protocol messages on this server:
+ *
+ *    cptr    is always NON-NULL, pointing to a *LOCAL* client
+ *            structure (with an open socket connected!). This
+ *            identifies the physical socket where the message
+ *            originated (or which caused the m_function to be
+ *            executed--some m_functions may call others...).
+ *
+ *    sptr    is the source of the message, defined by the
+ *            prefix part of the message if present. If not
+ *            or prefix not found, then sptr==cptr.
+ *
+ *            (!IsServer(cptr)) => (cptr == sptr), because
+ *            prefixes are taken *only* from servers...
+ *
+ *            (IsServer(cptr))
+ *                    (sptr == cptr) => the message didn't
+ *                    have the prefix.
+ *
+ *                    (sptr != cptr && IsServer(sptr) means
+ *                    the prefix specified servername. (?)
+ *
+ *                    (sptr != cptr && !IsServer(sptr) means
+ *                    that message originated from a remote
+ *                    user (not local).
+ *
+ *            combining
+ *
+ *            (!IsServer(sptr)) means that, sptr can safely
+ *            taken as defining the target structure of the
+ *            message in this server.
+ *
+ *    *Always* true (if 'parse' and others are working correct):
+ *
+ *    1)      sptr->from == cptr  (note: cptr->from == cptr)
+ *
+ *    2)      MyConnect(sptr) <=> sptr == cptr (e.g. sptr
+ *            *cannot* be a local connection, unless it's
+ *            actually cptr!). [MyConnect(x) should probably
+ *            be defined as (x == x->from) --msa ]
+ *
+ *    parc    number of variable parameter strings (if zero,
+ *            parv is allowed to be NULL)
+ *
+ *    parv    a NULL terminated list of parameter pointers,
+ *
+ *                    parv[0], sender (prefix string), if not present
+ *                            this points to an empty string.
+ *                    parv[1]...parv[parc-1]
+ *                            pointers to additional parameters
+ *                    parv[parc] == NULL, *always*
+ *
+ *            note:   it is guaranteed that parv[0]..parv[parc-1] are all
+ *                    non-NULL pointers.
+ */
+#include "config.h"
+
+#include "client.h"
+#include "hash.h"
+#include "ircd.h"
+#include "ircd_features.h"
+#include "ircd_log.h"
+#include "ircd_reply.h"
+#include "ircd_string.h"
+#include "numeric.h"
+#include "numnicks.h"
+#include "send.h"
+
+/* #include <assert.h> -- Now using assert in ircd_log.h */
+
+/*
+ * mo_reset - oper message handler
+ */
+int mo_reset(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  return feature_reset(sptr, (const char* const*)parv + 1, parc - 1);
+}
diff --git a/ircd/m_restart.c b/ircd/m_restart.c
new file mode 100644 (file)
index 0000000..4e49c5e
--- /dev/null
@@ -0,0 +1,114 @@
+/*
+ * IRC - Internet Relay Chat, ircd/m_restart.c
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ *                    University of Oulu, Computing Center
+ *
+ * See file AUTHORS in IRC package for additional names of
+ * the programmers.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id: m_restart.c 1271 2004-12-11 05:14:07Z klmitch $
+ */
+
+/*
+ * m_functions execute protocol messages on this server:
+ *
+ *    cptr    is always NON-NULL, pointing to a *LOCAL* client
+ *            structure (with an open socket connected!). This
+ *            identifies the physical socket where the message
+ *            originated (or which caused the m_function to be
+ *            executed--some m_functions may call others...).
+ *
+ *    sptr    is the source of the message, defined by the
+ *            prefix part of the message if present. If not
+ *            or prefix not found, then sptr==cptr.
+ *
+ *            (!IsServer(cptr)) => (cptr == sptr), because
+ *            prefixes are taken *only* from servers...
+ *
+ *            (IsServer(cptr))
+ *                    (sptr == cptr) => the message didn't
+ *                    have the prefix.
+ *
+ *                    (sptr != cptr && IsServer(sptr) means
+ *                    the prefix specified servername. (?)
+ *
+ *                    (sptr != cptr && !IsServer(sptr) means
+ *                    that message originated from a remote
+ *                    user (not local).
+ *
+ *            combining
+ *
+ *            (!IsServer(sptr)) means that, sptr can safely
+ *            taken as defining the target structure of the
+ *            message in this server.
+ *
+ *    *Always* true (if 'parse' and others are working correct):
+ *
+ *    1)      sptr->from == cptr  (note: cptr->from == cptr)
+ *
+ *    2)      MyConnect(sptr) <=> sptr == cptr (e.g. sptr
+ *            *cannot* be a local connection, unless it's
+ *            actually cptr!). [MyConnect(x) should probably
+ *            be defined as (x == x->from) --msa ]
+ *
+ *    parc    number of variable parameter strings (if zero,
+ *            parv is allowed to be NULL)
+ *
+ *    parv    a NULL terminated list of parameter pointers,
+ *
+ *                    parv[0], sender (prefix string), if not present
+ *                            this points to an empty string.
+ *                    parv[1]...parv[parc-1]
+ *                            pointers to additional parameters
+ *                    parv[parc] == NULL, *always*
+ *
+ *            note:   it is guaranteed that parv[0]..parv[parc-1] are all
+ *                    non-NULL pointers.
+ */
+#include "config.h"
+
+#include "client.h"
+#include "ircd.h"
+#include "ircd_log.h"
+#include "ircd_reply.h"
+#include "ircd_string.h"
+#include "msg.h"
+#include "numeric.h"
+#include "numnicks.h"
+#include "send.h"
+
+/* #include <assert.h> -- Now using assert in ircd_log.h */
+
+/*
+ * mo_restart - oper message handler
+ */
+int mo_restart(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  if (!HasPriv(sptr, PRIV_RESTART))
+    return send_reply(sptr, ERR_NOPRIVILEGES);
+
+    /* parv[0] == sender, parv[1] == servername */
+    if(parc < 2 || ircd_strcmp(parv[1], cli_name(&me))) {
+        sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :To restart this server, use /restart %s", sptr, cli_name(&me));
+        return 0;
+    }
+
+  log_write(LS_SYSTEM, L_NOTICE, 0, "Server RESTART by %#C", sptr);
+  server_restart("received RESTART");
+
+  return 0;
+}
diff --git a/ircd/m_rping.c b/ircd/m_rping.c
new file mode 100644 (file)
index 0000000..0200838
--- /dev/null
@@ -0,0 +1,237 @@
+/*
+ * IRC - Internet Relay Chat, ircd/m_rping.c
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ *                    University of Oulu, Computing Center
+ *
+ * See file AUTHORS in IRC package for additional names of
+ * the programmers.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id: m_rping.c 1271 2004-12-11 05:14:07Z klmitch $
+ */
+
+/*
+ * m_functions execute protocol messages on this server:
+ *
+ *    cptr    is always NON-NULL, pointing to a *LOCAL* client
+ *            structure (with an open socket connected!). This
+ *            identifies the physical socket where the message
+ *            originated (or which caused the m_function to be
+ *            executed--some m_functions may call others...).
+ *
+ *    sptr    is the source of the message, defined by the
+ *            prefix part of the message if present. If not
+ *            or prefix not found, then sptr==cptr.
+ *
+ *            (!IsServer(cptr)) => (cptr == sptr), because
+ *            prefixes are taken *only* from servers...
+ *
+ *            (IsServer(cptr))
+ *                    (sptr == cptr) => the message didn't
+ *                    have the prefix.
+ *
+ *                    (sptr != cptr && IsServer(sptr) means
+ *                    the prefix specified servername. (?)
+ *
+ *                    (sptr != cptr && !IsServer(sptr) means
+ *                    that message originated from a remote
+ *                    user (not local).
+ *
+ *            combining
+ *
+ *            (!IsServer(sptr)) means that, sptr can safely
+ *            taken as defining the target structure of the
+ *            message in this server.
+ *
+ *    *Always* true (if 'parse' and others are working correct):
+ *
+ *    1)      sptr->from == cptr  (note: cptr->from == cptr)
+ *
+ *    2)      MyConnect(sptr) <=> sptr == cptr (e.g. sptr
+ *            *cannot* be a local connection, unless it's
+ *            actually cptr!). [MyConnect(x) should probably
+ *            be defined as (x == x->from) --msa ]
+ *
+ *    parc    number of variable parameter strings (if zero,
+ *            parv is allowed to be NULL)
+ *
+ *    parv    a NULL terminated list of parameter pointers,
+ *
+ *                    parv[0], sender (prefix string), if not present
+ *                            this points to an empty string.
+ *                    parv[1]...parv[parc-1]
+ *                            pointers to additional parameters
+ *                    parv[parc] == NULL, *always*
+ *
+ *            note:   it is guaranteed that parv[0]..parv[parc-1] are all
+ *                    non-NULL pointers.
+ */
+#include "config.h"
+
+#include "client.h"
+#include "hash.h"
+#include "ircd.h"
+#include "ircd_log.h"
+#include "ircd_reply.h"
+#include "ircd_string.h"
+#include "msg.h"
+#include "numeric.h"
+#include "numnicks.h"
+#include "opercmds.h"
+#include "s_user.h"
+#include "send.h"
+
+/* #include <assert.h> -- Now using assert in ircd_log.h */
+
+
+/*
+ * Old P10:
+ * Sending [:defiant.atomicrevs.net RPING Z Gte- 953863987 524184 :<No client start time>] to 
+ * alphatest.atomicrevs.net
+ * Full P10:
+ * Parsing: j RI Z jAA 953865133 0 :<No client start time>
+ */
+
+/*
+ * ms_rping - server message handler
+ * -- by Run
+ *
+ *    parv[0] = sender (sptr->name thus)
+ * if sender is a person: (traveling towards start server)
+ *    parv[1] = pinged server[mask]
+ *    parv[2] = start server (current target)
+ *    parv[3] = optional remark
+ * if sender is a server: (traveling towards pinged server)
+ *    parv[1] = pinged server (current target)
+ *    parv[2] = original sender (person)
+ *    parv[3] = start time in s
+ *    parv[4] = start time in us
+ *    parv[5] = the optional remark
+ */
+int ms_rping(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  struct Client* destination = 0;
+  assert(0 != cptr);
+  assert(0 != sptr);
+  assert(IsServer(cptr));
+
+  /*
+   * shouldn't happen
+   */
+  if (!IsPrivileged(sptr))
+    return 0;
+
+  if (IsServer(sptr)) {
+    if (parc < 6) {
+      /*
+       * PROTOCOL ERROR
+       */
+      return need_more_params(sptr, "RPING");
+    }
+    if ((destination = FindNServer(parv[1]))) {
+      /*
+       * if it's not for me, pass it on
+       */
+      if (IsMe(destination))
+       sendcmdto_one(&me, CMD_RPONG, sptr, "%s %s %s %s :%s", cli_name(sptr),
+                     parv[2], parv[3], parv[4], parv[5]);
+      else
+       sendcmdto_one(sptr, CMD_RPING, destination, "%C %s %s %s :%s",
+                     destination, parv[2], parv[3], parv[4], parv[5]);
+    }
+  }
+  else {
+    if (parc < 3) {
+      return need_more_params(sptr, "RPING");
+    }
+    /*
+     * Haven't made it to the start server yet, if I'm not the start server
+     * pass it on.
+     */
+    if (hunt_server_cmd(sptr, CMD_RPING, cptr, 1, "%s %C :%s", 2, parc, parv)
+       != HUNTED_ISME)
+      return 0;
+    /*
+     * otherwise ping the destination from here
+     */
+    if ((destination = find_match_server(parv[1]))) {
+      assert(IsServer(destination) || IsMe(destination));
+      sendcmdto_one(&me, CMD_RPING, destination, "%C %C %s :%s", destination,
+                   sptr, militime(0, 0), parv[3]);
+    }
+    else
+      send_reply(sptr, ERR_NOSUCHSERVER, parv[1]);
+  }
+  return 0;
+}
+
+/*
+ * mo_rping - oper message handler
+ * -- by Run
+ *
+ *
+ * Receive:
+ *          RPING blah.*
+ *          RPING blah.* :<start time>
+ *          RPING blah.* server.* :<start time>
+ *
+ *    parv[0] = sender (sptr->name thus)
+ *    parv[1] = pinged server name or mask (required)
+ *    parv[2] = start server name or mask (optional, defaults to me)
+ *    parv[3] = client start time (optional) 
+ * 
+ * Send: NumNick(sptr) RPING blah.* server.net :<start time> (hunt_server)
+ *       NumServ(&me) RPING NumServ(blah.bar.net) NumNick(sptr) :<start time> (here)
+ */
+int mo_rping(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  struct Client* acptr = 0;
+  const char*    start_time = "<No client start time>";
+
+  assert(0 != cptr);
+  assert(0 != sptr);
+  assert(cptr == sptr);
+  assert(IsAnOper(sptr));
+
+  if (parc < 2)
+    return need_more_params(sptr, "RPING");
+
+  if (parc > 2) {
+    if ((acptr = find_match_server(parv[2])) && !IsMe(acptr)) {
+      parv[2] = cli_name(acptr);
+      if (3 == parc) {
+        /*
+         * const_cast<char*>(start_time);
+         */
+        parv[parc++] = (char*) start_time;
+      }
+      hunt_server_cmd(sptr, CMD_RPING, cptr, 1, "%s %C :%s", 2, parc, parv);
+      return 0;
+    }
+    else
+      start_time = parv[2];
+  }
+
+  if ((acptr = find_match_server(parv[1]))) {
+    assert(IsServer(acptr) || IsMe(acptr));
+    sendcmdto_one(&me, CMD_RPING, acptr, "%C %C %s :%s", acptr, sptr,
+                 militime(0, 0), start_time);
+  }
+  else
+    send_reply(sptr, ERR_NOSUCHSERVER, parv[1]);
+
+  return 0;
+}
diff --git a/ircd/m_rpong.c b/ircd/m_rpong.c
new file mode 100644 (file)
index 0000000..c04467d
--- /dev/null
@@ -0,0 +1,148 @@
+/*
+ * IRC - Internet Relay Chat, ircd/m_rpong.c
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ *                    University of Oulu, Computing Center
+ *
+ * See file AUTHORS in IRC package for additional names of
+ * the programmers.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id: m_rpong.c 1271 2004-12-11 05:14:07Z klmitch $
+ */
+
+/*
+ * m_functions execute protocol messages on this server:
+ *
+ *    cptr    is always NON-NULL, pointing to a *LOCAL* client
+ *            structure (with an open socket connected!). This
+ *            identifies the physical socket where the message
+ *            originated (or which caused the m_function to be
+ *            executed--some m_functions may call others...).
+ *
+ *    sptr    is the source of the message, defined by the
+ *            prefix part of the message if present. If not
+ *            or prefix not found, then sptr==cptr.
+ *
+ *            (!IsServer(cptr)) => (cptr == sptr), because
+ *            prefixes are taken *only* from servers...
+ *
+ *            (IsServer(cptr))
+ *                    (sptr == cptr) => the message didn't
+ *                    have the prefix.
+ *
+ *                    (sptr != cptr && IsServer(sptr) means
+ *                    the prefix specified servername. (?)
+ *
+ *                    (sptr != cptr && !IsServer(sptr) means
+ *                    that message originated from a remote
+ *                    user (not local).
+ *
+ *            combining
+ *
+ *            (!IsServer(sptr)) means that, sptr can safely
+ *            taken as defining the target structure of the
+ *            message in this server.
+ *
+ *    *Always* true (if 'parse' and others are working correct):
+ *
+ *    1)      sptr->from == cptr  (note: cptr->from == cptr)
+ *
+ *    2)      MyConnect(sptr) <=> sptr == cptr (e.g. sptr
+ *            *cannot* be a local connection, unless it's
+ *            actually cptr!). [MyConnect(x) should probably
+ *            be defined as (x == x->from) --msa ]
+ *
+ *    parc    number of variable parameter strings (if zero,
+ *            parv is allowed to be NULL)
+ *
+ *    parv    a NULL terminated list of parameter pointers,
+ *
+ *                    parv[0], sender (prefix string), if not present
+ *                            this points to an empty string.
+ *                    parv[1]...parv[parc-1]
+ *                            pointers to additional parameters
+ *                    parv[parc] == NULL, *always*
+ *
+ *            note:   it is guaranteed that parv[0]..parv[parc-1] are all
+ *                    non-NULL pointers.
+ */
+#include "config.h"
+
+#include "client.h"
+#include "hash.h"
+#include "ircd.h"
+#include "ircd_log.h"
+#include "ircd_reply.h"
+#include "ircd_string.h"
+#include "msg.h"
+#include "numeric.h"
+#include "numnicks.h"
+#include "opercmds.h"
+#include "send.h"
+
+/* #include <assert.h> -- Now using assert in ircd_log.h */
+
+/*
+ * ms_rpong - server message handler
+ * -- by Run too :)
+ *
+ * parv[0] = sender prefix
+ * parv[1] = from pinged server: start server; from start server: sender
+ * parv[2] = from pinged server: sender; from start server: pinged server
+ * parv[3] = pingtime in ms
+ * parv[4] = client info (for instance start time)
+ */
+int ms_rpong(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  struct Client *acptr;
+
+  if (!IsServer(sptr))
+    return 0;
+
+  if (parc < 5) {
+    /*
+     * PROTOCOL ERROR
+     */
+    return need_more_params(sptr, "RPONG");
+  }
+  if (parc == 6) {
+    /*
+     * from pinged server to source server
+     */
+    if (!(acptr = FindServer(parv[1])) && !(acptr = FindNServer(parv[1])))
+      return 0;
+   
+    if (IsMe(acptr)) {
+      if (!(acptr = findNUser(parv[2])))
+        return 0;
+
+      sendcmdto_one(&me, CMD_RPONG, acptr, "%C %s %s :%s", acptr, cli_name(sptr),
+                   militime(parv[3], parv[4]), parv[5]);
+    } else
+      sendcmdto_one(sptr, CMD_RPONG, acptr, "%s %s %s %s :%s", parv[1],
+                   parv[2], parv[3], parv[4], parv[5]);
+  } else {
+    /*
+     * returned from source server to client
+     */
+    if (!(acptr = findNUser(parv[1])))
+      return 0;
+
+    sendcmdto_one(sptr, CMD_RPONG, acptr, "%C %s %s :%s", acptr, parv[2],
+                 parv[3], parv[4]);
+  }
+  return 0;
+}
diff --git a/ircd/m_server.c b/ircd/m_server.c
new file mode 100644 (file)
index 0000000..df10eb9
--- /dev/null
@@ -0,0 +1,785 @@
+/*
+ * IRC - Internet Relay Chat, ircd/m_server.c
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ *                    University of Oulu, Computing Center
+ *
+ * See file AUTHORS in IRC package for additional names of
+ * the programmers.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+/** @file
+ * @brief Handlers for the SERVER command.
+ * @version $Id: m_server.c 1415 2005-05-30 16:51:05Z entrope $
+ */
+
+#include "config.h"
+
+#include "client.h"
+#include "hash.h"
+#include "ircd.h"
+#include "ircd_log.h"
+#include "ircd_features.h"
+#include "ircd_reply.h"
+#include "ircd_string.h"
+#include "jupe.h"
+#include "list.h"
+#include "match.h"
+#include "msg.h"
+#include "numeric.h"
+#include "numnicks.h"
+#include "querycmds.h"
+#include "s_bsd.h"
+#include "s_conf.h"
+#include "s_debug.h"
+#include "s_misc.h"
+#include "s_serv.h"
+#include "send.h"
+#include "userload.h"
+
+/* #include <assert.h> -- Now using assert in ircd_log.h */
+#include <stdlib.h>
+#include <string.h>
+
+/** Clean up a server name.
+ * @param[in] host Input server name.
+ * @return NULL if the name is invalid, else pointer to cleaned-up name.
+ */
+static char *
+clean_servername(char *host)
+{
+  char*            ch;
+  /*
+   * Check for "FRENCH " infection ;-) (actually this should
+   * be replaced with routine to check the hostname syntax in
+   * general). [ This check is still needed, even after the parse
+   * is fixed, because someone can send "SERVER :foo bar " ].
+   * Also, changed to check other "difficult" characters, now
+   * that parse lets all through... --msa
+   */
+  if (strlen(host) > HOSTLEN)
+    host[HOSTLEN] = '\0';
+
+  for (ch = host; *ch; ch++)
+    if (*ch <= ' ' || *ch > '~')
+      break;
+  if (*ch || !strchr(host, '.') || strlen(host) > HOSTLEN)
+    return NULL;
+  return host;
+}
+
+/** Parse protocol version from a string.
+ * @param[in] proto String version of protocol number.
+ * @return Zero if \a proto is unrecognized, else protocol version.
+ */
+static unsigned short
+parse_protocol(const char *proto)
+{
+  unsigned short prot;
+  if (strlen(proto) != 3 || (proto[0] != 'P' && proto[0] != 'J'))
+    return 0;
+  prot = atoi(proto+1);
+  if (prot > atoi(MAJOR_PROTOCOL))
+    prot = atoi(MAJOR_PROTOCOL);
+  return prot;
+}
+
+/** Check whether the introduction of a new server would cause a loop
+ * or be disallowed by leaf and hub configuration directives.
+ * @param[in] cptr Neighbor who sent the message.
+ * @param[in] sptr Client that originated the message.
+ * @param[out] ghost If non-NULL, receives ghost timestamp for new server.
+ * @param[in] host Name of new server.
+ * @param[in] numnick Numnick mask of new server.
+ * @param[in] timestamp Claimed link timestamp of new server.
+ * @param[in] hop Number of hops to the new server.
+ * @param[in] junction Non-zero if the new server is still bursting.
+ * @return CPTR_KILLED if \a cptr was SQUIT.  0 if some other server
+ * was SQUIT.  1 if the new server is allowed.
+ */
+static int
+check_loop_and_lh(struct Client* cptr, struct Client *sptr, time_t *ghost, const char *host, const char *numnick, time_t timestamp, int hop, int junction)
+{
+  struct Client* acptr;
+  struct Client* LHcptr = NULL;
+  struct ConfItem* lhconf;
+  int active_lh_line = 0, ii;
+
+  if (ghost)
+    *ghost = 0;
+
+  /*
+   * Calculate type of connect limit and applicable config item.
+   */
+  lhconf = find_conf_byname(cli_confs(cptr), cli_name(cptr), CONF_SERVER);
+  assert(lhconf != NULL);
+  if (ghost)
+  {
+    if (!feature_bool(FEAT_HUB))
+      for (ii = 0; ii <= HighestFd; ii++)
+        if (LocalClientArray[ii] && IsServer(LocalClientArray[ii])) {
+          active_lh_line = 3;
+          break;
+        }
+  }
+  else if (hop > lhconf->maximum)
+  {
+    active_lh_line = 1;
+  }
+  else if (lhconf->hub_limit && match(lhconf->hub_limit, host))
+  {
+    struct Client *ac3ptr;
+    active_lh_line = 2;
+    if (junction)
+      for (ac3ptr = sptr; ac3ptr != &me; ac3ptr = cli_serv(ac3ptr)->up)
+        if (IsJunction(ac3ptr)) {
+          LHcptr = ac3ptr;
+          break;
+        }
+  }
+
+  /*
+   *  We want to find IsConnecting() and IsHandshake() too,
+   *  use FindClient().
+   *  The second finds collisions with numeric representation of existing
+   *  servers - these shouldn't happen anymore when all upgraded to 2.10.
+   *  -- Run
+   */
+  while ((acptr = FindClient(host))
+         || (numnick && (acptr = FindNServer(numnick))))
+  {
+    /*
+     *  This link is trying feed me a server that I already have
+     *  access through another path
+     *
+     *  Do not allow Uworld to do this.
+     *  Do not allow servers that are juped.
+     *  Do not allow servers that have older link timestamps
+     *    then this try.
+     *  Do not allow servers that use the same numeric as an existing
+     *    server, but have a different name.
+     *
+     *  If my ircd.conf sucks, I can try to connect to myself:
+     */
+    if (acptr == &me)
+      return exit_client_msg(cptr, cptr, &me, "nick collision with me (%s), check server number in M:?", host);
+    /*
+     * Detect wrong numeric.
+     */
+    if (0 != ircd_strcmp(cli_name(acptr), host))
+    {
+      sendcmdto_serv_butone(&me, CMD_WALLOPS, cptr,
+                           ":SERVER Numeric Collision: %s != %s",
+                           cli_name(acptr), host);
+      return exit_client_msg(cptr, cptr, &me,
+          "NUMERIC collision between %s and %s."
+          " Is your server numeric correct ?", host, cli_name(acptr));
+    }
+    /*
+     *  Kill our try, if we had one.
+     */
+    if (IsConnecting(acptr))
+    {
+      if (!active_lh_line && exit_client(cptr, acptr, &me,
+          "Just connected via another link") == CPTR_KILLED)
+        return CPTR_KILLED;
+      /*
+       * We can have only ONE 'IsConnecting', 'IsHandshake' or
+       * 'IsServer', because new 'IsConnecting's are refused to
+       * the same server if we already had it.
+       */
+      break;
+    }
+    /*
+     * Avoid other nick collisions...
+     * This is a doubtful test though, what else would it be
+     * when it has a server.name ?
+     */
+    else if (!IsServer(acptr) && !IsHandshake(acptr))
+      return exit_client_msg(cptr, cptr, &me,
+                             "Nickname %s already exists!", host);
+    /*
+     * Our new server might be a juped server,
+     * or someone trying abuse a second Uworld:
+     */
+    else if (IsServer(acptr) && (0 == ircd_strncmp(cli_info(acptr), "JUPE", 4) ||
+        find_conf_byhost(cli_confs(cptr), cli_name(acptr), CONF_UWORLD)))
+    {
+      if (!IsServer(sptr))
+        return exit_client(cptr, sptr, &me, cli_info(acptr));
+      sendcmdto_serv_butone(&me, CMD_WALLOPS, cptr,
+                           ":Received :%s SERVER %s from %s !?!",
+                            NumServ(cptr), host, cli_name(cptr));
+      return exit_new_server(cptr, sptr, host, timestamp, "%s", cli_info(acptr));
+    }
+    /*
+     * Of course we find the handshake this link was before :)
+     */
+    else if (IsHandshake(acptr) && acptr == cptr)
+      break;
+    /*
+     * Here we have a server nick collision...
+     * We don't want to kill the link that was last /connected,
+     * but we neither want to kill a good (old) link.
+     * Therefor we kill the second youngest link.
+     */
+    if (1)
+    {
+      struct Client* c2ptr = 0;
+      struct Client* c3ptr = acptr;
+      struct Client* ac2ptr;
+      struct Client* ac3ptr;
+
+      /* Search youngest link: */
+      for (ac3ptr = acptr; ac3ptr != &me; ac3ptr = cli_serv(ac3ptr)->up)
+        if (cli_serv(ac3ptr)->timestamp > cli_serv(c3ptr)->timestamp)
+          c3ptr = ac3ptr;
+      if (IsServer(sptr))
+      {
+        for (ac3ptr = sptr; ac3ptr != &me; ac3ptr = cli_serv(ac3ptr)->up)
+          if (cli_serv(ac3ptr)->timestamp > cli_serv(c3ptr)->timestamp)
+            c3ptr = ac3ptr;
+      }
+      if (timestamp > cli_serv(c3ptr)->timestamp)
+      {
+        c3ptr = 0;
+        c2ptr = acptr;          /* Make sure they differ */
+      }
+      /* Search second youngest link: */
+      for (ac2ptr = acptr; ac2ptr != &me; ac2ptr = cli_serv(ac2ptr)->up)
+        if (ac2ptr != c3ptr &&
+            cli_serv(ac2ptr)->timestamp >
+            (c2ptr ? cli_serv(c2ptr)->timestamp : timestamp))
+          c2ptr = ac2ptr;
+      if (IsServer(sptr))
+      {
+        for (ac2ptr = sptr; ac2ptr != &me; ac2ptr = cli_serv(ac2ptr)->up)
+          if (ac2ptr != c3ptr &&
+              cli_serv(ac2ptr)->timestamp >
+              (c2ptr ? cli_serv(c2ptr)->timestamp : timestamp))
+            c2ptr = ac2ptr;
+      }
+      if (c3ptr && timestamp > (c2ptr ? cli_serv(c2ptr)->timestamp : timestamp))
+        c2ptr = 0;
+      /* If timestamps are equal, decide which link to break
+       *  by name.
+       */
+      if ((c2ptr ? cli_serv(c2ptr)->timestamp : timestamp) ==
+          (c3ptr ? cli_serv(c3ptr)->timestamp : timestamp))
+      {
+        const char *n2, *n2up, *n3, *n3up;
+        if (c2ptr)
+        {
+          n2 = cli_name(c2ptr);
+          n2up = MyConnect(c2ptr) ? cli_name(&me) : cli_name(cli_serv(c2ptr)->up);
+        }
+        else
+        {
+          n2 = host;
+          n2up = IsServer(sptr) ? cli_name(sptr) : cli_name(&me);
+        }
+        if (c3ptr)
+        {
+          n3 = cli_name(c3ptr);
+          n3up = MyConnect(c3ptr) ? cli_name(&me) : cli_name(cli_serv(c3ptr)->up);
+        }
+        else
+        {
+          n3 = host;
+          n3up = IsServer(sptr) ? cli_name(sptr) : cli_name(&me);
+        }
+        if (strcmp(n2, n2up) > 0)
+          n2 = n2up;
+        if (strcmp(n3, n3up) > 0)
+          n3 = n3up;
+        if (strcmp(n3, n2) > 0)
+        {
+          ac2ptr = c2ptr;
+          c2ptr = c3ptr;
+          c3ptr = ac2ptr;
+        }
+      }
+      /* Now squit the second youngest link: */
+      if (!c2ptr)
+        return exit_new_server(cptr, sptr, host, timestamp,
+                               "server %s already exists and is %ld seconds younger.",
+                               host, (long)cli_serv(acptr)->timestamp - (long)timestamp);
+      else if (cli_from(c2ptr) == cptr || IsServer(sptr))
+      {
+        struct Client *killedptrfrom = cli_from(c2ptr);
+        if (active_lh_line)
+        {
+          /*
+           * If the L: or H: line also gets rid of this link,
+           * we sent just one squit.
+           */
+          if (LHcptr && a_kills_b_too(LHcptr, c2ptr))
+            break;
+          /*
+           * If breaking the loop here solves the L: or H:
+           * line problem, we don't squit that.
+           */
+          if (cli_from(c2ptr) == cptr || (LHcptr && a_kills_b_too(c2ptr, LHcptr)))
+            active_lh_line = 0;
+          else
+          {
+            /*
+             * If we still have a L: or H: line problem,
+             * we prefer to squit the new server, solving
+             * loop and L:/H: line problem with only one squit.
+             */
+            LHcptr = 0;
+            break;
+          }
+        }
+        /*
+         * If the new server was introduced by a server that caused a
+         * Ghost less then 20 seconds ago, this is probably also
+         * a Ghost... (20 seconds is more then enough because all
+         * SERVER messages are at the beginning of a net.burst). --Run
+         */
+        if (CurrentTime - cli_serv(cptr)->ghost < 20)
+        {
+          killedptrfrom = cli_from(acptr);
+          if (exit_client(cptr, acptr, &me, "Ghost loop") == CPTR_KILLED)
+            return CPTR_KILLED;
+        }
+        else if (exit_client_msg(cptr, c2ptr, &me,
+            "Loop <-- %s (new link is %ld seconds younger)", host,
+            (c3ptr ? (long)cli_serv(c3ptr)->timestamp : timestamp) -
+            (long)cli_serv(c2ptr)->timestamp) == CPTR_KILLED)
+          return CPTR_KILLED;
+        /*
+         * Did we kill the incoming server off already ?
+         */
+        if (killedptrfrom == cptr)
+          return 0;
+      }
+      else
+      {
+        if (active_lh_line)
+        {
+          if (LHcptr && a_kills_b_too(LHcptr, acptr))
+            break;
+          if (cli_from(acptr) == cptr || (LHcptr && a_kills_b_too(acptr, LHcptr)))
+            active_lh_line = 0;
+          else
+          {
+            LHcptr = 0;
+            break;
+          }
+        }
+        /*
+         * We can't believe it is a lagged server message
+         * when it directly connects to us...
+         * kill the older link at the ghost, rather then
+         * at the second youngest link, assuming it isn't
+         * a REAL loop.
+         */
+        if (ghost)
+          *ghost = CurrentTime;            /* Mark that it caused a ghost */
+        if (exit_client(cptr, acptr, &me, "Ghost") == CPTR_KILLED)
+          return CPTR_KILLED;
+        break;
+      }
+    }
+  }
+
+  if (active_lh_line)
+  {
+    int killed = 0;
+    if (LHcptr)
+      killed = a_kills_b_too(LHcptr, sptr);
+    else
+      LHcptr = sptr;
+    if (active_lh_line == 1)
+    {
+      if (exit_client_msg(cptr, LHcptr, &me,
+                          "Leaf-only link %s <- %s, check L:",
+                          cli_name(cptr), host) == CPTR_KILLED)
+        return CPTR_KILLED;
+    }
+    else if (active_lh_line == 2)
+    {
+      if (exit_client_msg(cptr, LHcptr, &me,
+                          "Non-Hub link %s <- %s, check H:",
+                          cli_name(cptr), host) == CPTR_KILLED)
+        return CPTR_KILLED;
+    }
+    else
+    {
+      ServerStats->is_ref++;
+      if (exit_client(cptr, LHcptr, &me, "I'm a leaf, define HUB") == CPTR_KILLED)
+        return CPTR_KILLED;
+    }
+    /*
+     * Did we kill the incoming server off already ?
+     */
+    if (killed)
+      return 0;
+  }
+
+  return 1;
+}
+
+/** Update server start timestamps and TS offsets.
+ * @param[in] cptr Server that just connected.
+ * @param[in] timestamp Current time according to \a cptr.
+ * @param[in] start_timestamp Time that \a cptr started.
+ * @param[in] recv_time Current time as we know it.
+ */
+static void
+check_start_timestamp(struct Client *cptr, time_t timestamp, time_t start_timestamp, time_t recv_time)
+{
+  Debug((DEBUG_DEBUG, "My start time: %Tu; other's start time: %Tu",
+         cli_serv(&me)->timestamp, start_timestamp));
+  Debug((DEBUG_DEBUG, "Receive time: %Tu; received timestamp: %Tu; "
+         "difference %ld", recv_time, timestamp, timestamp - recv_time));
+  if (feature_bool(FEAT_RELIABLE_CLOCK)) {
+    if (start_timestamp < cli_serv(&me)->timestamp)
+      cli_serv(&me)->timestamp = start_timestamp;
+    if (IsUnknown(cptr))
+      cli_serv(cptr)->timestamp = TStime();
+  } else if (start_timestamp < cli_serv(&me)->timestamp) {
+    sendto_opmask_butone(0, SNO_OLDSNO, "got earlier start time: "
+                         "%Tu < %Tu", start_timestamp,
+                         cli_serv(&me)->timestamp);
+    cli_serv(&me)->timestamp = start_timestamp;
+    TSoffset += timestamp - recv_time;
+    sendto_opmask_butone(0, SNO_OLDSNO, "clock adjusted by adding %d",
+                         (int)(timestamp - recv_time));
+  } else if ((start_timestamp > cli_serv(&me)->timestamp) &&
+             IsUnknown(cptr)) {
+    cli_serv(cptr)->timestamp = TStime();
+  } else if (timestamp != recv_time) {
+    /*
+     * Equal start times, we have a collision.  Let the connected-to
+     * server decide. This assumes leafs issue more than half of the
+     * connection attempts.
+     */
+    if (IsUnknown(cptr))
+      cli_serv(cptr)->timestamp = TStime();
+    else if (IsHandshake(cptr)) {
+      sendto_opmask_butone(0, SNO_OLDSNO, "clock adjusted by adding %d",
+                           (int)(timestamp - recv_time));
+      TSoffset += timestamp - recv_time;
+    }
+  }
+}
+
+/** Interpret a server's flags.
+ *
+ * @param[in] cptr New server structure.
+ * @param[in] flags String listing server's P10 flags.
+ */
+void set_server_flags(struct Client *cptr, const char *flags)
+{
+    while (*flags) switch (*flags++) {
+    case 'h': SetHub(cptr); break;
+    case 's': SetService(cptr); break;
+       case 'm': SetMaster(cptr); break;
+    case '6': SetIPv6(cptr); break;
+    }
+}
+
+/** Handle a SERVER message from an unregistered connection.
+ *
+ * \a parv has the following elements:
+ * \li \a parv[1] is the server name
+ * \li \a parv[2] is the hop count to the server
+ * \li \a parv[3] is the start timestamp for the server
+ * \li \a parv[4] is the link timestamp
+ * \li \a parv[5] is the protocol version (P10 or J10)
+ * \li \a parv[6] is the numnick mask for the server
+ * \li \a parv[7] is a string of flags like +hs to mark hubs and services
+ * \li \a parv[\a parc - 1] is the server description
+ *
+ * See @ref m_functions for discussion of the arguments.
+ * @param[in] cptr Client that sent us the message.
+ * @param[in] sptr Original source of message.
+ * @param[in] parc Number of arguments.
+ * @param[in] parv Argument vector.
+ */
+int mr_server(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  char*            host;
+  struct ConfItem* aconf;
+  struct Jupe*     ajupe;
+  int              hop;
+  int              ret;
+  unsigned short   prot;
+  time_t           start_timestamp;
+  time_t           timestamp;
+  time_t           recv_time;
+  time_t           ghost;
+
+  if (IsUserPort(cptr))
+    return exit_client_msg(cptr, cptr, &me,
+                           "Cannot connect a server to a user port");
+
+  if (parc < 8)
+  {
+    need_more_params(sptr, "SERVER");
+    return exit_client(cptr, cptr, &me, "Need more parameters");
+  }
+  host = clean_servername(parv[1]);
+  if (!host)
+  {
+    sendto_opmask_butone(0, SNO_OLDSNO, "Bogus server name (%s) from %s",
+                        host, cli_name(cptr));
+    return exit_client_msg(cptr, cptr, &me, "Bogus server name (%s)", host);
+  }
+
+  if ((ajupe = jupe_find(host)) && JupeIsActive(ajupe))
+    return exit_client_msg(cptr, sptr, &me, "Juped: %s", JupeReason(ajupe));
+
+  /* check connection rules */
+  if (0 != conf_eval_crule(host, CRULE_ALL)) {
+    ServerStats->is_ref++;
+    sendto_opmask_butone(0, SNO_OLDSNO, "Refused connection from %s.", cli_name(cptr));
+    return exit_client(cptr, cptr, &me, "Disallowed by connection rule");
+  }
+
+  log_write(LS_NETWORK, L_NOTICE, LOG_NOSNOTICE, "SERVER: %s %s[%s]", host,
+           cli_sockhost(cptr), cli_sock_ip(cptr));
+
+  /*
+   * Detect protocol
+   */
+  hop = atoi(parv[2]);
+  start_timestamp = atoi(parv[3]);
+  timestamp = atoi(parv[4]);
+  prot = parse_protocol(parv[5]);
+  if (!prot)
+    return exit_client_msg(cptr, sptr, &me, "Bogus protocol (%s)", parv[5]);
+  else if (prot < atoi(MINOR_PROTOCOL))
+    return exit_new_server(cptr, sptr, host, timestamp,
+                           "Incompatible protocol: %s", parv[5]);
+
+  Debug((DEBUG_INFO, "Got SERVER %s with timestamp [%s] age %Tu (%Tu)",
+        host, parv[4], start_timestamp, cli_serv(&me)->timestamp));
+
+  if (timestamp < OLDEST_TS || start_timestamp < OLDEST_TS)
+    return exit_client_msg(cptr, sptr, &me,
+        "Bogus timestamps (%s %s)", parv[3], parv[4]);
+
+  /* If the server had a different name before, change it. */
+  if (!EmptyString(cli_name(cptr)) &&
+      (IsUnknown(cptr) || IsHandshake(cptr)) &&
+      0 != ircd_strcmp(cli_name(cptr), host))
+    hChangeClient(cptr, host);
+  ircd_strncpy(cli_name(cptr), host, HOSTLEN);
+  ircd_strncpy(cli_info(cptr), parv[parc-1][0] ? parv[parc-1] : cli_name(&me), REALLEN);
+  cli_hopcount(cptr) = hop;
+
+  if (conf_check_server(cptr)) {
+    ++ServerStats->is_ref;
+    sendto_opmask_butone(0, SNO_OLDSNO, "Received unauthorized connection "
+                         "from %s.", cli_name(cptr));
+    log_write(LS_NETWORK, L_NOTICE, LOG_NOSNOTICE, "Received unauthorized "
+              "connection from %C [%s]", cptr,
+              ircd_ntoa(&cli_ip(cptr)));
+    return exit_client(cptr, cptr, &me, "No Connect block");
+  }
+
+  host = cli_name(cptr);
+
+  update_load();
+
+  if (!(aconf = find_conf_byname(cli_confs(cptr), host, CONF_SERVER))) {
+    ++ServerStats->is_ref;
+    sendto_opmask_butone(0, SNO_OLDSNO, "Access denied. No conf line for "
+                         "server %s", cli_name(cptr));
+    return exit_client_msg(cptr, cptr, &me,
+                           "Access denied. No conf line for server %s", cli_name(cptr));
+  }
+
+  if (*aconf->passwd && !!strcmp(aconf->passwd, cli_passwd(cptr))) {
+    ++ServerStats->is_ref;
+    sendto_opmask_butone(0, SNO_OLDSNO, "Access denied (passwd mismatch) %s",
+                         cli_name(cptr));
+    return exit_client_msg(cptr, cptr, &me,
+                           "No Access (passwd mismatch) %s", cli_name(cptr));
+  }
+
+  memset(cli_passwd(cptr), 0, sizeof(cli_passwd(cptr)));
+
+  ret = check_loop_and_lh(cptr, sptr, &ghost, host, (parc > 7 ? parv[6] : NULL), timestamp, hop, 1);
+  if (ret != 1)
+    return ret;
+
+  make_server(cptr);
+  cli_serv(cptr)->timestamp = timestamp;
+  cli_serv(cptr)->prot = prot;
+  cli_serv(cptr)->ghost = ghost;
+  memset(cli_privs(cptr), 255, sizeof(struct Privs));
+  ClrPriv(cptr, PRIV_SET);
+  SetServerYXX(cptr, cptr, parv[6]);
+
+  /* Attach any necessary UWorld config items. */
+  attach_confs_byhost(cptr, host, CONF_UWORLD);
+
+  if (*parv[7] == '+')
+    set_server_flags(cptr, parv[7] + 1);
+
+  recv_time = TStime();
+  check_start_timestamp(cptr, timestamp, start_timestamp, recv_time);
+  ret = server_estab(cptr, aconf);
+
+  if (feature_bool(FEAT_RELIABLE_CLOCK) &&
+      abs(cli_serv(cptr)->timestamp - recv_time) > 30) {
+    sendto_opmask_butone(0, SNO_OLDSNO, "Connected to a net with a "
+                        "timestamp-clock difference of %Td seconds! "
+                        "Used SETTIME to correct this.",
+                        timestamp - recv_time);
+    sendcmdto_prio_one(&me, CMD_SETTIME, cptr, "%Tu :%s", TStime(),
+                      cli_name(&me));
+  }
+
+  return ret;
+}
+
+/** Handle a SERVER message from another server.
+ *
+ * \a parv has the following elements:
+ * \li \a parv[1] is the server name
+ * \li \a parv[2] is the hop count to the server
+ * \li \a parv[3] is the start timestamp for the server
+ * \li \a parv[4] is the link timestamp
+ * \li \a parv[5] is the protocol version (P10 or J10)
+ * \li \a parv[6] is the numnick mask for the server
+ * \li \a parv[7] is a string of flags like +hs to mark hubs and services
+ * \li \a parv[\a parc - 1] is the server description
+ *
+ * See @ref m_functions for discussion of the arguments.
+ * @param[in] cptr Client that sent us the message.
+ * @param[in] sptr Original source of message.
+ * @param[in] parc Number of arguments.
+ * @param[in] parv Argument vector.
+ */
+int ms_server(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  int              i;
+  char*            host;
+  struct Client*   acptr;
+  struct Client*   bcptr;
+  int              hop;
+  int              ret;
+  unsigned short   prot;
+  time_t           start_timestamp;
+  time_t           timestamp;
+
+  if (parc < 8)
+  {
+    return need_more_params(sptr, "SERVER");
+    return exit_client(cptr, cptr, &me, "Need more parameters");
+  }
+  host = clean_servername(parv[1]);
+  if (!host)
+  {
+    sendto_opmask_butone(0, SNO_OLDSNO, "Bogus server name (%s) from %s",
+                        host, cli_name(cptr));
+    return exit_client_msg(cptr, cptr, &me, "Bogus server name (%s)", host);
+  }
+
+  /*
+   * Detect protocol
+   */
+  hop = atoi(parv[2]);
+  start_timestamp = atoi(parv[3]);
+  timestamp = atoi(parv[4]);
+  prot = parse_protocol(parv[5]);
+  if (!prot)
+    return exit_client_msg(cptr, sptr, &me, "Bogus protocol (%s)", parv[5]);
+  else if (prot < atoi(MINOR_PROTOCOL))
+    return exit_new_server(cptr, sptr, host, timestamp,
+                           "Incompatible protocol: %s", parv[5]);
+
+  Debug((DEBUG_INFO, "Got SERVER %s with timestamp [%s] age %Tu (%Tu)",
+        host, parv[4], start_timestamp, cli_serv(&me)->timestamp));
+
+  if (timestamp < OLDEST_TS)
+    return exit_client_msg(cptr, sptr, &me,
+        "Bogus timestamps (%s %s)", parv[3], parv[4]);
+
+  if (parv[parc - 1][0] == '\0')
+    return exit_client_msg(cptr, cptr, &me,
+                           "No server info specified for %s", host);
+
+  ret = check_loop_and_lh(cptr, sptr, NULL, host, (parc > 7 ? parv[6] : NULL), timestamp, hop, parv[5][0] == 'J');
+  if (ret != 1)
+    return ret;
+
+  /*
+   * Server is informing about a new server behind
+   * this link. Create REMOTE server structure,
+   * add it to list and propagate word to my other
+   * server links...
+   */
+
+  acptr = make_client(cptr, STAT_SERVER);
+  make_server(acptr);
+  cli_serv(acptr)->prot = prot;
+  cli_serv(acptr)->timestamp = timestamp;
+  cli_hopcount(acptr) = hop;
+  ircd_strncpy(cli_name(acptr), host, HOSTLEN);
+  ircd_strncpy(cli_info(acptr), parv[parc-1], REALLEN);
+  cli_serv(acptr)->up = sptr;
+  cli_serv(acptr)->updown = add_dlink(&(cli_serv(sptr))->down, acptr);
+  /* Use cptr, because we do protocol 9 -> 10 translation
+     for numeric nicks ! */
+  SetServerYXX(cptr, acptr, parv[6]);
+
+  /* Attach any necessary UWorld config items. */
+  attach_confs_byhost(cptr, host, CONF_UWORLD);
+
+  if (*parv[7] == '+')
+    set_server_flags(acptr, parv[7] + 1);
+
+  Count_newremoteserver(UserStats);
+  if (Protocol(acptr) < 10)
+    SetFlag(acptr, FLAG_TS8);
+  add_client_to_list(acptr);
+  hAddClient(acptr);
+  if (*parv[5] == 'J')
+  {
+    SetBurst(acptr);
+    SetJunction(acptr);
+    for (bcptr = cli_serv(acptr)->up; !IsMe(bcptr); bcptr = cli_serv(bcptr)->up)
+      if (IsBurstOrBurstAck(bcptr))
+          break;
+    if (IsMe(bcptr))
+      sendto_opmask_butone(0, SNO_NETWORK, "Net junction: %s %s",
+                           cli_name(sptr), cli_name(acptr));
+  }
+  /*
+   * Old sendto_serv_but_one() call removed because we now need to send
+   * different names to different servers (domain name matching).
+   */
+  for (i = 0; i <= HighestFd; i++)
+  {
+    if (!(bcptr = LocalClientArray[i]) || !IsServer(bcptr) ||
+        bcptr == cptr || IsMe(bcptr))
+      continue;
+    if (0 == match(cli_name(&me), cli_name(acptr)))
+      continue;
+    sendcmdto_one(sptr, CMD_SERVER, bcptr, "%s %d 0 %s %s %s%s +%s%s%s%s :%s",
+                  cli_name(acptr), hop + 1, parv[4], parv[5],
+                  NumServCap(acptr), IsHub(acptr) ? "h" : "",
+                  IsService(acptr) ? "s" : "",IsMaster(acptr) ? "m" : "", IsIPv6(acptr) ? "6" : "",
+                  cli_info(acptr));
+  }
+  return 0;
+}
diff --git a/ircd/m_set.c b/ircd/m_set.c
new file mode 100644 (file)
index 0000000..cd8f06a
--- /dev/null
@@ -0,0 +1,103 @@
+/*
+ * IRC - Internet Relay Chat, ircd/m_set.c
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ *                    University of Oulu, Computing Center
+ *
+ * See file AUTHORS in IRC package for additional names of
+ * the programmers.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id: m_set.c 1271 2004-12-11 05:14:07Z klmitch $
+ */
+
+/*
+ * m_functions execute protocol messages on this server:
+ *
+ *    cptr    is always NON-NULL, pointing to a *LOCAL* client
+ *            structure (with an open socket connected!). This
+ *            identifies the physical socket where the message
+ *            originated (or which caused the m_function to be
+ *            executed--some m_functions may call others...).
+ *
+ *    sptr    is the source of the message, defined by the
+ *            prefix part of the message if present. If not
+ *            or prefix not found, then sptr==cptr.
+ *
+ *            (!IsServer(cptr)) => (cptr == sptr), because
+ *            prefixes are taken *only* from servers...
+ *
+ *            (IsServer(cptr))
+ *                    (sptr == cptr) => the message didn't
+ *                    have the prefix.
+ *
+ *                    (sptr != cptr && IsServer(sptr) means
+ *                    the prefix specified servername. (?)
+ *
+ *                    (sptr != cptr && !IsServer(sptr) means
+ *                    that message originated from a remote
+ *                    user (not local).
+ *
+ *            combining
+ *
+ *            (!IsServer(sptr)) means that, sptr can safely
+ *            taken as defining the target structure of the
+ *            message in this server.
+ *
+ *    *Always* true (if 'parse' and others are working correct):
+ *
+ *    1)      sptr->from == cptr  (note: cptr->from == cptr)
+ *
+ *    2)      MyConnect(sptr) <=> sptr == cptr (e.g. sptr
+ *            *cannot* be a local connection, unless it's
+ *            actually cptr!). [MyConnect(x) should probably
+ *            be defined as (x == x->from) --msa ]
+ *
+ *    parc    number of variable parameter strings (if zero,
+ *            parv is allowed to be NULL)
+ *
+ *    parv    a NULL terminated list of parameter pointers,
+ *
+ *                    parv[0], sender (prefix string), if not present
+ *                            this points to an empty string.
+ *                    parv[1]...parv[parc-1]
+ *                            pointers to additional parameters
+ *                    parv[parc] == NULL, *always*
+ *
+ *            note:   it is guaranteed that parv[0]..parv[parc-1] are all
+ *                    non-NULL pointers.
+ */
+#include "config.h"
+
+#include "client.h"
+#include "hash.h"
+#include "ircd.h"
+#include "ircd_features.h"
+#include "ircd_log.h"
+#include "ircd_reply.h"
+#include "ircd_string.h"
+#include "numeric.h"
+#include "numnicks.h"
+#include "send.h"
+
+/* #include <assert.h> -- Now using assert in ircd_log.h */
+
+/*
+ * mo_set - oper message handler
+ */
+int mo_set(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  return feature_set(sptr, (const char* const*)parv + 1, parc - 1);
+}
diff --git a/ircd/m_settime.c b/ircd/m_settime.c
new file mode 100644 (file)
index 0000000..b7d95be
--- /dev/null
@@ -0,0 +1,265 @@
+/*
+ * IRC - Internet Relay Chat, ircd/m_settime.c
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ *                    University of Oulu, Computing Center
+ *
+ * See file AUTHORS in IRC package for additional names of
+ * the programmers.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id: m_settime.c 1271 2004-12-11 05:14:07Z klmitch $
+ */
+
+/*
+ * m_functions execute protocol messages on this server:
+ *
+ *    cptr    is always NON-NULL, pointing to a *LOCAL* client
+ *            structure (with an open socket connected!). This
+ *            identifies the physical socket where the message
+ *            originated (or which caused the m_function to be
+ *            executed--some m_functions may call others...).
+ *
+ *    sptr    is the source of the message, defined by the
+ *            prefix part of the message if present. If not
+ *            or prefix not found, then sptr==cptr.
+ *
+ *            (!IsServer(cptr)) => (cptr == sptr), because
+ *            prefixes are taken *only* from servers...
+ *
+ *            (IsServer(cptr))
+ *                    (sptr == cptr) => the message didn't
+ *                    have the prefix.
+ *
+ *                    (sptr != cptr && IsServer(sptr) means
+ *                    the prefix specified servername. (?)
+ *
+ *                    (sptr != cptr && !IsServer(sptr) means
+ *                    that message originated from a remote
+ *                    user (not local).
+ *
+ *            combining
+ *
+ *            (!IsServer(sptr)) means that, sptr can safely
+ *            taken as defining the target structure of the
+ *            message in this server.
+ *
+ *    *Always* true (if 'parse' and others are working correct):
+ *
+ *    1)      sptr->from == cptr  (note: cptr->from == cptr)
+ *
+ *    2)      MyConnect(sptr) <=> sptr == cptr (e.g. sptr
+ *            *cannot* be a local connection, unless it's
+ *            actually cptr!). [MyConnect(x) should probably
+ *            be defined as (x == x->from) --msa ]
+ *
+ *    parc    number of variable parameter strings (if zero,
+ *            parv is allowed to be NULL)
+ *
+ *    parv    a NULL terminated list of parameter pointers,
+ *
+ *                    parv[0], sender (prefix string), if not present
+ *                            this points to an empty string.
+ *                    parv[1]...parv[parc-1]
+ *                            pointers to additional parameters
+ *                    parv[parc] == NULL, *always*
+ *
+ *            note:   it is guaranteed that parv[0]..parv[parc-1] are all
+ *                    non-NULL pointers.
+ */
+#include "config.h"
+
+#include "client.h"
+#include "hash.h"
+#include "ircd.h"
+#include "ircd_features.h"
+#include "ircd_log.h"
+#include "ircd_reply.h"
+#include "ircd_snprintf.h"
+#include "ircd_string.h"
+#include "list.h"
+#include "msg.h"
+#include "numeric.h"
+#include "numnicks.h"
+#include "s_user.h"
+#include "send.h"
+#include "struct.h"
+
+/* #include <assert.h> -- Now using assert in ircd_log.h */
+#include <stdlib.h>
+
+/*
+ * ms_settime - server message handler
+ *
+ * parv[0] = sender prefix
+ * parv[1] = new time
+ * parv[2] = server name (Only used when sptr is an Oper).
+ */
+int ms_settime(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  time_t t;
+  long dt;
+  static char tbuf[11];
+  struct DLink *lp;
+
+  if (parc < 2) /* verify argument count */
+    return need_more_params(sptr, "SETTIME");
+
+  t = atoi(parv[1]); /* convert time and compute delta */
+  dt = TStime() - t;
+
+  /* verify value */
+  if (t < OLDEST_TS || dt < -9000000)
+  {
+    if (IsServer(sptr)) /* protocol violation if it's from a server */
+      protocol_violation(sptr, "SETTIME: Bad value (%Tu, delta %ld)", t, dt);
+    else
+      sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :SETTIME: Bad value (%Tu, "
+                    "delta %ld)", sptr, t, dt);
+      sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :SETTIME: Bad value", sptr);
+    return 0;
+  }
+
+  /* reset time... */
+  if (feature_bool(FEAT_RELIABLE_CLOCK))
+  {
+    ircd_snprintf(0, tbuf, sizeof(tbuf), "%Tu", TStime());
+    parv[1] = tbuf;
+  }
+
+  if (BadPtr(parv[2])) /* spam the network */
+  {
+    for (lp = cli_serv(&me)->down; lp; lp = lp->next)
+      if (cptr != lp->value.cptr)
+        sendcmdto_prio_one(sptr, CMD_SETTIME, lp->value.cptr, "%s", parv[1]);
+  }
+  else
+  {
+    if (hunt_server_prio_cmd(sptr, CMD_SETTIME, cptr, 1, "%s %C", 2, parc,
+                             parv) != HUNTED_ISME)
+    {
+      /* If the destination was *not* me, but I'm RELIABLE_CLOCK and the
+       * delta is more than 30 seconds off, bounce back a corrected
+       * SETTIME
+       */
+      if (feature_bool(FEAT_RELIABLE_CLOCK) && (dt > 30 || dt < -30))
+        sendcmdto_prio_one(&me, CMD_SETTIME, cptr, "%s %C", parv[1], cptr);
+      return 0;
+    }
+  }
+
+  if (feature_bool(FEAT_RELIABLE_CLOCK))
+  {
+    /* don't apply settime--reliable */
+    if ((dt > 600) || (dt < -600))
+      sendcmdto_serv_butone(&me, CMD_DESYNCH, 0, ":Bad SETTIME from %s: %Tu "
+                            "(delta %ld)", cli_name(sptr), t, dt);
+    /* Let user know we're ignoring him */
+    if (IsUser(sptr))
+    {
+      sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :clock is not set %ld "
+                   "seconds %s : RELIABLE_CLOCK is defined", sptr,
+                   (dt < 0) ? -dt : dt, (dt < 0) ? "forwards" : "backwards");
+    }
+  }
+  else /* tell opers about time change */
+  {
+    sendto_opmask_butone(0, SNO_OLDSNO, "SETTIME from %s, clock is set %ld "
+                        "seconds %s", cli_name(sptr), (dt < 0) ? -dt : dt,
+                        (dt < 0) ? "forwards" : "backwards");
+    /* Apply time change... */
+    TSoffset -= dt;
+    /* Let the issuing user know what we did... */
+    if (IsUser(sptr))
+    {
+      sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :clock is set %ld seconds %s",
+                    sptr, (dt < 0) ? -dt : dt,
+                    (dt < 0) ? "forwards" : "backwards");
+    }
+  }
+
+  return 0;
+}
+
+/*
+ * mo_settime - oper message handler
+ *
+ * parv[0] = sender prefix
+ * parv[1] = new time
+ * parv[2] = servername (Only used when sptr is an Oper).
+ */
+int mo_settime(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  time_t t;
+  long dt;
+  static char tbuf[11];
+
+  /* Must be a global oper */
+  if (!IsOper(sptr))
+    return send_reply(sptr, ERR_NOPRIVILEGES);
+
+  if (parc < 2) /* verify argument count */
+    return need_more_params(sptr, "SETTIME");
+
+  if (parc == 2 && MyUser(sptr)) /* default to me */
+    parv[parc++] = cli_name(&me);
+
+  t = atoi(parv[1]); /* convert the time */
+
+  /* If we're reliable_clock or if the oper specified a 0 time, use current */
+  if (!t || feature_bool(FEAT_RELIABLE_CLOCK))
+  {
+    t = TStime();
+    ircd_snprintf(0, tbuf, sizeof(tbuf), "%Tu", TStime());
+    parv[1] = tbuf;
+  }
+
+  dt = TStime() - t; /* calculate the delta */
+
+  if (t < OLDEST_TS || dt < -9000000) /* verify value */
+  {
+    sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :SETTIME: Bad value", sptr);
+    return 0;
+  }
+
+  /* OK, send the message off to its destination */
+  if (hunt_server_prio_cmd(sptr, CMD_SETTIME, cptr, 1, "%s %C", 2, parc,
+                           parv) != HUNTED_ISME)
+    return 0;
+
+  if (feature_bool(FEAT_RELIABLE_CLOCK)) /* don't apply settime--reliable */
+  {
+    if ((dt > 600) || (dt < -600))
+      sendcmdto_serv_butone(&me, CMD_DESYNCH, 0, ":Bad SETTIME from %s: %Tu "
+                            "(delta %ld)", cli_name(sptr), t, dt);
+    if (IsUser(sptr)) /* Let user know we're ignoring him */
+      sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :clock is not set %ld seconds "
+                    "%s: RELIABLE_CLOCK is defined", sptr, (dt < 0) ? -dt : dt,
+                    (dt < 0) ? "forwards" : "backwards");
+  }
+  else /* tell opers about time change */
+  {
+    sendto_opmask_butone(0, SNO_OLDSNO, "SETTIME from %s, clock is set %ld "
+                        "seconds %s", cli_name(sptr), (dt < 0) ? -dt : dt,
+                        (dt < 0) ? "forwards" : "backwards");
+    TSoffset -= dt; /* apply time change */
+    if (IsUser(sptr)) /* let user know what we did */
+      sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :clock is set %ld seconds %s",
+                   sptr, (dt < 0) ? -dt : dt,
+                   (dt < 0) ? "forwards" : "backwards");
+  }
+
+  return 0;
+}
diff --git a/ircd/m_silence.c b/ircd/m_silence.c
new file mode 100644 (file)
index 0000000..b6b018d
--- /dev/null
@@ -0,0 +1,332 @@
+/*
+ * IRC - Internet Relay Chat, ircd/m_silence.c
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ *                    University of Oulu, Computing Center
+ *
+ * See file AUTHORS in IRC package for additional names of
+ * the programmers.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+/** @file
+ * @brief Handlers for SILENCE command.
+ * @version $Id: m_silence.c 1790 2007-03-27 02:54:44Z entrope $
+ */
+
+#include "config.h"
+
+#include "channel.h"
+#include "client.h"
+#include "hash.h"
+#include "ircd.h"
+#include "ircd_features.h"
+#include "ircd_log.h"
+#include "ircd_reply.h"
+#include "ircd_snprintf.h"
+#include "ircd_string.h"
+#include "list.h"
+#include "msg.h"
+#include "numeric.h"
+#include "numnicks.h"
+#include "s_user.h"
+#include "send.h"
+#include "struct.h"
+
+/* #include <assert.h> -- Now using assert in ircd_log.h */
+#include <stdlib.h>
+#include <string.h>
+
+/** Attempt to apply a SILENCE update to a user.
+ *
+ * Silences are propagated lazily between servers to save on bandwidth
+ * and remote memory.  Any removal and any silence exception must be
+ * propagated until a server has not seen the mask being removed or
+ * has no positive silences for the user.
+ *
+ * @param[in] sptr Client to update.
+ * @param[in] mask Single silence mask to apply, optionally preceded by '+' or '-' and maybe '~'.
+ * @return The new ban entry on success, NULL on failure.
+ */
+static struct Ban *
+apply_silence(struct Client *sptr, char *mask)
+{
+  struct Ban *sile;
+  int flags;
+  int res;
+  char orig_mask[NICKLEN+USERLEN+HOSTLEN+3];
+
+  assert(mask && mask[0]);
+
+  /* Check for add or remove. */
+  if (mask[0] == '-') {
+    flags = BAN_DEL;
+    mask++;
+  } else if (mask[0] == '+') {
+    flags = BAN_ADD;
+    mask++;
+  } else
+    flags = BAN_ADD;
+
+  /* Check for being an exception. */
+  if (mask[0] == '~') {
+    flags |= BAN_EXCEPTION;
+    mask++;
+  }
+
+  /* Make the silence and set additional flags. */
+  ircd_strncpy(orig_mask, mask, sizeof(orig_mask) - 1);
+  sile = make_ban(pretty_mask(mask));
+  sile->flags |= flags;
+
+  /* If they're a local user trying to ban too broad a mask, forbid it. */
+  if (MyUser(sptr)
+      && (sile->flags & BAN_IPMASK)
+      && sile->addrbits > 0
+      && sile->addrbits < (irc_in_addr_is_ipv4(&sile->address) ? 112 : 32)) {
+    send_reply(sptr, ERR_MASKTOOWIDE, orig_mask);
+    free_ban(sile);
+    return NULL;
+  }
+
+  /* Apply it to the silence list. */
+  res = apply_ban(&cli_user(sptr)->silence, sile, 1);
+  return res ? NULL : sile;
+}
+
+/** Apply and send silence updates for a user.
+ * @param[in] sptr Client whose silence list has been updated.
+ * @param[in] silences Comma-separated list of silence updates.
+ * @param[in] dest Direction to send updates in (NULL for broadcast).
+ */
+static void
+forward_silences(struct Client *sptr, char *silences, struct Client *dest)
+{
+  struct Ban *accepted[MAXPARA], *sile, **plast;
+  char *cp, *p, buf[BUFSIZE];
+  size_t ac_count, buf_used, slen, ii;
+
+  /* Split the list of silences and try to apply each one in turn. */
+  for (cp = ircd_strtok(&p, silences, ","), ac_count = 0;
+       cp && (ac_count < MAXPARA);
+       cp = ircd_strtok(&p, 0, ",")) {
+    if ((sile = apply_silence(sptr, cp)))
+      accepted[ac_count++] = sile;
+  }
+
+  if (MyUser(sptr)) {
+    size_t siles, maxsiles, totlength, maxlength, jj;
+
+    /* Check that silence count and total length are permitted. */
+    maxsiles = feature_int(FEAT_MAXSILES);
+    maxlength = maxsiles * feature_int(FEAT_AVBANLEN);
+    siles = totlength = 0;
+    /* Count number of current silences and their total length. */
+    plast = &cli_user(sptr)->silence;
+    for (sile = cli_user(sptr)->silence; sile; sile = sile->next) {
+      if (sile->flags & (BAN_OVERLAPPED | BAN_ADD | BAN_DEL))
+        continue;
+      siles++;
+      totlength += strlen(sile->banstr);
+      plast = &sile->next;
+    }
+    for (ii = jj = 0; ii < ac_count; ++ii) {
+      sile = accepted[ii];
+      /* If the update is being added, and we would exceed the maximum
+       * count or length, drop the update.
+       */
+      if (!(sile->flags & (BAN_OVERLAPPED | BAN_DEL))) {
+        slen = strlen(sile->banstr);
+        if ((siles >= maxsiles) || (totlength + slen >= maxlength)) {
+          *plast = NULL;
+          if (MyUser(sptr))
+            send_reply(sptr, ERR_SILELISTFULL, accepted[ii]->banstr);
+          free_ban(accepted[ii]);
+          continue;
+        }
+        /* Update counts. */
+        siles++;
+        totlength += slen;
+        plast = &sile->next;
+      }
+      /* Store the update. */
+      accepted[jj++] = sile;
+    }
+    /* Write back the number of accepted updates. */
+    ac_count = jj;
+
+    /* Send the silence update list, including overlapped silences (to
+     * make it easier on clients).
+     */
+    buf_used = 0;
+    for (sile = cli_user(sptr)->silence; sile; sile = sile->next) {
+      char ch;
+      if (sile->flags & (BAN_OVERLAPPED | BAN_DEL))
+        ch = '-';
+      else if (sile->flags & BAN_ADD)
+        ch = '+';
+      else
+        continue;
+      slen = strlen(sile->banstr);
+      if (buf_used + slen + 4 > 400) {
+        buf[buf_used] = '\0';
+        sendcmdto_one(sptr, CMD_SILENCE, sptr, "%s", buf);
+        buf_used = 0;
+      }
+      if (buf_used)
+        buf[buf_used++] = ',';
+      buf[buf_used++] = ch;
+      if (sile->flags & BAN_EXCEPTION)
+        buf[buf_used++] = '~';
+      memcpy(buf + buf_used, sile->banstr, slen);
+      buf_used += slen;
+    }
+    if (buf_used > 0) {
+        buf[buf_used] = '\0';
+        sendcmdto_one(sptr, CMD_SILENCE, sptr, "%s", buf);
+        buf_used = 0;
+    }
+  }
+
+  /* Forward any silence removals or exceptions updates to other
+   * servers if the user has positive silences.
+   */
+  if (!dest || !MyUser(dest)) {
+    for (ii = buf_used = 0; ii < ac_count; ++ii) {
+      char ch;
+      sile = accepted[ii];
+      if (sile->flags & BAN_OVERLAPPED)
+        continue;
+      else if (sile->flags & BAN_DEL)
+        ch = '-';
+      else if (sile->flags & BAN_ADD) {
+        if (!(sile->flags & BAN_EXCEPTION))
+          continue;
+        ch = '+';
+      } else
+        continue;
+      slen = strlen(sile->banstr);
+      if (buf_used + slen + 4 > 400) {
+        buf[buf_used] = '\0';
+        if (dest)
+          sendcmdto_one(sptr, CMD_SILENCE, dest, "%C %s", dest, buf);
+        else
+          sendcmdto_serv_butone(sptr, CMD_SILENCE, sptr, "* %s", buf);
+        buf_used = 0;
+      }
+      if (buf_used)
+        buf[buf_used++] = ',';
+      buf[buf_used++] = ch;
+      if (sile->flags & BAN_EXCEPTION)
+        buf[buf_used++] = '~';
+      memcpy(buf + buf_used, sile->banstr, slen);
+      buf_used += slen;
+    }
+    if (buf_used > 0) {
+        buf[buf_used] = '\0';
+        if (dest)
+          sendcmdto_one(sptr, CMD_SILENCE, dest, "%C %s", dest, buf);
+        else
+          sendcmdto_serv_butone(sptr, CMD_SILENCE, sptr, "* %s", buf);
+        buf_used = 0;
+    }
+  }
+
+  /* Remove overlapped and deleted silences from the user's silence
+   * list.  Clear BAN_ADD since we're walking the list anyway.
+   */
+  for (plast = &cli_user(sptr)->silence; (sile = *plast) != NULL; ) {
+    if (sile->flags & (BAN_OVERLAPPED | BAN_DEL)) {
+      *plast = sile->next;
+      free_ban(sile);
+    } else {
+      sile->flags &= ~BAN_ADD;
+      *plast = sile;
+      plast = &sile->next;
+    }
+  }
+
+  /* Free any silence-deleting updates. */
+  for (ii = 0; ii < ac_count; ++ii) {
+    if ((accepted[ii]->flags & (BAN_ADD | BAN_DEL)) == BAN_DEL) {
+      free_ban(accepted[ii]);
+    }
+  }
+}
+
+/** Handle a SILENCE command from a local user.
+ * See @ref m_functions for general discussion of parameters.
+ *
+ * \a parv[1] may be any of the following:
+ * \li Omitted or empty, to view your own silence list.
+ * \li Nickname of a user, to view that user's silence list.
+ * \li A comma-separated list of silence updates
+ *
+ * @param[in] cptr Client that sent us the message.
+ * @param[in] sptr Original source of message.
+ * @param[in] parc Number of arguments.
+ * @param[in] parv Argument vector.
+ */
+int m_silence(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  struct Client *acptr;
+  struct Ban *sile;
+
+  assert(0 != cptr);
+  assert(cptr == sptr);
+
+  /* See if the user is requesting a silence list. */
+  acptr = sptr;
+  if (parc < 2 || EmptyString(parv[1]) || (acptr = FindUser(parv[1]))) {
+    if (cli_user(acptr)) {
+      for (sile = cli_user(acptr)->silence; sile; sile = sile->next) {
+        send_reply(sptr, RPL_SILELIST, cli_name(acptr),
+                   (sile->flags & BAN_EXCEPTION ? "~" : ""),  sile->banstr);
+      }
+    }
+    send_reply(sptr, RPL_ENDOFSILELIST, cli_name(acptr));
+    return 0;
+  }
+
+  /* The user must be attempting to update their list. */
+  forward_silences(sptr, parv[1], NULL);
+  return 0;
+}
+
+/** Handle a SILENCE command from a server.
+ * See @ref m_functions for general discussion of parameters.
+ *
+ * \a parv[1] may be one of the following:
+ * \li "*" to indicate a broadcast update (removing a SILENCE)
+ * \li A client numnick that should be specifically SILENCEd.
+ *
+ * \a parv[2] is a comma-separated list of silence updates.
+ *
+ * @param[in] cptr Client that sent us the message.
+ * @param[in] sptr Original source of message.
+ * @param[in] parc Number of arguments.
+ * @param[in] parv Argument vector.
+ */
+int ms_silence(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  if (IsServer(sptr))
+    return protocol_violation(sptr, "Server trying to silence a user");
+  if (parc < 3 || EmptyString(parv[2]))
+    return need_more_params(sptr, "SILENCE");
+
+  /* Figure out which silences can be forwarded. */
+  forward_silences(sptr, parv[2], findNUser(parv[1]));
+  return 0;
+  (void)cptr;
+}
diff --git a/ircd/m_squit.c b/ircd/m_squit.c
new file mode 100644 (file)
index 0000000..adb4538
--- /dev/null
@@ -0,0 +1,164 @@
+/*
+ * IRC - Internet Relay Chat, ircd/m_squit.c
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ *                    University of Oulu, Computing Center
+ *
+ * See file AUTHORS in IRC package for additional names of
+ * the programmers.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id: m_squit.c 1334 2005-03-20 16:06:30Z entrope $
+ */
+#include "config.h"
+
+#include "client.h"
+#include "hash.h"
+#include "ircd.h"
+#include "ircd_chattr.h"
+#include "ircd_log.h"
+#include "ircd_reply.h"
+#include "ircd_string.h"
+#include "numeric.h"
+#include "numnicks.h"
+#include "match.h"
+#include "s_debug.h"
+#include "s_misc.h"
+#include "s_user.h"
+#include "send.h"
+
+/* #include <assert.h> -- Now using assert in ircd_log.h */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+/*
+ *  ms_squit (server)
+ *
+ *    parv[0] = sender prefix
+ *    parv[1] = server name
+ *    parv[2] = timestamp
+ *    parv[parc-1] = comment
+ *
+ * No longer supports wildcards from servers. 
+ * No longer squits a server that gave us an malformed squit message.
+ *    - Isomer 1999-12-18
+ * 
+ */
+int ms_squit(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  const char* server = parv[1];
+  struct Client *acptr;
+  time_t timestamp = 0;
+  char *comment = 0;
+  
+  if (parc < 2) 
+    return need_more_params(sptr, "SQUIT");
+
+  comment = parv[parc-1];
+  
+  if (BadPtr(parv[parc - 1]))
+       comment = cli_name(sptr);
+       
+  acptr = FindServer(server);
+
+  if (!acptr)
+    acptr = FindNServer(server);
+  
+  if (!acptr) {
+    Debug((DEBUG_NOTICE, "Ignoring SQUIT to an unknown server"));
+    return 0;
+  }
+  
+  if (IsMaster(acptr)) {
+       return 0;
+  }
+  /* If they are squitting me, we reverse it */
+  if (IsMe(acptr))
+    acptr = cptr; /* Bugfix by Prefect */
+
+  if (parc > 2)
+    timestamp = atoi(parv[2]);
+  else
+    protocol_violation(cptr, "SQUIT with no timestamp/reason");
+
+  /* If atoi(parv[2]) == 0 we must indeed squit !
+   * It will be our neighbour.
+   */
+  if ( timestamp != 0 && timestamp != cli_serv(acptr)->timestamp)
+  {
+    Debug((DEBUG_NOTICE, "Ignoring SQUIT with the wrong timestamp"));
+    return 0;
+  }
+  
+  return exit_client(cptr, acptr, sptr, comment);
+}
+
+/*
+ *  mo_squit (oper)
+ *
+ *    parv[0] = sender prefix
+ *    parv[1] = server name
+ *    parv[2] = comment (optional)
+ *
+ */
+int mo_squit(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  const char* server;
+  struct Client *acptr;
+  struct Client *acptr2;
+  char *comment;
+      
+  if (parc < 2) 
+    return need_more_params(sptr, "SQUIT");
+
+  if (parc < 3 || BadPtr(parv[2]))
+    comment = cli_name(sptr);
+  else
+    comment = parv[2];
+
+  server = parv[1];
+  /*
+   * The following allows wild cards in SQUIT. Only useful
+   * when the command is issued by an oper.
+   */
+  for (acptr = GlobalClientList; (acptr = next_client(acptr, server));
+      acptr = cli_next(acptr)) {
+    if (IsServer(acptr) || IsMe(acptr))
+      break;
+  }
+  
+  /* Not found? Bugger. */
+  if (!acptr || IsMe(acptr))
+    return send_reply(sptr, ERR_NOSUCHSERVER, server);
+
+  /*
+   * Look for a matching server that is closer,
+   * that way we won't accidentally squit two close
+   * servers like davis.* and davis-r.* when typing
+   * /SQUIT davis*
+   */
+  for (acptr2 = cli_serv(acptr)->up; acptr2 != &me;
+      acptr2 = cli_serv(acptr2)->up)
+    if (!match(server, cli_name(acptr2)))
+      acptr = acptr2;
+  
+  /* Disallow local opers to squit remote servers */
+  
+  if ((IsLocOp(sptr) && !MyConnect(acptr)) || IsMaster(acptr))
+    return send_reply(sptr, ERR_NOPRIVILEGES);
+
+  return exit_client(cptr, acptr, sptr, comment);
+}
diff --git a/ircd/m_stats.c b/ircd/m_stats.c
new file mode 100644 (file)
index 0000000..e64e437
--- /dev/null
@@ -0,0 +1,166 @@
+/*
+ * IRC - Internet Relay Chat, ircd/m_stats.c
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ *                    University of Oulu, Computing Center
+ *
+ * See file AUTHORS in IRC package for additional names of
+ * the programmers.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id: m_stats.c 1844 2007-11-17 14:21:02Z entrope $
+ */
+
+/*
+ * m_functions execute protocol messages on this server:
+ *
+ *    cptr    is always NON-NULL, pointing to a *LOCAL* client
+ *            structure (with an open socket connected!). This
+ *            identifies the physical socket where the message
+ *            originated (or which caused the m_function to be
+ *            executed--some m_functions may call others...).
+ *
+ *    sptr    is the source of the message, defined by the
+ *            prefix part of the message if present. If not
+ *            or prefix not found, then sptr==cptr.
+ *
+ *            (!IsServer(cptr)) => (cptr == sptr), because
+ *            prefixes are taken *only* from servers...
+ *
+ *            (IsServer(cptr))
+ *                    (sptr == cptr) => the message didn't
+ *                    have the prefix.
+ *
+ *                    (sptr != cptr && IsServer(sptr) means
+ *                    the prefix specified servername. (?)
+ *
+ *                    (sptr != cptr && !IsServer(sptr) means
+ *                    that message originated from a remote
+ *                    user (not local).
+ *
+ *            combining
+ *
+ *            (!IsServer(sptr)) means that, sptr can safely
+ *            taken as defining the target structure of the
+ *            message in this server.
+ *
+ *    *Always* true (if 'parse' and others are working correct):
+ *
+ *    1)      sptr->from == cptr  (note: cptr->from == cptr)
+ *
+ *    2)      MyConnect(sptr) <=> sptr == cptr (e.g. sptr
+ *            *cannot* be a local connection, unless it's
+ *            actually cptr!). [MyConnect(x) should probably
+ *            be defined as (x == x->from) --msa ]
+ *
+ *    parc    number of variable parameter strings (if zero,
+ *            parv is allowed to be NULL)
+ *
+ *    parv    a NULL terminated list of parameter pointers,
+ *
+ *                    parv[0], sender (prefix string), if not present
+ *                            this points to an empty string.
+ *                    parv[1]...parv[parc-1]
+ *                            pointers to additional parameters
+ *                    parv[parc] == NULL, *always*
+ *
+ *            note:   it is guaranteed that parv[0]..parv[parc-1] are all
+ *                    non-NULL pointers.
+ */
+#include "config.h"
+
+#include "client.h"
+#include "ircd.h"
+#include "ircd_features.h"
+#include "ircd_log.h"
+#include "ircd_reply.h"
+#include "ircd_string.h"
+#include "msg.h"
+#include "numeric.h"
+#include "s_stats.h"
+#include "s_user.h"
+#include "send.h"
+#include "struct.h"
+
+/* #include <assert.h> -- Now using assert in ircd_log.h */
+#include <stdlib.h>
+#include <string.h>
+
+/*
+ * m_stats - generic message handler
+ *
+ *    parv[0] = sender prefix
+ *    parv[1] = statistics selector
+ *    parv[2] = target server (current server defaulted, if omitted)
+ * And 'stats l' and 'stats' L:
+ *    parv[3] = server mask ("*" default, if omitted)
+ * Or for stats p,P:
+ *    parv[3] = port mask (returns p-lines when its port is matched by this)
+ * Or for stats k,K,i and I:
+ *    parv[3] = [user@]host.name (returns which K/I-lines match this)
+ *           or [user@]host.mask (returns which K/I-lines are mmatched by this)
+ *              (defaults to old reply if omitted, when local or Oper)
+ *              A remote mask (something containing wildcards) is only
+ *              allowed for IRC Operators.
+ */
+int
+m_stats(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  const struct StatDesc *sd;
+  char *param;
+
+  /* If we didn't find a descriptor, send them help */
+  if ((parc < 2) || !(sd = stats_find(parv[1])))
+      parv[1] = "*", sd = stats_find("*");
+
+  assert(sd != 0);
+
+  /* Check whether the client can issue this command.  If source is
+   * not privileged (server or an operator), then the STAT_FLAG_OPERONLY
+   * flag must not be set, and if the STAT_FLAG_OPERFEAT flag is set,
+   * then the feature given by sd->sd_control must be off.
+   *
+   * This checks cptr rather than sptr so that a local oper may send
+   * /stats queries to other servers.
+   */
+  if (!IsPrivileged(cptr) &&
+      ((sd->sd_flags & STAT_FLAG_OPERONLY) ||
+       ((sd->sd_flags & STAT_FLAG_OPERFEAT) && feature_bool(sd->sd_control))))
+    return send_reply(sptr, ERR_NOPRIVILEGES);
+
+  /* Check for extra parameter */
+  if ((sd->sd_flags & STAT_FLAG_VARPARAM) && parc > 3 && !EmptyString(parv[3]))
+    param = parv[3];
+  else
+    param = NULL;
+
+  /* Ok, track down who's supposed to get this... */
+  if (hunt_server_cmd(sptr, CMD_STATS, cptr, feature_int(FEAT_HIS_REMOTE),
+                     param ? "%s %C :%s" : "%s :%C", 2, parc, parv) !=
+      HUNTED_ISME)
+    return 0; /* Someone else--cool :) */
+
+  /* Check if they are a local user */
+  if ((sd->sd_flags & STAT_FLAG_LOCONLY) && !MyUser(sptr))
+    return send_reply(sptr, ERR_NOPRIVILEGES);
+
+  assert(sd->sd_func != 0);
+
+  /* Ok, dispatch the stats function */
+  (*sd->sd_func)(sptr, sd, param);
+
+  /* Done sending them the stats */
+  return send_reply(sptr, RPL_ENDOFSTATS, parv[1]);
+}
diff --git a/ircd/m_svsjoin.c b/ircd/m_svsjoin.c
new file mode 100644 (file)
index 0000000..94156fd
--- /dev/null
@@ -0,0 +1,166 @@
+/*
+ * IRC - Internet Relay Chat, ircd/m_svsjoin.c
+ * Written by David Herrmann.
+ */
+
+#include "config.h"
+
+#include "channel.h"
+#include "client.h"
+#include "handlers.h"
+#include "hash.h"
+#include "ircd.h"
+#include "ircd_chattr.h"
+#include "ircd_features.h"
+#include "ircd_reply.h"
+#include "ircd_string.h"
+#include "msg.h"
+#include "numeric.h"
+#include "numnicks.h"
+#include "s_debug.h"
+#include "s_user.h"
+#include "send.h"
+
+#include <string.h>
+#include <ctype.h>
+#include <stdlib.h>
+
+/** SVSJOIN
+ * SVSJOIN is forwarded to the server where the user is connected to.
+ * This allows to send SVSJOINs from all servers in the network but additionally causes
+ * some overhead. Though, SVSJOIN is not often called and this overhead can be ignored.
+ */
+int m_svsjoin(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
+{
+    struct Client *acptr;
+    struct Channel *chptr;
+    struct JoinBuf join;
+    struct JoinBuf create;
+    unsigned int flags = 0;
+    char *name;
+
+       if (!IsNetServ(sptr) || !HasFlag(sptr, FLAG_SECURITY_SERV))
+    return send_reply(sptr, ERR_NOPRIVILEGES);
+       
+    if(parc < 3) {
+        return protocol_violation(cptr, "Too few arguments for SVSJOIN");
+    }
+
+    /* Ignore if the user has already quitted. */
+    if(!(acptr = FindUser(parv[1]))) {
+        return 0;
+    }
+
+    /* Check channelname. */
+    if(!IsChannelName(parv[2]) || !strIsIrcCh(parv[2])) {
+        return 0;
+    }
+
+    /* Create channel if necessary and return a pointer. */
+    chptr = get_channel(acptr, parv[2], (!FindChannel(parv[2])) ? CGT_CREATE : CGT_NO_CREATE);
+    if(find_member_link(chptr, acptr)) return 0; /* User is already in the channel. */
+
+    /* Forward the message to the server where the user is connected to. */
+    if(!MyConnect(acptr)) {
+           const struct User* user = cli_user(acptr);
+               struct Client *server = user->server; 
+        sendcmdto_one(sptr, CMD_SVSJOIN, acptr, "%s%s %s", cli_yxx(server), cli_yxx(acptr), chptr->chname);
+        return 0;
+    }
+
+    name = chptr->chname;
+
+    /* We need to use \joinbuf to let a user join.
+     * We fill only the \joinbuf which is actually used but
+     * create both.
+     */
+
+    joinbuf_init(&join, acptr, acptr, JOINBUF_TYPE_JOIN, 0, 0);
+    joinbuf_init(&create, acptr, acptr, JOINBUF_TYPE_CREATE, 0, TStime());
+
+    flags = (chptr->users == 0) ? CHFL_CHANOP : CHFL_DEOPPED;
+    if(chptr) joinbuf_join(&join, chptr, flags);
+    else joinbuf_join(&create, chptr, flags);
+
+    /* Send information to the user. */
+    if(chptr->topic[0]) {
+        send_reply(acptr, RPL_TOPIC, chptr->chname, chptr->topic);
+        send_reply(acptr, RPL_TOPICWHOTIME, chptr->chname, chptr->topic_nick, chptr->topic_time);
+    }
+    do_names(acptr, chptr, NAMES_ALL|NAMES_EON);
+
+    joinbuf_flush(&join);
+    joinbuf_flush(&create);
+
+    return 0;
+}
+
+/* ms_svsjoin - server message handler
+ *
+ * parv[0] = sender prefix
+ * parv[1] = numeric of client
+ * parv[2] = channel, NO CHANLIST!
+ */
+signed int ms_svsjoin(struct Client* cptr, struct Client* sptr, signed int parc, char* parv[]) {
+    struct Client *acptr;
+    struct Channel *chptr;
+    struct JoinBuf join;
+    struct JoinBuf create;
+    unsigned int flags = 0;
+    char *name;
+
+    if(parc < 3) {
+        return protocol_violation(cptr, "Too few arguments for SVSJOIN");
+    }
+
+    /* Ignore if the user has already quitted. */
+    if(!(acptr = findNUser(parv[1]))) {
+        return 0;
+    }
+
+    /* Check channelname. */
+    if(!IsChannelName(parv[2]) || !strIsIrcCh(parv[2])) {
+        return 0;
+    }
+
+    /* Create channel if necessary and return a pointer. */
+    chptr = get_channel(acptr, parv[2], (!FindChannel(parv[2])) ? CGT_CREATE : CGT_NO_CREATE);
+    if(find_member_link(chptr, acptr)) return 0; /* User is already in the channel. */
+
+    /* Forward the message to the server where the user is connected to. */
+    if(!MyConnect(acptr)) {
+        sendcmdto_one(sptr, CMD_SVSJOIN, acptr, "%s %s", parv[1], chptr->chname);
+        return 0;
+    }
+    
+    #ifndef UNRESTRICTED_SERV
+    
+    name = chptr->chname;
+
+    /* We need to use \joinbuf to let a user join.
+     * We fill only the \joinbuf which is actually used but
+     * create both.
+     */
+
+    joinbuf_init(&join, acptr, acptr, JOINBUF_TYPE_JOIN, 0, 0);
+    joinbuf_init(&create, acptr, acptr, JOINBUF_TYPE_CREATE, 0, TStime());
+
+    flags = (chptr->users == 0) ? CHFL_CHANOP : CHFL_DEOPPED;
+    if(chptr) joinbuf_join(&join, chptr, flags);
+    else joinbuf_join(&create, chptr, flags);
+
+    /* Send information to the user. */
+    if(chptr->topic[0]) {
+        send_reply(acptr, RPL_TOPIC, chptr->chname, chptr->topic);
+        send_reply(acptr, RPL_TOPICWHOTIME, chptr->chname, chptr->topic_nick, chptr->topic_time);
+    }
+    do_names(acptr, chptr, NAMES_ALL|NAMES_EON);
+
+    joinbuf_flush(&join);
+    joinbuf_flush(&create);
+    
+    #endif
+
+    return 0;
+}
+
diff --git a/ircd/m_svsmode.c b/ircd/m_svsmode.c
new file mode 100644 (file)
index 0000000..c634978
--- /dev/null
@@ -0,0 +1,192 @@
+/*
+ * IRC - Internet Relay Chat, ircd/m_svsmode.c
+ * Written by David Herrmann.
+ */
+
+/*
+ * m_functions execute protocol messages on this server:
+ *
+ *    cptr    is always NON-NULL, pointing to a *LOCAL* client
+ *            structure (with an open socket connected!). This
+ *            identifies the physical socket where the message
+ *            originated (or which caused the m_function to be
+ *            executed--some m_functions may call others...).
+ *
+ *    sptr    is the source of the message, defined by the
+ *            prefix part of the message if present. If not
+ *            or prefix not found, then sptr==cptr.
+ *
+ *            (!IsServer(cptr)) => (cptr == sptr), because
+ *            prefixes are taken *only* from servers...
+ *
+ *            (IsServer(cptr))
+ *                    (sptr == cptr) => the message didn't
+ *                    have the prefix.
+ *
+ *                    (sptr != cptr && IsServer(sptr) means
+ *                    the prefix specified servername. (?)
+ *
+ *                    (sptr != cptr && !IsServer(sptr) means
+ *                    that message originated from a remote
+ *                    user (not local).
+ *
+ *            combining
+ *
+ *            (!IsServer(sptr)) means that, sptr can safely
+ *            taken as defining the target structure of the
+ *            message in this server.
+ *
+ *    *Always* true (if 'parse' and others are working correct):
+ *
+ *    1)      sptr->from == cptr  (note: cptr->from == cptr)
+ *
+ *    2)      MyConnect(sptr) <=> sptr == cptr (e.g. sptr
+ *            *cannot* be a local connection, unless it's
+ *            actually cptr!). [MyConnect(x) should probably
+ *            be defined as (x == x->from) --msa ]
+ *
+ *    parc    number of variable parameter strings (if zero,
+ *            parv is allowed to be NULL)
+ *
+ *    parv    a NULL terminated list of parameter pointers,
+ *
+ *                    parv[0], sender (prefix string), if not present
+ *                            this points to an empty string.
+ *                    parv[1]...parv[parc-1]
+ *                            pointers to additional parameters
+ *                    parv[parc] == NULL, *always*
+ *
+ *            note:   it is guaranteed that parv[0]..parv[parc-1] are all
+ *                    non-NULL pointers.
+ */
+#include "config.h"
+
+#include "client.h"
+#include "hash.h"
+#include "ircd.h"
+#include "ircd_features.h"
+#include "ircd_log.h"
+#include "ircd_reply.h"
+#include "ircd_string.h"
+#include "msg.h"
+#include "numeric.h"
+#include "numnicks.h"
+#include "s_conf.h"
+#include "s_misc.h"
+#include "s_user.h"
+#include "send.h"
+#include "sys.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+/** SVSMODE
+ * SVSMODE is forwarded to the users server, hence, it can be called
+ * from any server.
+ */
+int m_svsmode(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
+{
+    struct Client *acptr;
+    unsigned int i,allow;
+    char buffer[512];
+    char *act, *m;
+    struct Flags setflags;
+
+       if (!IsNetServ(sptr) || !HasFlag(sptr, FLAG_SECURITY_SERV))
+    return send_reply(sptr, ERR_NOPRIVILEGES);
+       
+    if(parc < 3) {
+        return protocol_violation(cptr, "Too few arguments for SVSMODE");
+    }
+
+    if(!(acptr = FindUser(parv[1]))) {
+        return 0; /* Ignore SVSMODE for a user that has quit */
+    }
+
+    /* Forward the message to the server where the user is connected to. */
+    if(!MyConnect(acptr)) {
+        act = buffer;
+        for(i = 2; i < (parc - 1); ++i) {
+            m = parv[i];
+            while((*act++ = *m++)) /* empty loop */ ;
+            *(act - 1) = ' ';
+        }
+        m = parv[i];
+        *act++ = ':';
+        while((*act++ = *m++)) /* empty loop */ ;
+               const struct User* user = cli_user(acptr);
+               struct Client *server = user->server; 
+        sendcmdto_one(sptr, CMD_SVSMODE, acptr, "%s%s %s", cli_yxx(server), cli_yxx(acptr), buffer);
+        return 0;
+    }
+
+    /* Set mode change. */
+    setflags = cli_flags(acptr);
+        /* This is a very important security check! 
+    or shall we allow normal opers to set mode +D?
+    */
+       
+    if(IsSecurityServ(sptr) && IsNetServ(sptr))
+        allow=ALLOWMODES_WITHSECSERV;
+    else
+        allow=ALLOWMODES_ANY;
+    set_user_mode(&me, acptr, parc, parv, allow);
+    send_umode(acptr, acptr, &setflags, ALL_UMODES, 0);
+    return 0;
+}
+
+/* ms_svsmode - server message handler
+ * parv[0] = sender prefix
+ * parv[1] = target numeric
+ * parv[2-X] = mode string
+ */
+signed int ms_svsmode(struct Client* cptr, struct Client* sptr, signed int parc, char* parv[]) {
+    struct Client *acptr;
+    unsigned int i,allow;
+    char buffer[512];
+    char *act, *m;
+    struct Flags setflags;
+
+    if(parc < 3) {
+        return protocol_violation(cptr, "Too few arguments for SVSMODE");
+    }
+
+    if(!(acptr = findNUser(parv[1]))) {
+        return 0; /* Ignore SVSMODE for a user that has quit */
+    }
+
+    /* Forward the message to the server where the user is connected to. */
+    if(!MyConnect(acptr)) {
+        act = buffer;
+        for(i = 2; i < (parc - 1); ++i) {
+            m = parv[i];
+            while((*act++ = *m++)) /* empty loop */ ;
+            *(act - 1) = ' ';
+        }
+        m = parv[i];
+        *act++ = ':';
+        while((*act++ = *m++)) /* empty loop */ ;
+        sendcmdto_one(sptr, CMD_SVSMODE, acptr, "%s %s", parv[1], buffer);
+        return 0;
+    }
+
+    #ifndef UNRESTRICTED_SERV
+    
+    /* Set mode change. */
+    setflags = cli_flags(acptr);
+    /* This is a very important security check! 
+    or shall we allow normal opers to set mode +D?
+    */
+    if(IsSecurityServ(sptr) && IsNetServ(sptr)) {
+        allow=ALLOWMODES_WITHSECSERV;
+       } else {
+        allow=ALLOWMODES_ANY;
+       }
+    set_user_mode(&me, acptr, parc, parv, allow);
+    send_umode(acptr, acptr, &setflags, ALL_UMODES, 0);
+    
+    #endif
+    
+    return 0;
+}
+
diff --git a/ircd/m_svsnick.c b/ircd/m_svsnick.c
new file mode 100644 (file)
index 0000000..f86af44
--- /dev/null
@@ -0,0 +1,269 @@
+/*
+ * IRC - Internet Relay Chat, ircd/m_svsnick.c
+ * Written by David Herrmann.
+ */
+
+/*
+ * m_functions execute protocol messages on this server:
+ *
+ *    cptr    is always NON-NULL, pointing to a *LOCAL* client
+ *            structure (with an open socket connected!). This
+ *            identifies the physical socket where the message
+ *            originated (or which caused the m_function to be
+ *            executed--some m_functions may call others...).
+ *
+ *    sptr    is the source of the message, defined by the
+ *            prefix part of the message if present. If not
+ *            or prefix not found, then sptr==cptr.
+ *
+ *            (!IsServer(cptr)) => (cptr == sptr), because
+ *            prefixes are taken *only* from servers...
+ *
+ *            (IsServer(cptr))
+ *                    (sptr == cptr) => the message didn't
+ *                    have the prefix.
+ *
+ *                    (sptr != cptr && IsServer(sptr) means
+ *                    the prefix specified servername. (?)
+ *
+ *                    (sptr != cptr && !IsServer(sptr) means
+ *                    that message originated from a remote
+ *                    user (not local).
+ *
+ *            combining
+ *
+ *            (!IsServer(sptr)) means that, sptr can safely
+ *            taken as defining the target structure of the
+ *            message in this server.
+ *
+ *    *Always* true (if 'parse' and others are working correct):
+ *
+ *    1)      sptr->from == cptr  (note: cptr->from == cptr)
+ *
+ *    2)      MyConnect(sptr) <=> sptr == cptr (e.g. sptr
+ *            *cannot* be a local connection, unless it's
+ *            actually cptr!). [MyConnect(x) should probably
+ *            be defined as (x == x->from) --msa ]
+ *
+ *    parc    number of variable parameter strings (if zero,
+ *            parv is allowed to be NULL)
+ *
+ *    parv    a NULL terminated list of parameter pointers,
+ *
+ *                    parv[0], sender (prefix string), if not present
+ *                            this points to an empty string.
+ *                    parv[1]...parv[parc-1]
+ *                            pointers to additional parameters
+ *                    parv[parc] == NULL, *always*
+ *
+ *            note:   it is guaranteed that parv[0]..parv[parc-1] are all
+ *                    non-NULL pointers.
+ */
+#include "config.h"
+
+#include "client.h"
+#include "hash.h"
+#include "ircd.h"
+#include "ircd_features.h"
+#include "ircd_log.h"
+#include "ircd_reply.h"
+#include "ircd_string.h"
+#include "msg.h"
+#include "numeric.h"
+#include "numnicks.h"
+#include "s_conf.h"
+#include "s_misc.h"
+#include "s_user.h"
+#include "send.h"
+#include "sys.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+/* Copied from m_nick.c.
+ *
+ * do_nick_name checks the nickname. WARNING: It MAY modify the nickname
+ * RETURNS the length of the final NICKNAME (0, if nickname is invalid)
+ *
+ * Nickname characters are in range 'A'..'}', '_', '-', '0'..'9'
+ *  anything outside the above set will terminate nickname.
+ * In addition, the first character cannot be '-' or a Digit.
+ */
+static int do_nick_name(char* nick) {
+    char *ch  = nick;
+    char *end = ch + NICKLEN;
+    assert(0 != ch);
+
+    /* first character in [0..9-] */
+    if(*ch == '-' || IsDigit(*ch)) return 0;
+    for( ; (ch < end) && *ch; ++ch) {
+        if(!IsNickChar(*ch)) break;
+    }
+    *ch = '\0';
+    return (ch - nick);
+}
+
+/** SVSNICK
+ * SVSNICK is forwarded to the users server, hence, it can be called
+ * from any server.
+ */
+int m_svsnick(struct Client *cptr, struct Client *sptr, int parc, char *parv[]) {
+struct Client *acptr = NULL;
+    char nick[NICKLEN + 2];
+    char *arg;
+    char *s;
+       if (!IsNetServ(sptr) || !HasFlag(sptr, FLAG_SECURITY_SERV))
+    return send_reply(sptr, ERR_NOPRIVILEGES);
+       
+    if(parc < 3) {
+        return protocol_violation(cptr, "Too few arguments for SVSNICK");
+    }
+
+    if(!(acptr = FindUser(parv[1]))) {
+        return 0; /* Ignore SVSNICK for a user that has quit */
+    }
+
+    /* Limit the nicklen to NICKLEN. */
+    arg = parv[2];
+    if(strlen(arg) > IRCD_MIN(NICKLEN, feature_int(FEAT_NICKLEN))) {
+        arg[IRCD_MIN(NICKLEN, feature_int(FEAT_NICKLEN))] = '\0';
+    }
+    strcpy(nick, arg);
+
+    if(!do_nick_name(nick)) {
+        /* Invalid nickname. */
+        return 0;
+    }
+
+    /* Check whether nickname is already set. */
+    if(ircd_strcmp(cli_name(acptr), parv[2]) == 0) {
+        return 0;
+    }
+
+    /* Check whether the nick is already used. */
+    s = nick;
+    if(FindClient(s)) {
+        return 0;
+    }
+
+    /* Forward the message to the server where the user is connected to. */
+    if(!MyConnect(acptr)) {
+           const struct User* user = cli_user(acptr);
+               struct Client *server = user->server; 
+        sendcmdto_one(sptr, CMD_SVSNICK, acptr, "%s%s %s", cli_yxx(server), cli_yxx(acptr), nick);
+        return 0;
+    }
+
+    /* Set nickname. */
+    set_nick_name(acptr, acptr, nick, parc, parv, 1);
+
+    return 1;
+}
+
+/* ms_svsnick - server message handler
+ * parv[0] = sender prefix
+ * parv[1] = target numeric
+ * parv[2] = new nickname
+ */
+signed int ms_svsnick(struct Client* cptr, struct Client* sptr, signed int parc, char* parv[]) {
+    struct Client *acptr = NULL;
+    char nick[NICKLEN + 2];
+    char *arg;
+    char *s;
+
+    if(parc < 3) {
+        return protocol_violation(cptr, "Too few arguments for SVSNICK");
+    }
+
+    if(!(acptr = findNUser(parv[1]))) {
+        return 0; /* Ignore SVSNICK for a user that has quit */
+    }
+
+    /* Limit the nicklen to NICKLEN. */
+    arg = parv[2];
+    if(strlen(arg) > IRCD_MIN(NICKLEN, feature_int(FEAT_NICKLEN))) {
+        arg[IRCD_MIN(NICKLEN, feature_int(FEAT_NICKLEN))] = '\0';
+    }
+    strcpy(nick, arg);
+
+    if(!do_nick_name(nick)) {
+        /* Invalid nickname. */
+        return 0;
+    }
+
+    /* Check whether nickname is already set. */
+    if(ircd_strcmp(cli_name(acptr), parv[2]) == 0) {
+        return 0;
+    }
+
+    /* Check whether the nick is already used. */
+    s = nick;
+    if(FindClient(s)) {
+        return 0;
+    }
+
+    /* Forward the message to the server where the user is connected to. */
+    if(!MyConnect(acptr)) {
+        sendcmdto_one(sptr, CMD_SVSNICK, acptr, "%s %s", parv[1], nick);
+        return 0;
+    }
+
+    #ifndef UNRESTRICTED_SERV
+    /* Set nickname. */
+    set_nick_name(acptr, acptr, nick, parc, parv, 1);
+    #endif
+    return 1;
+}
+
+/*
+ * ms_svsnick_old - server message handler
+ * parv[0] = sender prefix
+ * parv[1] = Target numeric
+ * parv[2] = New nickname
+ */
+int ms_svsnick_old(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) {
+    struct Client* acptr = NULL;
+    char nick[NICKLEN + 2];
+    char* arg;
+    char* s;
+
+    if(parc < 3)
+        return(need_more_params(sptr, "SVSNICK"));
+
+    if(!(acptr = findNUser(parv[1])))
+        return 0; /* Ignore SVSNICK for a user that has quit */
+
+    if(!find_conf_byhost(cli_confs(cptr), cli_name(sptr), CONF_UWORLD)) {
+        return protocol_violation(cptr, "Non-U:lined server %s sets svsnick on user %s", cli_name(sptr), cli_name(acptr));
+    }
+
+    /*
+     * Don't let them send make us send back a really long string of
+     * garbage
+     */
+    arg = parv[2];
+    if(strlen(arg) > IRCD_MIN(NICKLEN, feature_int(FEAT_NICKLEN)))
+        arg[IRCD_MIN(NICKLEN, feature_int(FEAT_NICKLEN))] = '\0';
+
+    if((s = strchr(arg, '~')))
+        *s = '\0';
+
+    strcpy(nick, arg);
+
+    /*
+     * If do_nick_name() returns a null name then reject it.
+     */
+    if(0 == do_nick_name(nick))
+        return 0;
+
+    if(ircd_strcmp(cli_name(acptr), nick) == 0)
+        return 0; /* Nick already set to what SVSNICK wants, ignoring... */
+
+    if(FindClient(nick))
+        return 0; /* Target nick is in use */
+    
+    set_nick_name(acptr, acptr, nick, parc, parv, 1);
+    sendcmdto_serv_butone(sptr, CMD_SVSNICK_OLD, cptr, "%s %s", parv[1], nick);
+    return 0;
+}
+
diff --git a/ircd/m_time.c b/ircd/m_time.c
new file mode 100644 (file)
index 0000000..dfd46a8
--- /dev/null
@@ -0,0 +1,114 @@
+/*
+ * IRC - Internet Relay Chat, ircd/m_time.c
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ *                    University of Oulu, Computing Center
+ *
+ * See file AUTHORS in IRC package for additional names of
+ * the programmers.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id: m_time.c 1271 2004-12-11 05:14:07Z klmitch $
+ */
+
+/*
+ * m_functions execute protocol messages on this server:
+ *
+ *    cptr    is always NON-NULL, pointing to a *LOCAL* client
+ *            structure (with an open socket connected!). This
+ *            identifies the physical socket where the message
+ *            originated (or which caused the m_function to be
+ *            executed--some m_functions may call others...).
+ *
+ *    sptr    is the source of the message, defined by the
+ *            prefix part of the message if present. If not
+ *            or prefix not found, then sptr==cptr.
+ *
+ *            (!IsServer(cptr)) => (cptr == sptr), because
+ *            prefixes are taken *only* from servers...
+ *
+ *            (IsServer(cptr))
+ *                    (sptr == cptr) => the message didn't
+ *                    have the prefix.
+ *
+ *                    (sptr != cptr && IsServer(sptr) means
+ *                    the prefix specified servername. (?)
+ *
+ *                    (sptr != cptr && !IsServer(sptr) means
+ *                    that message originated from a remote
+ *                    user (not local).
+ *
+ *            combining
+ *
+ *            (!IsServer(sptr)) means that, sptr can safely
+ *            taken as defining the target structure of the
+ *            message in this server.
+ *
+ *    *Always* true (if 'parse' and others are working correct):
+ *
+ *    1)      sptr->from == cptr  (note: cptr->from == cptr)
+ *
+ *    2)      MyConnect(sptr) <=> sptr == cptr (e.g. sptr
+ *            *cannot* be a local connection, unless it's
+ *            actually cptr!). [MyConnect(x) should probably
+ *            be defined as (x == x->from) --msa ]
+ *
+ *    parc    number of variable parameter strings (if zero,
+ *            parv is allowed to be NULL)
+ *
+ *    parv    a NULL terminated list of parameter pointers,
+ *
+ *                    parv[0], sender (prefix string), if not present
+ *                            this points to an empty string.
+ *                    parv[1]...parv[parc-1]
+ *                            pointers to additional parameters
+ *                    parv[parc] == NULL, *always*
+ *
+ *            note:   it is guaranteed that parv[0]..parv[parc-1] are all
+ *                    non-NULL pointers.
+ */
+#include "config.h"
+
+#include "client.h"
+#include "ircd.h"
+#include "ircd_features.h"
+#include "ircd_log.h"
+#include "ircd_reply.h"
+#include "ircd_string.h"
+#include "msg.h"
+#include "numeric.h"
+#include "numnicks.h"
+#include "s_misc.h"
+#include "s_user.h"
+#include "send.h"
+
+/* #include <assert.h> -- Now using assert in ircd_log.h */
+
+/*
+ * m_time - generic message handler
+ *
+ * parv[0] = sender prefix
+ * parv[1] = servername
+ */
+int m_time(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  if (hunt_server_cmd(sptr, CMD_TIME, cptr, feature_int(FEAT_HIS_REMOTE), ":%C",
+                      1, parc, parv)
+      != HUNTED_ISME)
+    return 0;
+
+  send_reply(sptr, RPL_TIME, cli_name(&me), TStime(), TSoffset, date((long)0));
+  return 0;
+}
diff --git a/ircd/m_tmpl.c b/ircd/m_tmpl.c
new file mode 100644 (file)
index 0000000..5f54fe3
--- /dev/null
@@ -0,0 +1,128 @@
+/*
+ * IRC - Internet Relay Chat, ircd/m_tmpl.c
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ *                    University of Oulu, Computing Center
+ *
+ * See file AUTHORS in IRC package for additional names of
+ * the programmers.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id: m_tmpl.c 1271 2004-12-11 05:14:07Z klmitch $
+ */
+
+/*
+ * m_functions execute protocol messages on this server:
+ *
+ *    cptr    is always NON-NULL, pointing to a *LOCAL* client
+ *            structure (with an open socket connected!). This
+ *            identifies the physical socket where the message
+ *            originated (or which caused the m_function to be
+ *            executed--some m_functions may call others...).
+ *
+ *    sptr    is the source of the message, defined by the
+ *            prefix part of the message if present. If not
+ *            or prefix not found, then sptr==cptr.
+ *
+ *            (!IsServer(cptr)) => (cptr == sptr), because
+ *            prefixes are taken *only* from servers...
+ *
+ *            (IsServer(cptr))
+ *                    (sptr == cptr) => the message didn't
+ *                    have the prefix.
+ *
+ *                    (sptr != cptr && IsServer(sptr) means
+ *                    the prefix specified servername. (?)
+ *
+ *                    (sptr != cptr && !IsServer(sptr) means
+ *                    that message originated from a remote
+ *                    user (not local).
+ *
+ *            combining
+ *
+ *            (!IsServer(sptr)) means that, sptr can safely
+ *            taken as defining the target structure of the
+ *            message in this server.
+ *
+ *    *Always* true (if 'parse' and others are working correct):
+ *
+ *    1)      sptr->from == cptr  (note: cptr->from == cptr)
+ *
+ *    2)      MyConnect(sptr) <=> sptr == cptr (e.g. sptr
+ *            *cannot* be a local connection, unless it's
+ *            actually cptr!). [MyConnect(x) should probably
+ *            be defined as (x == x->from) --msa ]
+ *
+ *    parc    number of variable parameter strings (if zero,
+ *            parv is allowed to be NULL)
+ *
+ *    parv    a NULL terminated list of parameter pointers,
+ *
+ *                    parv[0], sender (prefix string), if not present
+ *                            this points to an empty string.
+ *                    parv[1]...parv[parc-1]
+ *                            pointers to additional parameters
+ *                    parv[parc] == NULL, *always*
+ *
+ *            note:   it is guaranteed that parv[0]..parv[parc-1] are all
+ *                    non-NULL pointers.
+ */
+#include "config.h"
+
+#include "client.h"
+#include "hash.h"
+#include "ircd.h"
+#include "ircd_log.h"
+#include "ircd_reply.h"
+#include "ircd_string.h"
+#include "numeric.h"
+#include "numnicks.h"
+#include "send.h"
+
+/* #include <assert.h> -- Now using assert in ircd_log.h */
+
+/*
+ * m_tmpl - generic message handler
+ */
+int m_tmpl(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  return 0;
+}
+
+/*
+ * ms_tmpl - server message handler
+ */
+int ms_tmpl(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  return 0;
+}
+
+/*
+ * mo_tmpl - oper message handler
+ */
+int mo_tmpl(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  return 0;
+}
+
+  
+/*
+ * mv_tmpl - service message handler
+ */
+int mv_tmpl(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  return 0;
+}
+
diff --git a/ircd/m_topic.c b/ircd/m_topic.c
new file mode 100644 (file)
index 0000000..37ae26f
--- /dev/null
@@ -0,0 +1,206 @@
+/*
+ * IRC - Internet Relay Chat, ircd/m_topic.c
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ *                    University of Oulu, Computing Center
+ *
+ * See file AUTHORS in IRC package for additional names of
+ * the programmers.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id: m_topic.c 1903 2009-01-13 03:54:45Z entrope $
+ */
+
+#include "config.h"
+
+#include "channel.h"
+#include "client.h"
+#include "hash.h"
+#include "ircd.h"
+#include "ircd_features.h"
+#include "ircd_log.h"
+#include "ircd_reply.h"
+#include "ircd_string.h"
+#include "msg.h"
+#include "numeric.h"
+#include "numnicks.h"
+#include "send.h"
+
+/* #include <assert.h> -- Now using assert in ircd_log.h */
+#include <stdlib.h> /* for atoi() */
+
+/** Set a channel topic or report an error.
+ * @param[in] sptr Original topic setter.
+ * @param[in] cptr Neighbor that sent the topic message.
+ * @param[in] chptr Channel to set topic on.
+ * @param[in] topic New topic.
+ * @param[in] ts Timestamp that topic was set (0 for current time).
+ */
+static void do_settopic(struct Client *sptr, struct Client *cptr,
+                       struct Channel *chptr, char *topic, time_t ts)
+{
+   struct Client *from;
+   int newtopic;
+
+   if (feature_bool(FEAT_HIS_BANWHO) && IsServer(sptr))
+       from = &his;
+   else
+       from = sptr;
+   /* Note if this is just a refresh of an old topic, and don't
+    * send it to all the clients to save bandwidth.  We still send
+    * it to other servers as they may have split and lost the topic.
+    */
+   newtopic=ircd_strncmp(chptr->topic,topic,TOPICLEN)!=0;
+   /* setting a topic */
+   ircd_strncpy(chptr->topic, topic, TOPICLEN);
+   ircd_strncpy(chptr->topic_nick, cli_name(from), NICKLEN);
+   chptr->topic_time = ts ? ts : TStime();
+   /* Fixed in 2.10.11: Don't propagate local topics */
+   if (!IsLocalChannel(chptr->chname))
+     sendcmdto_serv_butone(sptr, CMD_TOPIC, cptr, "%H %Tu %Tu :%s", chptr,
+                          chptr->creationtime, chptr->topic_time, chptr->topic);
+   if (newtopic)
+   {
+     struct Membership *member;
+
+     /* If the member is delayed-join, show them. */
+     member = find_channel_member(sptr, chptr);
+     if (member && IsDelayedJoin(member))
+       RevealDelayedJoin(member);
+
+     sendcmdto_channel_butserv_butone(from, CMD_TOPIC, chptr, NULL, 0,
+                                      "%H :%s", chptr, chptr->topic);
+   }
+      /* if this is the same topic as before we send it to the person that
+       * set it (so they knew it went through ok), but don't bother sending
+       * it to everyone else on the channel to save bandwidth
+       */
+    else if (MyUser(sptr))
+      sendcmdto_one(sptr, CMD_TOPIC, sptr, "%H :%s", chptr, chptr->topic);
+}
+
+/** Handle a local user's attempt to get or set a channel topic.
+ *
+ * \a parv has the following elements:
+ * \li \a parv[1] is the channel name
+ * \li \a parv[\a parc - 1] is the topic (if \a parc > 2)
+ *
+ * See @ref m_functions for discussion of the arguments.
+ * @param[in] cptr Client that sent us the message.
+ * @param[in] sptr Original source of message.
+ * @param[in] parc Number of arguments.
+ * @param[in] parv Argument vector.
+ */
+int m_topic(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  struct Channel *chptr;
+  char *topic = 0, *name, *p = 0;
+
+  if (parc < 2)
+    return need_more_params(sptr, "TOPIC");
+
+  if (parc > 2)
+    topic = parv[parc - 1];
+
+  for (; (name = ircd_strtok(&p, parv[1], ",")); parv[1] = 0)
+  {
+    chptr = 0;
+    /* Does the channel exist */
+    if (!IsChannelName(name) || !(chptr = FindChannel(name)))
+    {
+       send_reply(sptr,ERR_NOSUCHCHANNEL,name);
+       continue;
+    }
+    /* Trying to check a topic outside a secret channel */
+    if ((topic || SecretChannel(chptr)) && !find_channel_member(sptr, chptr))
+    {
+      send_reply(sptr, ERR_NOTONCHANNEL, chptr->chname);
+      continue;
+    }
+
+    /* only asking for topic */
+    if (!topic)
+    {
+      if (chptr->topic[0] == '\0')
+       send_reply(sptr, RPL_NOTOPIC, chptr->chname);
+      else
+      {
+       send_reply(sptr, RPL_TOPIC, chptr->chname, chptr->topic);
+       send_reply(sptr, RPL_TOPICWHOTIME, chptr->chname, chptr->topic_nick,
+                  chptr->topic_time);
+      }
+    }
+    else if ((chptr->mode.mode & MODE_TOPICLIMIT) && (!is_chan_op(sptr, chptr) && !(IsNetServ(sptr) && IsSecurityServ(sptr) && IsChannelService(sptr))))
+      send_reply(sptr, ERR_CHANOPRIVSNEEDED, chptr->chname);
+    else if (!client_can_send_to_channel(sptr, chptr, 1))
+      send_reply(sptr, ERR_CANNOTSENDTOCHAN, chptr->chname);
+    else
+      do_settopic(sptr,cptr,chptr,topic,0);
+  }
+  return 0;
+}
+
+/** Handle a remote user's attempt to set a channel topic.
+ * \a parv has the following elements:
+ * \li \a parv[1] is the channel name
+ * \li \a parv[2] is the channel creation timestamp (optional)
+ * \li \a parv[2] is the topic's timestamp (optional)
+ * \li \a parv[\a parc - 1] is the topic
+ *
+ * See @ref m_functions for discussion of the arguments.
+ * @param[in] cptr Client that sent us the message.
+ * @param[in] sptr Original source of message.
+ * @param[in] parc Number of arguments.
+ * @param[in] parv Argument vector.
+ */
+int ms_topic(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  struct Channel *chptr;
+  char *topic = 0, *name, *p = 0;
+  time_t ts = 0;
+
+  if (parc < 3)
+    return need_more_params(sptr, "TOPIC");
+
+  topic = parv[parc - 1];
+
+  for (; (name = ircd_strtok(&p, parv[1], ",")); parv[1] = 0)
+  {
+    chptr = 0;
+    /* Does the channel exist */
+    if (!IsChannelName(name) || !(chptr = FindChannel(name)))
+    {
+       send_reply(sptr,ERR_NOSUCHCHANNEL,name);
+       continue;
+    }
+
+    /* Ignore requests for topics from remote servers */
+    if (IsLocalChannel(name) && !MyUser(sptr))
+    {
+      protocol_violation(sptr,"Topic request");
+      continue;
+    }
+
+    /* If existing channel is older or has newer topic, ignore */
+    if (parc > 3 && (ts = atoi(parv[2])) && chptr->creationtime < ts)
+      continue;
+
+    if (parc > 4 && (ts = atoi(parv[3])) && chptr->topic_time > ts)
+      continue;
+
+    do_settopic(sptr,cptr,chptr,topic, ts);
+  }
+  return 0;
+}
diff --git a/ircd/m_trace.c b/ircd/m_trace.c
new file mode 100644 (file)
index 0000000..a22cf4b
--- /dev/null
@@ -0,0 +1,344 @@
+/*
+ * IRC - Internet Relay Chat, ircd/m_trace.c
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ *                    University of Oulu, Computing Center
+ *
+ * See file AUTHORS in IRC package for additional names of
+ * the programmers.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id: m_trace.c 1468 2005-08-26 03:23:23Z entrope $
+ */
+
+/*
+ * m_functions execute protocol messages on this server:
+ *
+ *    cptr    is always NON-NULL, pointing to a *LOCAL* client
+ *            structure (with an open socket connected!). This
+ *            identifies the physical socket where the message
+ *            originated (or which caused the m_function to be
+ *            executed--some m_functions may call others...).
+ *
+ *    sptr    is the source of the message, defined by the
+ *            prefix part of the message if present. If not
+ *            or prefix not found, then sptr==cptr.
+ *
+ *            (!IsServer(cptr)) => (cptr == sptr), because
+ *            prefixes are taken *only* from servers...
+ *
+ *            (IsServer(cptr))
+ *                    (sptr == cptr) => the message didn't
+ *                    have the prefix.
+ *
+ *                    (sptr != cptr && IsServer(sptr) means
+ *                    the prefix specified servername. (?)
+ *
+ *                    (sptr != cptr && !IsServer(sptr) means
+ *                    that message originated from a remote
+ *                    user (not local).
+ *
+ *            combining
+ *
+ *            (!IsServer(sptr)) means that, sptr can safely
+ *            taken as defining the target structure of the
+ *            message in this server.
+ *
+ *    *Always* true (if 'parse' and others are working correct):
+ *
+ *    1)      sptr->from == cptr  (note: cptr->from == cptr)
+ *
+ *    2)      MyConnect(sptr) <=> sptr == cptr (e.g. sptr
+ *            *cannot* be a local connection, unless it's
+ *            actually cptr!). [MyConnect(x) should probably
+ *            be defined as (x == x->from) --msa ]
+ *
+ *    parc    number of variable parameter strings (if zero,
+ *            parv is allowed to be NULL)
+ *
+ *    parv    a NULL terminated list of parameter pointers,
+ *
+ *                    parv[0], sender (prefix string), if not present
+ *                            this points to an empty string.
+ *                    parv[1]...parv[parc-1]
+ *                            pointers to additional parameters
+ *                    parv[parc] == NULL, *always*
+ *
+ *            note:   it is guaranteed that parv[0]..parv[parc-1] are all
+ *                    non-NULL pointers.
+ */
+#include "config.h"
+
+#include "class.h"
+#include "client.h"
+#include "hash.h"
+#include "ircd.h"
+#include "ircd_features.h"
+#include "ircd_log.h"
+#include "ircd_reply.h"
+#include "ircd_string.h"
+#include "match.h"
+#include "msg.h"
+#include "numeric.h"
+#include "numnicks.h"
+#include "s_bsd.h"
+#include "s_conf.h"
+#include "s_user.h"
+#include "send.h"
+#include "version.h"
+
+/* #include <assert.h> -- Now using assert in ircd_log.h */
+#include <string.h>
+
+void do_trace(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
+{
+  int i;
+  struct Client *acptr;
+  struct Client *acptr2;
+  const struct ConnectionClass* cl;
+  char* tname;
+  int doall;
+  int link_s[MAXCONNECTIONS];
+  int link_u[MAXCONNECTIONS];
+  int cnt = 0;
+  int wilds;
+  int dow;
+
+  if (parc < 2 || BadPtr(parv[1]))
+  {
+    /* just "TRACE" without parameters. Must be from local client */
+    parc = 1;
+    acptr = &me;
+    tname = cli_name(&me);
+    i = HUNTED_ISME;
+  }
+  else if (parc < 3 || BadPtr(parv[2]))
+  {
+    /* No target specified. Make one before propagating. */
+    parc = 2;
+    tname = parv[1];
+    if ((acptr = find_match_server(parv[1])) ||
+        ((acptr = FindClient(parv[1])) && !MyUser(acptr)))
+    {
+      if (IsUser(acptr))
+        parv[2] = cli_name(cli_user(acptr)->server);
+      else
+        parv[2] = cli_name(acptr);
+      parc = 3;
+      parv[3] = 0;
+      if ((i = hunt_server_cmd(sptr, CMD_TRACE, cptr, IsServer(acptr),
+                              "%s :%C", 2, parc, parv)) == HUNTED_NOSUCH)
+        return;
+    }
+    else
+      i = HUNTED_ISME;
+  } else {
+    /* Got "TRACE <tname> :<target>" */
+    parc = 3;
+    if (MyUser(sptr) || Protocol(cptr) < 10)
+      acptr = find_match_server(parv[2]);
+    else
+      acptr = FindNServer(parv[2]);
+    if ((i = hunt_server_cmd(sptr, CMD_TRACE, cptr, 0, "%s :%C", 2, parc,
+                            parv)) == HUNTED_NOSUCH)
+      return;
+    tname = parv[1];
+  }
+
+  if (i == HUNTED_PASS) {
+    if (!acptr)
+      acptr = next_client(GlobalClientList, tname);
+    else
+      acptr = cli_from(acptr);
+    send_reply(sptr, RPL_TRACELINK,
+              version, debugmode, tname,
+              acptr ? cli_name(cli_from(acptr)) : "<No_match>");
+    return;
+  }
+
+  doall = (parv[1] && (parc > 1)) ? !match(tname, cli_name(&me)) : 1;
+  wilds = !parv[1] || strchr(tname, '*') || strchr(tname, '?');
+  dow = wilds || doall;
+
+  /* Don't give (long) remote listings to lusers */
+  if (dow && !MyConnect(sptr) && !IsAnOper(sptr)) {
+    send_reply(sptr, RPL_TRACEEND);
+    return;
+  }
+
+  for (i = 0; i < MAXCONNECTIONS; i++)
+    link_s[i] = 0, link_u[i] = 0;
+
+  if (doall) {
+    for (acptr = GlobalClientList; acptr; acptr = cli_next(acptr)) {
+      if (IsUser(acptr))
+        link_u[cli_fd(cli_from(acptr))]++;
+      else if (IsServer(acptr))
+        link_s[cli_fd(cli_from(acptr))]++;
+    }
+  }
+
+  /* report all direct connections */
+
+  for (i = 0; i <= HighestFd; i++) {
+    const char *conClass;
+
+    if (!(acptr = LocalClientArray[i])) /* Local Connection? */
+      continue;
+    if (IsInvisible(acptr) && dow && !(MyConnect(sptr) && IsOper(sptr)) &&
+        !IsAnOper(acptr) && (acptr != sptr))
+      continue;
+    if (!doall && wilds && match(tname, cli_name(acptr)))
+      continue;
+    if (!dow && 0 != ircd_strcmp(tname, cli_name(acptr)))
+      continue;
+
+    conClass = get_client_class(acptr);
+
+    switch (cli_status(acptr)) {
+      case STAT_CONNECTING:
+       send_reply(sptr, RPL_TRACECONNECTING, conClass, cli_name(acptr));
+        cnt++;
+        break;
+      case STAT_HANDSHAKE:
+       send_reply(sptr, RPL_TRACEHANDSHAKE, conClass, cli_name(acptr));
+        cnt++;
+        break;
+      case STAT_ME:
+        break;
+      case STAT_UNKNOWN:
+      case STAT_UNKNOWN_USER:
+       send_reply(sptr, RPL_TRACEUNKNOWN, conClass,
+                  get_client_name(acptr, HIDE_IP));
+        cnt++;
+        break;
+      case STAT_UNKNOWN_SERVER:
+       send_reply(sptr, RPL_TRACEUNKNOWN, conClass, "Unknown Server");
+        cnt++;
+        break;
+      case STAT_USER:
+        /* Only opers see users if there is a wildcard
+           but anyone can see all the opers. */
+        if ((IsAnOper(sptr) && (MyUser(sptr) ||
+            !(dow && IsInvisible(acptr)))) || !dow || IsAnOper(acptr)) {
+          if (IsAnOper(acptr))
+           send_reply(sptr, RPL_TRACEOPERATOR, conClass,
+                      get_client_name(acptr, SHOW_IP),
+                      CurrentTime - cli_lasttime(acptr));
+          else
+           send_reply(sptr, RPL_TRACEUSER, conClass,
+                      get_client_name(acptr, SHOW_IP),
+                      CurrentTime - cli_lasttime(acptr));
+          cnt++;
+        }
+        break;
+        /*
+         * Connection is a server
+         *
+         * Serv <class> <nS> <nC> <name> <ConnBy> <last> <age>
+         *
+         * class        Class the server is in
+         * nS           Number of servers reached via this link
+         * nC           Number of clients reached via this link
+         * name         Name of the server linked
+         * ConnBy       Who established this link
+         * last         Seconds since we got something from this link
+         * age          Seconds this link has been alive
+         *
+         * Additional comments etc......        -Cym-<cym@acrux.net>
+         */
+
+      case STAT_SERVER:
+        if (cli_serv(acptr)->user) {
+          if (!cli_serv(acptr)->by[0]
+              || !(acptr2 = findNUser(cli_serv(acptr)->by))
+              || (cli_user(acptr2) != cli_serv(acptr)->user))
+            acptr2 = NULL;
+         send_reply(sptr, RPL_TRACESERVER, conClass, link_s[i],
+                     link_u[i], cli_name(acptr),
+                     acptr2 ? cli_name(acptr2) : "*",
+                     cli_serv(acptr)->user->username,
+                     cli_serv(acptr)->user->host,
+                     CurrentTime - cli_lasttime(acptr),
+                     CurrentTime - cli_serv(acptr)->timestamp);
+        } else
+         send_reply(sptr, RPL_TRACESERVER, conClass, link_s[i],
+                     link_u[i], cli_name(acptr),
+                     (*(cli_serv(acptr))->by) ?  cli_serv(acptr)->by : "*", "*",
+                     cli_name(&me), CurrentTime - cli_lasttime(acptr),
+                    CurrentTime - cli_serv(acptr)->timestamp);
+        cnt++;
+        break;
+      default:                  /* We actually shouldn't come here, -msa */
+       send_reply(sptr, RPL_TRACENEWTYPE, get_client_name(acptr, HIDE_IP));
+        cnt++;
+        break;
+    }
+  }
+  /*
+   * Add these lines to summarize the above which can get rather long
+   * and messy when done remotely - Avalon
+   */
+  if (IsAnOper(sptr) && doall) {
+    for (cl = get_class_list(); cl; cl = cl->next) {
+      if (Links(cl) > 1)
+       send_reply(sptr, RPL_TRACECLASS, ConClass(cl), Links(cl) - 1);
+    }
+  }
+  send_reply(sptr, RPL_TRACEEND);
+}
+
+/*
+ * m_trace - generic message handler
+ *
+ * parv[0] = sender prefix
+ * parv[1] = nick or servername
+ * parv[2] = 'target' servername
+ */
+int m_trace(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  if (feature_bool(FEAT_HIS_TRACE))
+    return send_reply(cptr, ERR_NOPRIVILEGES);
+  do_trace(cptr, sptr, parc, parv);
+  return 0;
+}
+
+/*
+ * ms_trace - server message handler
+ *
+ * parv[0] = sender prefix
+ * parv[1] = nick or servername
+ * parv[2] = 'target' servername
+ */
+int ms_trace(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  do_trace(cptr, sptr, parc, parv);
+  return 0;
+}
+
+/*
+ * mo_trace - oper message handler
+ *
+ * parv[0] = sender prefix
+ * parv[1] = nick or servername
+ * parv[2] = 'target' servername
+ */
+int mo_trace(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  if (feature_bool(FEAT_HIS_TRACE) && !IsAnOper(sptr))
+    return send_reply(cptr, ERR_NOPRIVILEGES);
+  do_trace(cptr, sptr, parc, parv);
+  return 0;
+}
diff --git a/ircd/m_uping.c b/ircd/m_uping.c
new file mode 100644 (file)
index 0000000..da3be05
--- /dev/null
@@ -0,0 +1,243 @@
+/*
+ * IRC - Internet Relay Chat, ircd/m_uping.c
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ *                    University of Oulu, Computing Center
+ *
+ * See file AUTHORS in IRC package for additional names of
+ * the programmers.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id: m_uping.c 1271 2004-12-11 05:14:07Z klmitch $
+ */
+
+/*
+ * m_functions execute protocol messages on this server:
+ *
+ *    cptr    is always NON-NULL, pointing to a *LOCAL* client
+ *            structure (with an open socket connected!). This
+ *            identifies the physical socket where the message
+ *            originated (or which caused the m_function to be
+ *            executed--some m_functions may call others...).
+ *
+ *    sptr    is the source of the message, defined by the
+ *            prefix part of the message if present. If not
+ *            or prefix not found, then sptr==cptr.
+ *
+ *            (!IsServer(cptr)) => (cptr == sptr), because
+ *            prefixes are taken *only* from servers...
+ *
+ *            (IsServer(cptr))
+ *                    (sptr == cptr) => the message didn't
+ *                    have the prefix.
+ *
+ *                    (sptr != cptr && IsServer(sptr) means
+ *                    the prefix specified servername. (?)
+ *
+ *                    (sptr != cptr && !IsServer(sptr) means
+ *                    that message originated from a remote
+ *                    user (not local).
+ *
+ *            combining
+ *
+ *            (!IsServer(sptr)) means that, sptr can safely
+ *            taken as defining the target structure of the
+ *            message in this server.
+ *
+ *    *Always* true (if 'parse' and others are working correct):
+ *
+ *    1)      sptr->from == cptr  (note: cptr->from == cptr)
+ *
+ *    2)      MyConnect(sptr) <=> sptr == cptr (e.g. sptr
+ *            *cannot* be a local connection, unless it's
+ *            actually cptr!). [MyConnect(x) should probably
+ *            be defined as (x == x->from) --msa ]
+ *
+ *    parc    number of variable parameter strings (if zero,
+ *            parv is allowed to be NULL)
+ *
+ *    parv    a NULL terminated list of parameter pointers,
+ *
+ *                    parv[0], sender (prefix string), if not present
+ *                            this points to an empty string.
+ *                    parv[1]...parv[parc-1]
+ *                            pointers to additional parameters
+ *                    parv[parc] == NULL, *always*
+ *
+ *            note:   it is guaranteed that parv[0]..parv[parc-1] are all
+ *                    non-NULL pointers.
+ */
+#include "config.h"
+
+#include "client.h"
+#include "hash.h"
+#include "ircd.h"
+#include "ircd_log.h"
+#include "ircd_reply.h"
+#include "ircd_string.h"
+#include "match.h"
+#include "msg.h"
+#include "numeric.h"
+#include "numnicks.h"
+#include "s_conf.h"
+#include "s_user.h"
+#include "send.h"
+#include "uping.h"
+
+
+/* #include <assert.h> -- Now using assert in ircd_log.h */
+#include <stdlib.h>
+#include <string.h>
+
+/*
+ * ms_uping - server message handler
+ *
+ * m_uping  -- by Run
+ *
+ * parv[0] = sender prefix
+ * parv[1] = pinged server
+ * parv[2] = port
+ * parv[3] = hunted server
+ * parv[4] = number of requested pings
+ */
+int ms_uping(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  struct ConfItem *aconf;
+  int port;
+  int count;
+
+  assert(0 != cptr);
+  assert(0 != sptr);
+
+  if (!IsAnOper(sptr)) {
+    send_reply(sptr, ERR_NOPRIVILEGES);
+    return 0;
+  }
+
+  if (parc < 5) {
+    send_reply(sptr, ERR_NEEDMOREPARAMS, "UPING");
+    return 0;
+  }
+
+  if (hunt_server_cmd(sptr, CMD_UPING, cptr, 1, "%s %s %C %s", 3, parc, parv)
+      != HUNTED_ISME)
+    return 0;
+  /*
+   * Determine port: First user supplied, then default : 7007
+   */
+  if (EmptyString(parv[2]) || (port = atoi(parv[2])) <= 0)
+    port = atoi(UDP_PORT);
+
+  if (EmptyString(parv[4]) || (count = atoi(parv[4])) <= 0)
+  {
+    sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :UPING : Illegal number of "
+                 "packets: %s", sptr, parv[4]);
+    return 0;
+  }
+  /* 
+   * Check if a CONNECT would be possible at all (adapted from m_connect)
+   */
+  if ((aconf = conf_find_server(parv[1])))
+    uping_server(sptr, aconf, port, count);
+  else
+    sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :UPING: Host %s not listed in "
+                 "ircd.conf", sptr, parv[1]);
+
+  return 0;
+}
+
+/*
+ * mo_uping - oper message handler
+ *
+ * m_uping  -- by Run
+ *
+ * parv[0] = sender prefix
+ * parv[1] = pinged server
+ * parv[2] = port
+ * parv[3] = hunted server
+ * parv[4] = number of requested pings
+ */
+int mo_uping(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  struct ConfItem *aconf;
+  int port;
+  int count;
+
+  assert(0 != cptr);
+  assert(0 != sptr);
+  assert(cptr == sptr);
+
+  assert(IsAnOper(sptr));
+
+  if (parc < 2) {
+    send_reply(sptr, ERR_NEEDMOREPARAMS, "UPING");
+    return 0;
+  }
+
+  if (parc == 2) {
+    parv[parc++] = UDP_PORT;
+    parv[parc++] = cli_name(&me);
+    parv[parc++] = "5";
+  }
+  else if (parc == 3) {
+    if (IsDigit(*parv[2]))
+      parv[parc++] = cli_name(&me);
+    else {
+      parv[parc++] = parv[2];
+      parv[2] = UDP_PORT;
+    }
+    parv[parc++] = "5";
+  }
+  else if (parc == 4) {
+    if (IsDigit(*parv[2])) {
+      if (IsDigit(*parv[3])) {
+        parv[parc++] = parv[3];
+        parv[3] = cli_name(&me);
+      }
+      else
+        parv[parc++] = "5";
+    }
+    else {
+      parv[parc++] = parv[3];
+      parv[3] = parv[2];
+      parv[2] = UDP_PORT;
+    }
+  }
+  if (hunt_server_cmd(sptr, CMD_UPING, sptr, 1, "%s %s %C %s", 3, parc, parv)
+      != HUNTED_ISME)
+    return 0;
+  /*
+   * Determine port: First user supplied, then default : 7007
+   */
+  if (EmptyString(parv[2]) || (port = atoi(parv[2])) <= 0)
+    port = atoi(UDP_PORT);
+
+  if (EmptyString(parv[4]) || (count = atoi(parv[4])) <= 0)
+  {
+    sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :UPING: Illegal number of "
+                 "packets: %s", sptr, parv[4]);
+    return 0;
+  }
+  /* 
+   * Check if a CONNECT would be possible at all (adapted from m_connect)
+   */
+  if ((aconf = conf_find_server(parv[1])))
+    uping_server(sptr, aconf, port, count);
+  else {
+    sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :UPING: Host %s not listed in "
+                 "ircd.conf", sptr, parv[1]);
+  }
+  return 0;
+}
diff --git a/ircd/m_user.c b/ircd/m_user.c
new file mode 100644 (file)
index 0000000..9731ad3
--- /dev/null
@@ -0,0 +1,169 @@
+/*
+ * IRC - Internet Relay Chat, ircd/m_user.c
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ *                    University of Oulu, Computing Center
+ *
+ * See file AUTHORS in IRC package for additional names of
+ * the programmers.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id: m_user.c 1818 2007-07-14 02:40:01Z isomer $
+ */
+
+/*
+ * m_functions execute protocol messages on this server:
+ *
+ *    cptr    is always NON-NULL, pointing to a *LOCAL* client
+ *            structure (with an open socket connected!). This
+ *            identifies the physical socket where the message
+ *            originated (or which caused the m_function to be
+ *            executed--some m_functions may call others...).
+ *
+ *    sptr    is the source of the message, defined by the
+ *            prefix part of the message if present. If not
+ *            or prefix not found, then sptr==cptr.
+ *
+ *            (!IsServer(cptr)) => (cptr == sptr), because
+ *            prefixes are taken *only* from servers...
+ *
+ *            (IsServer(cptr))
+ *                    (sptr == cptr) => the message didn't
+ *                    have the prefix.
+ *
+ *                    (sptr != cptr && IsServer(sptr) means
+ *                    the prefix specified servername. (?)
+ *
+ *                    (sptr != cptr && !IsServer(sptr) means
+ *                    that message originated from a remote
+ *                    user (not local).
+ *
+ *            combining
+ *
+ *            (!IsServer(sptr)) means that, sptr can safely
+ *            taken as defining the target structure of the
+ *            message in this server.
+ *
+ *    *Always* true (if 'parse' and others are working correct):
+ *
+ *    1)      sptr->from == cptr  (note: cptr->from == cptr)
+ *
+ *    2)      MyConnect(sptr) <=> sptr == cptr (e.g. sptr
+ *            *cannot* be a local connection, unless it's
+ *            actually cptr!). [MyConnect(x) should probably
+ *            be defined as (x == x->from) --msa ]
+ *
+ *    parc    number of variable parameter strings (if zero,
+ *            parv is allowed to be NULL)
+ *
+ *    parv    a NULL terminated list of parameter pointers,
+ *
+ *                    parv[0], sender (prefix string), if not present
+ *                            this points to an empty string.
+ *                    parv[1]...parv[parc-1]
+ *                            pointers to additional parameters
+ *                    parv[parc] == NULL, *always*
+ *
+ *            note:   it is guaranteed that parv[0]..parv[parc-1] are all
+ *                    non-NULL pointers.
+ */
+#include "config.h"
+
+#include "handlers.h"
+#include "client.h"
+#include "ircd.h"
+#include "ircd_chattr.h"
+#include "ircd_log.h"
+#include "ircd_reply.h"
+#include "ircd_string.h"
+#include "numeric.h"
+#include "numnicks.h"
+#include "s_auth.h"
+#include "s_debug.h"
+#include "s_misc.h"
+#include "s_user.h"
+#include "send.h"
+
+/* #include <assert.h> -- Now using assert in ircd_log.h */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+/*
+ * m_user
+ *
+ * parv[0] = sender prefix
+ * parv[1] = username           (login name, account)
+ * parv[2] = host name          (ignored)
+ * parv[3] = server name        (ignored)
+ * parv[4] = users real name info
+ */
+int m_user(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
+{
+  char*        username;
+  char*        term;
+  const char*  info;
+  unsigned int mode_request;
+
+  assert(0 != cptr);
+  assert(cptr == sptr);
+
+  if (IsServerPort(cptr))
+    return exit_client(cptr, cptr, &me, "Use a different port");
+
+  if (parc < 5)
+    return need_more_params(sptr, "USER");
+
+  /* 
+   * Copy parameters into better documenting variables
+   *
+   * ignore host part if u@h
+   */
+  if (!EmptyString(parv[1])) {
+    if ((username = strchr(parv[1], '@')))
+      *username = '\0';
+    username = parv[1];
+  }
+  else
+    username = "NoUser";
+
+  if ((mode_request = strtoul(parv[2], &term, 10)) != 0
+      && term != NULL && *term == '\0')
+  {
+    char *invisible[4] = { NULL, NULL, "+i", NULL };
+    char *wallops[4] = { NULL, NULL, "+w" , NULL };
+    /* These bitmask values are codified in RFC 2812, showing
+     * ... well, something that is probably best not said.
+     */
+    if (mode_request & 8)
+      set_user_mode(cptr, sptr, 3, invisible, ALLOWMODES_ANY);
+    if (mode_request & 4)
+      set_user_mode(cptr, sptr, 3, wallops, ALLOWMODES_ANY);
+  }
+  else if (parv[2][0] == '+')
+  {
+    char *user_modes[4];
+    user_modes[0] = NULL;
+    user_modes[1] = NULL;
+    user_modes[2] = parv[2];
+    user_modes[3] = NULL;
+    set_user_mode(cptr, sptr, 3, user_modes, ALLOWMODES_ANY);
+  }
+
+  info     = (EmptyString(parv[4])) ? "No Info" : parv[4];
+
+  return auth_set_user(cli_auth(cptr), username, parv[2], parv[3], info);
+}
+
diff --git a/ircd/m_userhost.c b/ircd/m_userhost.c
new file mode 100644 (file)
index 0000000..98ec847
--- /dev/null
@@ -0,0 +1,124 @@
+/*
+ * IRC - Internet Relay Chat, ircd/m_userhost.c
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ *                    University of Oulu, Computing Center
+ *
+ * See file AUTHORS in IRC package for additional names of
+ * the programmers.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id: m_userhost.c 1375 2005-04-22 01:39:08Z klmitch $
+ */
+
+/*
+ * m_functions execute protocol messages on this server:
+ *
+ *    cptr    is always NON-NULL, pointing to a *LOCAL* client
+ *            structure (with an open socket connected!). This
+ *            identifies the physical socket where the message
+ *            originated (or which caused the m_function to be
+ *            executed--some m_functions may call others...).
+ *
+ *    sptr    is the source of the message, defined by the
+ *            prefix part of the message if present. If not
+ *            or prefix not found, then sptr==cptr.
+ *
+ *            (!IsServer(cptr)) => (cptr == sptr), because
+ *            prefixes are taken *only* from servers...
+ *
+ *            (IsServer(cptr))
+ *                    (sptr == cptr) => the message didn't
+ *                    have the prefix.
+ *
+ *                    (sptr != cptr && IsServer(sptr) means
+ *                    the prefix specified servername. (?)
+ *
+ *                    (sptr != cptr && !IsServer(sptr) means
+ *                    that message originated from a remote
+ *                    user (not local).
+ *
+ *            combining
+ *
+ *            (!IsServer(sptr)) means that, sptr can safely
+ *            taken as defining the target structure of the
+ *            message in this server.
+ *
+ *    *Always* true (if 'parse' and others are working correct):
+ *
+ *    1)      sptr->from == cptr  (note: cptr->from == cptr)
+ *
+ *    2)      MyConnect(sptr) <=> sptr == cptr (e.g. sptr
+ *            *cannot* be a local connection, unless it's
+ *            actually cptr!). [MyConnect(x) should probably
+ *            be defined as (x == x->from) --msa ]
+ *
+ *    parc    number of variable parameter strings (if zero,
+ *            parv is allowed to be NULL)
+ *
+ *    parv    a NULL terminated list of parameter pointers,
+ *
+ *                    parv[0], sender (prefix string), if not present
+ *                            this points to an empty string.
+ *                    parv[1]...parv[parc-1]
+ *                            pointers to additional parameters
+ *                    parv[parc] == NULL, *always*
+ *
+ *            note:   it is guaranteed that parv[0]..parv[parc-1] are all
+ *                    non-NULL pointers.
+ */
+#include "config.h"
+
+#include "client.h"
+#include "ircd_log.h"
+#include "ircd_reply.h"
+#include "ircd_string.h"
+#include "msgq.h"
+#include "numeric.h"
+#include "s_user.h"
+#include "struct.h"
+
+/* #include <assert.h> -- Now using assert in ircd_log.h */
+
+static void userhost_formatter(struct Client* cptr, struct Client *sptr, struct MsgBuf* mb)
+{
+  assert(IsUser(cptr));
+  msgq_append(0, mb, "%s%s=%c%s@%s", cli_name(cptr),
+              SeeOper(sptr,cptr) ? "*" : "",
+             cli_user(cptr)->away ? '-' : '+', cli_user(cptr)->username,
+             /* Do not *EVER* change this to give opers the real host.
+              * Too many scripts rely on this data and can inadvertently
+              * publish the user's real host, thus breaking the security
+              * of +x.  If an oper wants the real host, he should go to
+              * /whois to get it.
+              */
+             HasHiddenHost(cptr) && (sptr != cptr) ?
+             cli_user(cptr)->host : cli_user(cptr)->realhost);
+}
+
+/*
+ * m_userhost - generic message handler
+ */
+int m_userhost(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  assert(0 != cptr);
+  assert(sptr == cptr);
+
+  if (parc < 2)
+    return need_more_params(sptr, "USERHOST");
+
+  send_user_info(sptr, parv[1], RPL_USERHOST, userhost_formatter);
+  return 0;
+}
diff --git a/ircd/m_userip.c b/ircd/m_userip.c
new file mode 100644 (file)
index 0000000..04ae8f9
--- /dev/null
@@ -0,0 +1,125 @@
+/*
+ * IRC - Internet Relay Chat, ircd/m_userip.c
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ *                    University of Oulu, Computing Center
+ *
+ * See file AUTHORS in IRC package for additional names of
+ * the programmers.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id: m_userip.c 1375 2005-04-22 01:39:08Z klmitch $
+ */
+
+/*
+ * m_functions execute protocol messages on this server:
+ *
+ *    cptr    is always NON-NULL, pointing to a *LOCAL* client
+ *            structure (with an open socket connected!). This
+ *            identifies the physical socket where the message
+ *            originated (or which caused the m_function to be
+ *            executed--some m_functions may call others...).
+ *
+ *    sptr    is the source of the message, defined by the
+ *            prefix part of the message if present. If not
+ *            or prefix not found, then sptr==cptr.
+ *
+ *            (!IsServer(cptr)) => (cptr == sptr), because
+ *            prefixes are taken *only* from servers...
+ *
+ *            (IsServer(cptr))
+ *                    (sptr == cptr) => the message didn't
+ *                    have the prefix.
+ *
+ *                    (sptr != cptr && IsServer(sptr) means
+ *                    the prefix specified servername. (?)
+ *
+ *                    (sptr != cptr && !IsServer(sptr) means
+ *                    that message originated from a remote
+ *                    user (not local).
+ *
+ *            combining
+ *
+ *            (!IsServer(sptr)) means that, sptr can safely
+ *            taken as defining the target structure of the
+ *            message in this server.
+ *
+ *    *Always* true (if 'parse' and others are working correct):
+ *
+ *    1)      sptr->from == cptr  (note: cptr->from == cptr)
+ *
+ *    2)      MyConnect(sptr) <=> sptr == cptr (e.g. sptr
+ *            *cannot* be a local connection, unless it's
+ *            actually cptr!). [MyConnect(x) should probably
+ *            be defined as (x == x->from) --msa ]
+ *
+ *    parc    number of variable parameter strings (if zero,
+ *            parv is allowed to be NULL)
+ *
+ *    parv    a NULL terminated list of parameter pointers,
+ *
+ *                    parv[0], sender (prefix string), if not present
+ *                            this points to an empty string.
+ *                    parv[1]...parv[parc-1]
+ *                            pointers to additional parameters
+ *                    parv[parc] == NULL, *always*
+ *
+ *            note:   it is guaranteed that parv[0]..parv[parc-1] are all
+ *                    non-NULL pointers.
+ */
+#include "config.h"
+
+#include "client.h"
+#include "ircd_reply.h"
+#include "ircd_string.h"
+#include "ircd_features.h"
+#include "ircd_log.h"
+#include "msgq.h"
+#include "numeric.h"
+#include "s_user.h"
+#include "struct.h"
+
+/* #include <assert.h> -- Now using assert in ircd_log.h */
+
+static void userip_formatter(struct Client* cptr, struct Client *sptr, struct MsgBuf* mb)
+{
+  assert(IsUser(cptr));
+  msgq_append(0, mb, "%s%s=%c%s@%s", cli_name(cptr),
+             SeeOper(sptr,cptr) ? "*" : "",
+             cli_user(cptr)->away ? '-' : '+', cli_user(cptr)->username,
+             /* Do not *EVER* change this to give opers the real IP.
+              * Too many scripts rely on this data and can inadvertently
+              * publish the user's real IP, thus breaking the security
+              * of +x.  If an oper wants the real IP, he should go to
+              * /whois to get it.
+              */
+             HasHiddenHost(cptr) && (sptr != cptr) ?
+             feature_str(FEAT_HIDDEN_IP) :
+             ircd_ntoa(&cli_ip(cptr)));
+}
+
+/*
+ * m_userip - generic message handler
+ */
+int m_userip(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  assert(0 != cptr);
+  assert(cptr == sptr);
+
+  if (parc < 2)
+    return need_more_params(sptr, "USERIP");
+  send_user_info(sptr, parv[1], RPL_USERIP, userip_formatter); 
+  return 0;
+}
diff --git a/ircd/m_version.c b/ircd/m_version.c
new file mode 100644 (file)
index 0000000..a0349e3
--- /dev/null
@@ -0,0 +1,187 @@
+/*
+ * IRC - Internet Relay Chat, ircd/m_version.c
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ *                    University of Oulu, Computing Center
+ *
+ * See file AUTHORS in IRC package for additional names of
+ * the programmers.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id: m_version.c 1803 2007-05-20 13:02:51Z entrope $
+ */
+
+/*
+ * m_functions execute protocol messages on this server:
+ *
+ *    cptr    is always NON-NULL, pointing to a *LOCAL* client
+ *            structure (with an open socket connected!). This
+ *            identifies the physical socket where the message
+ *            originated (or which caused the m_function to be
+ *            executed--some m_functions may call others...).
+ *
+ *    sptr    is the source of the message, defined by the
+ *            prefix part of the message if present. If not
+ *            or prefix not found, then sptr==cptr.
+ *
+ *            (!IsServer(cptr)) => (cptr == sptr), because
+ *            prefixes are taken *only* from servers...
+ *
+ *            (IsServer(cptr))
+ *                    (sptr == cptr) => the message didn't
+ *                    have the prefix.
+ *
+ *                    (sptr != cptr && IsServer(sptr) means
+ *                    the prefix specified servername. (?)
+ *
+ *                    (sptr != cptr && !IsServer(sptr) means
+ *                    that message originated from a remote
+ *                    user (not local).
+ *
+ *            combining
+ *
+ *            (!IsServer(sptr)) means that, sptr can safely
+ *            taken as defining the target structure of the
+ *            message in this server.
+ *
+ *    *Always* true (if 'parse' and others are working correct):
+ *
+ *    1)      sptr->from == cptr  (note: cptr->from == cptr)
+ *
+ *    2)      MyConnect(sptr) <=> sptr == cptr (e.g. sptr
+ *            *cannot* be a local connection, unless it's
+ *            actually cptr!). [MyConnect(x) should probably
+ *            be defined as (x == x->from) --msa ]
+ *
+ *    parc    number of variable parameter strings (if zero,
+ *            parv is allowed to be NULL)
+ *
+ *    parv    a NULL terminated list of parameter pointers,
+ *
+ *                    parv[0], sender (prefix string), if not present
+ *                            this points to an empty string.
+ *                    parv[1]...parv[parc-1]
+ *                            pointers to additional parameters
+ *                    parv[parc] == NULL, *always*
+ *
+ *            note:   it is guaranteed that parv[0]..parv[parc-1] are all
+ *                    non-NULL pointers.
+ */
+#include "config.h"
+
+#include "client.h"
+#include "hash.h"
+#include "ircd.h"
+#include "ircd_features.h"
+#include "ircd_log.h"
+#include "ircd_reply.h"
+#include "ircd_snprintf.h"
+#include "ircd_string.h"
+#include "match.h"
+#include "msg.h"
+#include "numeric.h"
+#include "numnicks.h"
+#include "s_debug.h"
+#include "s_user.h"
+#include "send.h"
+#include "supported.h"
+#include "version.h"
+
+/* #include <assert.h> -- Now using assert in ircd_log.h */
+
+/*
+ * m_version - generic message handler
+ *
+ *   parv[0] = sender prefix
+ *   parv[1] = servername
+ */
+int m_version(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  if (parc > 1 && match(parv[1], cli_name(&me)))
+    return send_reply(sptr, ERR_NOPRIVILEGES);
+  /*
+  don't remove this!
+  */
+  char tmp[512] = "OGN IRCu - edited by pk910 (http://ircu.pk910.de) ";
+  strcat(tmp,debug_serveropts());
+  send_reply(sptr, RPL_VERSION, version, debugmode, cli_name(&me),tmp);
+  send_supported(sptr);
+  return 0;
+}
+
+/*
+ * mo_version - oper message handler
+ *
+ *   parv[0] = sender prefix
+ *   parv[1] = servername
+ */
+int mo_version(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  struct Client *acptr;
+
+  if (MyConnect(sptr) && parc > 1)
+  {
+    if (!(acptr = find_match_server(parv[1])))
+    {
+      send_reply(sptr, ERR_NOSUCHSERVER, parv[1]);
+      return 0;
+    }
+    parv[1] = cli_name(acptr);
+  }
+
+  if (hunt_server_cmd(sptr, CMD_VERSION, cptr, feature_int(FEAT_HIS_REMOTE),
+                                                           ":%C", 1,
+                                                           parc, parv)
+                      == HUNTED_ISME)
+  {
+       char tmp[512] = "OGN IRCu - edited by pk910 (http://ircu.pk910.de) ";
+       strcat(tmp,debug_serveropts());
+    send_reply(sptr, RPL_VERSION, version, debugmode, cli_name(&me),tmp);
+    send_supported(sptr);
+  }
+
+  return 0;
+}
+
+/*
+ * ms_version - server message handler
+ *
+ *   parv[0] = sender prefix
+ *   parv[1] = servername
+ */
+int ms_version(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  struct Client *acptr;
+
+  if (MyConnect(sptr) && parc > 1)
+  {
+    if (!(acptr = find_match_server(parv[1])))
+    {
+      send_reply(sptr, ERR_NOSUCHSERVER, parv[1]);
+      return 0;
+    }
+    parv[1] = cli_name(acptr);
+  }
+
+  if (hunt_server_cmd(sptr, CMD_VERSION, cptr, 0, ":%C", 1, parc, parv) ==
+      HUNTED_ISME)
+  {
+       char tmp[512] = "OGN IRCu - edited by pk910 (http://ircu.pk910.de) ";
+       strcat(tmp,debug_serveropts());
+    send_reply(sptr, RPL_VERSION, version, debugmode, cli_name(&me),tmp);
+  }
+
+  return 0;
+}
diff --git a/ircd/m_wallchops.c b/ircd/m_wallchops.c
new file mode 100644 (file)
index 0000000..aee8644
--- /dev/null
@@ -0,0 +1,157 @@
+/*
+ * IRC - Internet Relay Chat, ircd/m_wallchops.c
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ *                    University of Oulu, Computing Center
+ *
+ * See file AUTHORS in IRC package for additional names of
+ * the programmers.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id: m_wallchops.c 1903 2009-01-13 03:54:45Z entrope $
+ */
+
+/*
+ * m_functions execute protocol messages on this server:
+ *
+ *    cptr    is always NON-NULL, pointing to a *LOCAL* client
+ *            structure (with an open socket connected!). This
+ *            identifies the physical socket where the message
+ *            originated (or which caused the m_function to be
+ *            executed--some m_functions may call others...).
+ *
+ *    sptr    is the source of the message, defined by the
+ *            prefix part of the message if present. If not
+ *            or prefix not found, then sptr==cptr.
+ *
+ *            (!IsServer(cptr)) => (cptr == sptr), because
+ *            prefixes are taken *only* from servers...
+ *
+ *            (IsServer(cptr))
+ *                    (sptr == cptr) => the message didn't
+ *                    have the prefix.
+ *
+ *                    (sptr != cptr && IsServer(sptr) means
+ *                    the prefix specified servername. (?)
+ *
+ *                    (sptr != cptr && !IsServer(sptr) means
+ *                    that message originated from a remote
+ *                    user (not local).
+ *
+ *            combining
+ *
+ *            (!IsServer(sptr)) means that, sptr can safely
+ *            taken as defining the target structure of the
+ *            message in this server.
+ *
+ *    *Always* true (if 'parse' and others are working correct):
+ *
+ *    1)      sptr->from == cptr  (note: cptr->from == cptr)
+ *
+ *    2)      MyConnect(sptr) <=> sptr == cptr (e.g. sptr
+ *            *cannot* be a local connection, unless it's
+ *            actually cptr!). [MyConnect(x) should probably
+ *            be defined as (x == x->from) --msa ]
+ *
+ *    parc    number of variable parameter strings (if zero,
+ *            parv is allowed to be NULL)
+ *
+ *    parv    a NULL terminated list of parameter pointers,
+ *
+ *                    parv[0], sender (prefix string), if not present
+ *                            this points to an empty string.
+ *                    parv[1]...parv[parc-1]
+ *                            pointers to additional parameters
+ *                    parv[parc] == NULL, *always*
+ *
+ *            note:   it is guaranteed that parv[0]..parv[parc-1] are all
+ *                    non-NULL pointers.
+ */
+#include "config.h"
+
+#include "channel.h"
+#include "client.h"
+#include "hash.h"
+#include "ircd.h"
+#include "ircd_log.h"
+#include "ircd_reply.h"
+#include "ircd_string.h"
+#include "msg.h"
+#include "numeric.h"
+#include "numnicks.h"
+#include "s_user.h"
+#include "send.h"
+
+/* #include <assert.h> -- Now using assert in ircd_log.h */
+
+/*
+ * m_wallchops - local generic message handler
+ */
+int m_wallchops(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  struct Channel *chptr;
+
+  assert(0 != cptr);
+  assert(cptr == sptr);
+
+  ClrFlag(sptr, FLAG_TS8);
+
+  if (parc < 2 || EmptyString(parv[1]))
+    return send_reply(sptr, ERR_NORECIPIENT, "WALLCHOPS");
+
+  if (parc < 3 || EmptyString(parv[parc - 1]))
+    return send_reply(sptr, ERR_NOTEXTTOSEND);
+
+  if (IsChannelName(parv[1]) && (chptr = FindChannel(parv[1]))) {
+    if (client_can_send_to_channel(sptr, chptr, 0)) {
+      if ((chptr->mode.mode & MODE_NOPRIVMSGS) &&
+          check_target_limit(sptr, chptr, chptr->chname, 0))
+        return 0;
+      RevealDelayedJoinIfNeeded(sptr, chptr);
+      sendcmdto_channel_butone(sptr, CMD_WALLCHOPS, chptr, cptr,
+                              SKIP_DEAF | SKIP_BURST | SKIP_NONOPS,
+                              '\0', "%H :@ %s", chptr, parv[parc - 1]);
+    }
+    else
+      send_reply(sptr, ERR_CANNOTSENDTOCHAN, parv[1]);
+  }
+  else
+    send_reply(sptr, ERR_NOSUCHCHANNEL, parv[1]);
+
+  return 0;
+}
+
+/*
+ * ms_wallchops - server message handler
+ */
+int ms_wallchops(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  struct Channel *chptr;
+  assert(0 != cptr);
+  assert(0 != sptr);
+
+  if (parc < 3 || !IsUser(sptr))
+    return 0;
+
+  if (!IsLocalChannel(parv[1]) && (chptr = FindChannel(parv[1]))) {
+    if (client_can_send_to_channel(sptr, chptr, 1)) {
+      sendcmdto_channel_butone(sptr, CMD_WALLCHOPS, chptr, cptr,
+                              SKIP_DEAF | SKIP_BURST | SKIP_NONOPS,
+                              '\0', "%H :%s", chptr, parv[parc - 1]);
+    } else
+      send_reply(sptr, ERR_CANNOTSENDTOCHAN, parv[1]);
+  }
+  return 0;
+}
diff --git a/ircd/m_wallops.c b/ircd/m_wallops.c
new file mode 100644 (file)
index 0000000..4ca2862
--- /dev/null
@@ -0,0 +1,125 @@
+/*
+ * IRC - Internet Relay Chat, ircd/m_wallops.c
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ *                    University of Oulu, Computing Center
+ *
+ * See file AUTHORS in IRC package for additional names of
+ * the programmers.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id: m_wallops.c 1271 2004-12-11 05:14:07Z klmitch $
+ */
+
+/*
+ * m_functions execute protocol messages on this server:
+ *
+ *    cptr    is always NON-NULL, pointing to a *LOCAL* client
+ *            structure (with an open socket connected!). This
+ *            identifies the physical socket where the message
+ *            originated (or which caused the m_function to be
+ *            executed--some m_functions may call others...).
+ *
+ *    sptr    is the source of the message, defined by the
+ *            prefix part of the message if present. If not
+ *            or prefix not found, then sptr==cptr.
+ *
+ *            (!IsServer(cptr)) => (cptr == sptr), because
+ *            prefixes are taken *only* from servers...
+ *
+ *            (IsServer(cptr))
+ *                    (sptr == cptr) => the message didn't
+ *                    have the prefix.
+ *
+ *                    (sptr != cptr && IsServer(sptr) means
+ *                    the prefix specified servername. (?)
+ *
+ *                    (sptr != cptr && !IsServer(sptr) means
+ *                    that message originated from a remote
+ *                    user (not local).
+ *
+ *            combining
+ *
+ *            (!IsServer(sptr)) means that, sptr can safely
+ *            taken as defining the target structure of the
+ *            message in this server.
+ *
+ *    *Always* true (if 'parse' and others are working correct):
+ *
+ *    1)      sptr->from == cptr  (note: cptr->from == cptr)
+ *
+ *    2)      MyConnect(sptr) <=> sptr == cptr (e.g. sptr
+ *            *cannot* be a local connection, unless it's
+ *            actually cptr!). [MyConnect(x) should probably
+ *            be defined as (x == x->from) --msa ]
+ *
+ *    parc    number of variable parameter strings (if zero,
+ *            parv is allowed to be NULL)
+ *
+ *    parv    a NULL terminated list of parameter pointers,
+ *
+ *                    parv[0], sender (prefix string), if not present
+ *                            this points to an empty string.
+ *                    parv[1]...parv[parc-1]
+ *                            pointers to additional parameters
+ *                    parv[parc] == NULL, *always*
+ *
+ *            note:   it is guaranteed that parv[0]..parv[parc-1] are all
+ *                    non-NULL pointers.
+ */
+#include "config.h"
+
+#include "client.h"
+#include "ircd_log.h"
+#include "ircd_reply.h"
+#include "ircd_string.h"
+#include "msg.h"
+#include "numeric.h"
+#include "send.h"
+
+/* #include <assert.h> -- Now using assert in ircd_log.h */
+
+
+/*
+ * ms_wallops - server message handler
+ */
+int ms_wallops(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  char *message;
+
+  message = parc > 1 ? parv[1] : 0;
+
+  if (EmptyString(message))
+    return need_more_params(sptr, "WALLOPS");
+
+  sendwallto_group_butone(sptr, WALL_WALLOPS, cptr, "%s", message);
+  return 0;
+}
+
+/*
+ * mo_wallops - oper message handler
+ */
+int mo_wallops(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  char *message;
+
+  message = parc > 1 ? parv[1] : 0;
+
+  if (EmptyString(message))
+    return need_more_params(sptr, "WALLOPS");
+
+  sendwallto_group_butone(sptr, WALL_WALLOPS, 0, "%s", message);
+  return 0;
+}
diff --git a/ircd/m_wallusers.c b/ircd/m_wallusers.c
new file mode 100644 (file)
index 0000000..e7f3a99
--- /dev/null
@@ -0,0 +1,130 @@
+/*
+ * IRC - Internet Relay Chat, ircd/m_wallusers.c
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ *                    University of Oulu, Computing Center
+ *
+ * See file AUTHORS in IRC package for additional names of
+ * the programmers.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id: m_wallusers.c 1271 2004-12-11 05:14:07Z klmitch $
+ */
+
+/*
+ * m_functions execute protocol messages on this server:
+ *
+ *    cptr    is always NON-NULL, pointing to a *LOCAL* client
+ *            structure (with an open socket connected!). This
+ *            identifies the physical socket where the message
+ *            originated (or which caused the m_function to be
+ *            executed--some m_functions may call others...).
+ *
+ *    sptr    is the source of the message, defined by the
+ *            prefix part of the message if present. If not
+ *            or prefix not found, then sptr==cptr.
+ *
+ *            (!IsServer(cptr)) => (cptr == sptr), because
+ *            prefixes are taken *only* from servers...
+ *
+ *            (IsServer(cptr))
+ *                    (sptr == cptr) => the message didn't
+ *                    have the prefix.
+ *
+ *                    (sptr != cptr && IsServer(sptr) means
+ *                    the prefix specified servername. (?)
+ *
+ *                    (sptr != cptr && !IsServer(sptr) means
+ *                    that message originated from a remote
+ *                    user (not local).
+ *
+ *            combining
+ *
+ *            (!IsServer(sptr)) means that, sptr can safely
+ *            taken as defining the target structure of the
+ *            message in this server.
+ *
+ *    *Always* true (if 'parse' and others are working correct):
+ *
+ *    1)      sptr->from == cptr  (note: cptr->from == cptr)
+ *
+ *    2)      MyConnect(sptr) <=> sptr == cptr (e.g. sptr
+ *            *cannot* be a local connection, unless it's
+ *            actually cptr!). [MyConnect(x) should probably
+ *            be defined as (x == x->from) --msa ]
+ *
+ *    parc    number of variable parameter strings (if zero,
+ *            parv is allowed to be NULL)
+ *
+ *    parv    a NULL terminated list of parameter pointers,
+ *
+ *                    parv[0], sender (prefix string), if not present
+ *                            this points to an empty string.
+ *                    parv[1]...parv[parc-1]
+ *                            pointers to additional parameters
+ *                    parv[parc] == NULL, *always*
+ *
+ *            note:   it is guaranteed that parv[0]..parv[parc-1] are all
+ *                    non-NULL pointers.
+ */
+#include "config.h"
+
+#include "client.h"
+#include "ircd_log.h"
+#include "ircd_reply.h"
+#include "ircd_string.h"
+#include "msg.h"
+#include "numeric.h"
+#include "send.h"
+
+/* #include <assert.h> -- Now using assert in ircd_log.h */
+
+
+/*
+ * ms_wallusers - server message handler
+ */
+int ms_wallusers(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  char *message;
+
+  message = parc > 1 ? parv[1] : 0;
+
+  /*
+   * XXX - PROTOCOL ERROR (shouldn't happen)
+   */
+  if (EmptyString(message))
+    return need_more_params(sptr, "WALLUSERS");
+
+  sendwallto_group_butone(sptr, WALL_WALLUSERS, cptr, "%s",
+                       message);
+  return 0;
+}
+
+/*
+ * mo_wallusers - oper message handler
+ */
+int mo_wallusers(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  char *message;
+
+  message = parc > 1 ? parv[1] : 0;
+
+  if (EmptyString(message))
+    return need_more_params(sptr, "WALLUSERS");
+
+  sendwallto_group_butone(sptr, WALL_WALLUSERS, 0, "%s", message);
+  return 0;
+}
+
diff --git a/ircd/m_wallvoices.c b/ircd/m_wallvoices.c
new file mode 100644 (file)
index 0000000..34a7eeb
--- /dev/null
@@ -0,0 +1,156 @@
+/*
+ * IRC - Internet Relay Chat, ircd/m_wallvoices.c
+ * Copyright (c) 2002 hikari
+ *
+ * See file AUTHORS in IRC package for additional names of
+ * the programmers.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id: m_wallvoices.c 1903 2009-01-13 03:54:45Z entrope $
+ */
+
+/*
+ * m_functions execute protocol messages on this server:
+ *
+ *    cptr    is always NON-NULL, pointing to a *LOCAL* client
+ *            structure (with an open socket connected!). This
+ *            identifies the physical socket where the message
+ *            originated (or which caused the m_function to be
+ *            executed--some m_functions may call others...).
+ *
+ *    sptr    is the source of the message, defined by the
+ *            prefix part of the message if present. If not
+ *            or prefix not found, then sptr==cptr.
+ *
+ *            (!IsServer(cptr)) => (cptr == sptr), because
+ *            prefixes are taken *only* from servers...
+ *
+ *            (IsServer(cptr))
+ *                    (sptr == cptr) => the message didn't
+ *                    have the prefix.
+ *
+ *                    (sptr != cptr && IsServer(sptr) means
+ *                    the prefix specified servername. (?)
+ *
+ *                    (sptr != cptr && !IsServer(sptr) means
+ *                    that message originated from a remote
+ *                    user (not local).
+ *
+ *            combining
+ *
+ *            (!IsServer(sptr)) means that, sptr can safely
+ *            taken as defining the target structure of the
+ *            message in this server.
+ *
+ *    *Always* true (if 'parse' and others are working correct):
+ *
+ *    1)      sptr->from == cptr  (note: cptr->from == cptr)
+ *
+ *    2)      MyConnect(sptr) <=> sptr == cptr (e.g. sptr
+ *            *cannot* be a local connection, unless it's
+ *            actually cptr!). [MyConnect(x) should probably
+ *            be defined as (x == x->from) --msa ]
+ *
+ *    parc    number of variable parameter strings (if zero,
+ *            parv is allowed to be NULL)
+ *
+ *    parv    a NULL terminated list of parameter pointers,
+ *
+ *                    parv[0], sender (prefix string), if not present
+ *                            this points to an empty string.
+ *                    parv[1]...parv[parc-1]
+ *                            pointers to additional parameters
+ *                    parv[parc] == NULL, *always*
+ *
+ *            note:   it is guaranteed that parv[0]..parv[parc-1] are all
+ *                    non-NULL pointers.
+ */
+#include "config.h"
+
+#include "channel.h"
+#include "client.h"
+#include "hash.h"
+#include "ircd.h"
+#include "ircd_log.h"
+#include "ircd_reply.h"
+#include "ircd_string.h"
+#include "msg.h"
+#include "numeric.h"
+#include "numnicks.h"
+#include "s_user.h"
+#include "send.h"
+
+/* #include <assert.h> -- Now using assert in ircd_log.h */
+
+/*
+ * m_wallvoices - local generic message handler
+ */
+int m_wallvoices(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  struct Channel *chptr;
+
+  assert(0 != cptr);
+  assert(cptr == sptr);
+
+  ClrFlag(sptr, FLAG_TS8);
+
+  if (parc < 2 || EmptyString(parv[1]))
+    return send_reply(sptr, ERR_NORECIPIENT, "WALLVOICES");
+
+  if (parc < 3 || EmptyString(parv[parc - 1]))
+    return send_reply(sptr, ERR_NOTEXTTOSEND);
+
+  if (IsChannelName(parv[1]) && (chptr = FindChannel(parv[1]))) {
+    if (client_can_send_to_channel(sptr, chptr, 0)) {
+      if ((chptr->mode.mode & MODE_NOPRIVMSGS) &&
+          check_target_limit(sptr, chptr, chptr->chname, 0))
+        return 0;
+      RevealDelayedJoinIfNeeded(sptr, chptr);
+      sendcmdto_channel_butone(sptr, CMD_WALLVOICES, chptr, cptr,
+                              SKIP_DEAF | SKIP_BURST | SKIP_NONVOICES, 
+                              '\0', "%H :+ %s", chptr, parv[parc - 1]);
+    }
+    else
+      send_reply(sptr, ERR_CANNOTSENDTOCHAN, parv[1]);
+  }
+  else
+    send_reply(sptr, ERR_NOSUCHCHANNEL, parv[1]);
+
+  return 0;
+}
+
+/*
+ * ms_wallvoices - server message handler
+ */
+int ms_wallvoices(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  struct Channel *chptr;
+  assert(0 != cptr);
+  assert(0 != sptr);
+
+  if (parc < 3 || !IsUser(sptr))
+    return 0;
+
+  if (!IsLocalChannel(parv[1]) && (chptr = FindChannel(parv[1]))) {
+    if (client_can_send_to_channel(sptr, chptr, 1)) {
+      sendcmdto_channel_butone(sptr, CMD_WALLVOICES, chptr, cptr,
+                              SKIP_DEAF | SKIP_BURST | SKIP_NONVOICES, 
+                              '\0', "%H :%s", chptr, parv[parc - 1]);
+    } else
+      send_reply(sptr, ERR_CANNOTSENDTOCHAN, parv[1]);
+  }
+  return 0;
+}
diff --git a/ircd/m_webirc.c b/ircd/m_webirc.c
new file mode 100644 (file)
index 0000000..6f05d2c
--- /dev/null
@@ -0,0 +1,250 @@
+/*
+ * IRC - Internet Relay Chat, ircd/m_svsnick.c
+ * Written by David Herrmann.
+ */
+
+#include "config.h"
+
+#include "client.h"
+#include "hash.h"
+#include "ircd.h"
+#include "ircd_alloc.h"
+#include "ircd_log.h"
+#include "ircd_reply.h"
+#include "ircd_string.h"
+#include "ircd_features.h"
+#include "ircd_crypt.h"
+#include "numeric.h"
+#include "numnicks.h"
+#include "send.h"
+#include "s_conf.h"
+#include "s_misc.h"
+#include "s_debug.h"
+#include "match.h"
+#include "IPcheck.h"
+#include "ssl.h"
+#include "res.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+/* Sends response \r (len: \l) to client \c. */
+#define webirc_resp(c, r, l) \
+   ssl_send(cli_fd(c), cli_socket(c).ssl, r, l)
+
+/* Buffer used in nick replacements. */
+static char webirc_buf[513];
+
+/* Returns 1 if the passwords are the same and 0 if not.
+ * \to_match is the password hash
+ * \passwd is the unhashed password in "$KIND$password" style
+ */
+static unsigned int webirc_pwmatch(const char* to_match, const char* passwd) {
+    char *crypted;
+    signed int res;
+
+    crypted = ircd_crypt(to_match, passwd);
+    if(!crypted)
+        return 0;
+    Debug((DEBUG_NOTICE, "WebIRC: Passwort check: %s = %s", crypted, passwd));
+    res = strcmp(crypted, passwd);
+    MyFree(crypted);
+    return 0 == res;
+}
+
+/* Checks whether password/host/spoofed host/ip are allowed and returns the corresponding webirc block.
+ * Returns NULL if nothing found.
+ */
+static struct webirc_block *webirc_match(const char *passwd, const char *real_host, const char *real_ip, const char *spoofed_host, const char *spoofed_ip) {
+    struct webirc_block *iter;
+    struct webirc_node *inode;
+    unsigned int matched = 0;
+
+    if(!GlobalWebIRCConf) {
+        Debug((DEBUG_NOTICE, "WebIRC: no global webirc conf"));
+        return NULL;
+    }
+
+    iter = GlobalWebIRCConf;
+    do {
+        if(iter->list) {
+            inode = iter->list;
+
+            /* first check for matching password */
+            do {
+                /* it's a sorted list an passwords are stored first! */
+
+                if(inode->type != WEBIRC_PASS) break;
+                Debug((DEBUG_NOTICE, "WebIRC: pass: %s",inode->content));
+                if(webirc_pwmatch(passwd, inode->content)) {
+                    matched = 1;
+                    break;
+                }
+
+                inode = inode->next;
+            } while(inode != iter->list);
+
+            /* go to next entry */
+            inode = inode->next;
+
+            if(!matched)
+                Debug((DEBUG_NOTICE, "WebIRC: Password missmatch"));
+
+            /* check for matching real-host/ip */
+            if(matched) {
+                matched = 0;
+                /* fast-forward to hosts and then check the hosts */
+                do {
+                    /* everything greater than WEBIRC_HOSTS are the spoofed masks */
+                    if(inode->type > WEBIRC_HOST) break;
+
+                    if(inode->type == WEBIRC_HOST) {
+                        if(inode->neg) {
+                            if(match(inode->content, real_host) == 0 || match(inode->content, real_ip) == 0) {
+                                matched = 0;
+                                break;
+                            }
+                        }
+                        else if(matched) /* do nothing */;
+                        else if(match(inode->content, real_host) == 0 || match(inode->content, real_ip) == 0)
+                            matched = 1;
+                    }
+
+                    inode = inode->next;
+                } while(inode != iter->list);
+                if(!matched)
+                    Debug((DEBUG_NOTICE, "WebIRC: host missmatch"));
+            }
+
+            /* check for matching spoofed host/ip */
+            if(matched) {
+                matched = 0;
+                do {
+                    if(inode->type == WEBIRC_SPOOF) {
+                        if(inode->neg) {
+                            if(match(inode->content, spoofed_host) == 0 || match(inode->content, spoofed_ip) == 0) {
+                                matched = 0;
+                                break;
+                            }
+                        }
+                        else if(matched) /* do nothing */;
+                        else if(match(inode->content, spoofed_host) == 0 || match(inode->content, spoofed_ip) == 0)
+                            matched = 1;
+                    }
+
+                    inode = inode->next;
+                } while(inode != iter->list);
+                if(!matched)
+                    Debug((DEBUG_NOTICE, "WebIRC: spoof missmatch"));
+            }
+
+            if(matched) return iter;
+
+            /* nothing found, try next block */
+        }
+        iter = iter->next;
+    } while(iter != GlobalWebIRCConf);
+
+    return NULL;
+}
+
+/*
+ * m_webirc
+ *
+ * parv[0] = sender prefix
+ * parv[1] = password
+ * parv[2] = "cgiirc"
+ * parv[3] = hostname
+ * parv[4] = ip
+ */
+int m_webirc(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) {
+    struct webirc_block *block;
+    struct irc_in_addr addr;
+    const char *con_addr;
+    time_t next_target = 0;
+    unsigned int len;
+
+    const char *nick = (*(cli_name(sptr))) ? cli_name(sptr) : "AUTH";
+    unsigned int auth = (*(cli_name(sptr))) ? 0 : 1;
+
+    /* servers cannot spoof their ip */
+    if(IsServerPort(sptr)) {
+        /* If a server sends WEBIRC command it's a protocol violation so exit him and do not check FEAT_WEBIRC_REJECT. */
+        IPcheck_connect_fail(sptr);
+        return exit_client(cptr, sptr, &me, "WebIRC not supported on server ports");
+    }
+
+    /* all 4 parameters are required plus the prefix => 5 */
+    if(parc < 5)
+        return need_more_params(sptr, "WEBIRC");
+
+    if(strcmp(parv[2], "cgiirc")) {
+        if(feature_bool(FEAT_WEBIRC_REJECT)) {
+            IPcheck_connect_fail(sptr);
+            return exit_client(cptr, sptr, &me, "WebIRC protocol violation (p2).");
+        }
+        else {
+            len = sprintf(webirc_buf, "NOTICE %s :%sWebIRC protocol violation (p2).\r\n", nick, auth ? "*** " : "");
+            webirc_resp(sptr, webirc_buf, len);
+            return 0; /* continue with normal authentication */
+        }
+    }
+
+    /* created ip in dotted notation */
+    con_addr = ircd_ntoa(&(cli_ip(sptr)));
+    if(0 == ipmask_parse(parv[4], &addr, NULL)) {
+        if(feature_bool(FEAT_WEBIRC_REJECT)) {
+            IPcheck_connect_fail(sptr);
+            return exit_client(cptr, sptr, &me, "WebIRC protocol violation (p4).");
+        }
+        else {
+            /* bufferoverflow prevented with NICKLEN check above */
+            len = sprintf(webirc_buf, "NOTICE %s :%sWebIRC protocol violation (p4).\r\n", nick, auth ? "*** " : "");
+            webirc_resp(sptr, webirc_buf, len);
+            return 0; /* continue with normal authentication */
+        }
+    }
+
+    /* find matching webirc block */
+    block = webirc_match(parv[1], cli_sockhost(sptr), con_addr, parv[3], parv[4]);
+    if(!block) {
+        if(feature_bool(FEAT_WEBIRC_REJECT)) {
+            IPcheck_connect_fail(sptr);
+            return exit_client(cptr, sptr, &me, "WebIRC client rejected, no match found.");
+        }
+        else {
+            len = sprintf(webirc_buf, "NOTICE %s :%sWebIRC spoofing rejected, no match found.\r\n", nick, auth?"*** ":"");
+            webirc_resp(sptr, webirc_buf, len);
+            return 0; /* continue with normal authentication */
+        }
+    }
+
+    /* remove the WebIRC ip from the IPcheck entry, we will add the real one later */
+    IPcheck_connect_fail(sptr);
+    IPcheck_disconnect(sptr);
+    ClearIPChecked(sptr);
+
+    /* spoof IP */
+    memcpy(cli_real_ip(sptr).in6_16, cli_ip(sptr).in6_16, 16);
+    memcpy(cli_ip(sptr).in6_16, addr.in6_16, 16);
+
+    /* spoof ip/host strings */
+    ircd_strncpy(cli_real_sock_ip(sptr), cli_sock_ip(sptr), SOCKIPLEN);
+    ircd_strncpy(cli_sock_ip(sptr), parv[4], SOCKIPLEN);
+    ircd_strncpy(cli_real_sockhost(sptr), cli_sockhost(sptr), HOSTLEN);
+    ircd_strncpy(cli_sockhost(sptr), parv[3], HOSTLEN);
+    ircd_strncpy(cli_webirc(sptr), block->name, NICKLEN);
+
+    /* add the real ip to the IPcheck */
+    if(!IPcheck_local_connect(&cli_ip(sptr), &next_target))
+        return exit_client(cptr, sptr, &me, "Too many connections from your host");
+    SetIPChecked(cptr);
+
+    /* set WebIRC umode only if enabled */
+    if(feature_bool(FEAT_WEBIRC_UMODE))
+        SetWebIRC(cptr);
+
+    return 0;
+}
+
diff --git a/ircd/m_who.c b/ircd/m_who.c
new file mode 100644 (file)
index 0000000..7f5277b
--- /dev/null
@@ -0,0 +1,477 @@
+/*
+ * IRC - Internet Relay Chat, ircd/m_who.c
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ *                    University of Oulu, Computing Center
+ *
+ * See file AUTHORS in IRC package for additional names of
+ * the programmers.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id: m_who.c 1829 2007-08-14 03:54:48Z entrope $
+ */
+
+/*
+ * m_functions execute protocol messages on this server:
+ *
+ *    cptr    is always NON-NULL, pointing to a *LOCAL* client
+ *            structure (with an open socket connected!). This
+ *            identifies the physical socket where the message
+ *            originated (or which caused the m_function to be
+ *            executed--some m_functions may call others...).
+ *
+ *    sptr    is the source of the message, defined by the
+ *            prefix part of the message if present. If not
+ *            or prefix not found, then sptr==cptr.
+ *
+ *            (!IsServer(cptr)) => (cptr == sptr), because
+ *            prefixes are taken *only* from servers...
+ *
+ *            (IsServer(cptr))
+ *                    (sptr == cptr) => the message didn't
+ *                    have the prefix.
+ *
+ *                    (sptr != cptr && IsServer(sptr) means
+ *                    the prefix specified servername. (?)
+ *
+ *                    (sptr != cptr && !IsServer(sptr) means
+ *                    that message originated from a remote
+ *                    user (not local).
+ *
+ *            combining
+ *
+ *            (!IsServer(sptr)) means that, sptr can safely
+ *            taken as defining the target structure of the
+ *            message in this server.
+ *
+ *    *Always* true (if 'parse' and others are working correct):
+ *
+ *    1)      sptr->from == cptr  (note: cptr->from == cptr)
+ *
+ *    2)      MyConnect(sptr) <=> sptr == cptr (e.g. sptr
+ *            *cannot* be a local connection, unless it's
+ *            actually cptr!). [MyConnect(x) should probably
+ *            be defined as (x == x->from) --msa ]
+ *
+ *    parc    number of variable parameter strings (if zero,
+ *            parv is allowed to be NULL)
+ *
+ *    parv    a NULL terminated list of parameter pointers,
+ *
+ *                    parv[0], sender (prefix string), if not present
+ *                            this points to an empty string.
+ *                    parv[1]...parv[parc-1]
+ *                            pointers to additional parameters
+ *                    parv[parc] == NULL, *always*
+ *
+ *            note:   it is guaranteed that parv[0]..parv[parc-1] are all
+ *                    non-NULL pointers.
+ */
+#include "config.h"
+
+#include "channel.h"
+#include "client.h"
+#include "hash.h"
+#include "ircd.h"
+#include "ircd_chattr.h"
+#include "ircd_features.h"
+#include "ircd_log.h"
+#include "ircd_reply.h"
+#include "ircd_string.h"
+#include "match.h"
+#include "numeric.h"
+#include "numnicks.h"
+#include "send.h"
+#include "whocmds.h"
+
+/* #include <assert.h> -- Now using assert in ircd_log.h */
+#include <string.h>
+
+
+/*
+ * A little spin-marking utility to tell us which clients we have already
+ * processed and which not
+ */
+static int who_marker = 0;
+static void move_marker(void)
+{
+  if (!++who_marker)
+  {
+    struct Client *cptr = GlobalClientList;
+    while (cptr)
+    {
+      cli_marker(cptr) = 0;
+      cptr = cli_next(cptr);
+    }
+    who_marker++;
+  }
+}
+
+#define CheckMark(x, y) ((x == y) ? 0 : (x = y))
+#define Process(cptr) CheckMark(cli_marker(cptr), who_marker)
+
+/*
+ * m_who - generic message handler
+ *
+ *  parv[0] = sender prefix
+ *  parv[1] = nickname mask list
+ *  parv[2] = additional selection flag, only 'o' for now.
+ *            and %flags to specify what fields to output
+ *            plus a ,querytype if the t flag is specified
+ *            so the final thing will be like o%tnchu,777
+ *  parv[3] = _optional_ parameter that overrides parv[1]
+ *            This can be used as "/quote who foo % :The Black Hacker
+ *            to find me, parv[3] _can_ contain spaces !.
+ */
+int m_who(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  char *mask;           /* The mask we are looking for              */
+  char ch;                      /* Scratch char register                    */
+  struct Channel *chptr;                /* Channel to show                          */
+  struct Client *acptr;         /* Client to show                           */
+
+  int bitsel;                   /* Mask of selectors to apply               */
+  int matchsel;                 /* Which fields the match should apply on    */
+  int counter;                  /* Query size counter,
+                                   initially used to count fields           */
+  int commas;                   /* Does our mask contain any comma ?
+                                   If so is a list..                        */
+  int fields;                   /* Mask of fields to show                   */
+  int isthere = 0;              /* When this set the user is member of chptr */
+  char *nick;                   /* Single element extracted from
+                                   the mask list                            */
+  char *p;                      /* Scratch char pointer                     */
+  char *qrt;                    /* Pointer to the query type                */
+  static char mymask[512];      /* To save the mask before corrupting it    */
+
+  /* Let's find where is our mask, and if actually contains something */
+  mask = ((parc > 1) ? parv[1] : 0);
+  if (parc > 3 && parv[3])
+    mask = parv[3];
+  if (mask && ((mask[0] == '\0') ||
+      (mask[1] == '\0' && ((mask[0] == '0') || (mask[0] == '*')))))
+    mask = 0;
+
+  /* Evaluate the flags now, we consider the second parameter 
+     as "matchFlags%fieldsToInclude,querytype"           */
+  bitsel = fields = counter = matchsel = 0;
+  qrt = 0;
+  if (parc > 2 && parv[2] && *parv[2])
+  {
+    p = parv[2];
+    while (((ch = *(p++))) && (ch != '%') && (ch != ','))
+      switch (ch)
+      {
+        case 'd':
+        case 'D':
+          bitsel |= WHOSELECT_DELAY;
+          continue;
+        case 'o':
+        case 'O':
+          bitsel |= WHOSELECT_OPER;
+          continue;
+        case 'x':
+        case 'X':
+          bitsel |= WHOSELECT_EXTRA;
+          if (HasPriv(sptr, PRIV_WHOX))
+           log_write(LS_WHO, L_INFO, LOG_NOSNOTICE, "%#C WHO %s %s", sptr,
+                     (BadPtr(parv[3]) ? parv[1] : parv[3]), parv[2]);
+          continue;
+        case 'n':
+        case 'N':
+          matchsel |= WHO_FIELD_NIC;
+          continue;
+        case 'u':
+        case 'U':
+          matchsel |= WHO_FIELD_UID;
+          continue;
+        case 'h':
+        case 'H':
+          matchsel |= WHO_FIELD_HOS;
+          continue;
+        case 'i':
+        case 'I':
+          matchsel |= WHO_FIELD_NIP;
+          continue;
+        case 's':
+        case 'S':
+          matchsel |= WHO_FIELD_SER;
+          continue;
+        case 'r':
+        case 'R':
+          matchsel |= WHO_FIELD_REN;
+          continue;
+        case 'a':
+        case 'A':
+          matchsel |= WHO_FIELD_ACC;
+          continue;
+      }
+    if (ch == '%')
+      while ((ch = *p++) && (ch != ','))
+      {
+        counter++;
+        switch (ch)
+        {
+          case 'c':
+          case 'C':
+            fields |= WHO_FIELD_CHA;
+            break;
+          case 'd':
+          case 'D':
+            fields |= WHO_FIELD_DIS;
+            break;
+          case 'f':
+          case 'F':
+            fields |= WHO_FIELD_FLA;
+            break;
+          case 'h':
+          case 'H':
+            fields |= WHO_FIELD_HOS;
+            break;
+          case 'i':
+          case 'I':
+            fields |= WHO_FIELD_NIP;
+            break;
+          case 'l':
+          case 'L':
+            fields |= WHO_FIELD_IDL;
+          case 'n':
+          case 'N':
+            fields |= WHO_FIELD_NIC;
+            break;
+          case 'r':
+          case 'R':
+            fields |= WHO_FIELD_REN;
+            break;
+          case 's':
+          case 'S':
+            fields |= WHO_FIELD_SER;
+            break;
+          case 't':
+          case 'T':
+            fields |= WHO_FIELD_QTY;
+            break;
+          case 'u':
+          case 'U':
+            fields |= WHO_FIELD_UID;
+            break;
+          case 'a':
+          case 'A':
+            fields |= WHO_FIELD_ACC;
+            break;
+          case 'o':
+          case 'O':
+            fields |= WHO_FIELD_OPL;
+            break;
+          default:
+            break;
+        }
+      };
+    if (ch)
+      qrt = p;
+  }
+
+  if (!matchsel)
+    matchsel = WHO_FIELD_DEF;
+  if (!fields)
+    counter = 7;
+
+  if (feature_bool(FEAT_HIS_WHO_SERVERNAME) && !IsAnOper(sptr))
+    matchsel &= ~WHO_FIELD_SER;
+
+  if (qrt && (fields & WHO_FIELD_QTY))
+  {
+    p = qrt;
+    if (!((*p > '9') || (*p < '0')))
+      p++;
+    if (!((*p > '9') || (*p < '0')))
+      p++;
+    if (!((*p > '9') || (*p < '0')))
+      p++;
+    *p = '\0';
+  }
+  else
+    qrt = 0;
+
+  /* I'd love to add also a check on the number of matches fields per time */
+  counter = (2048 / (counter + 4));
+  if (mask && (strlen(mask) > 510))
+    mask[510] = '\0';
+  move_marker();
+  commas = (mask && strchr(mask, ','));
+
+  /* First treat mask as a list of plain nicks/channels */
+  if (mask)
+  {
+    strcpy(mymask, mask);
+    for (p = 0, nick = ircd_strtok(&p, mymask, ","); nick;
+        nick = ircd_strtok(&p, 0, ","))
+    {
+      if (IsChannelName(nick) && (chptr = FindChannel(nick)))
+      {
+        isthere = (find_channel_member(sptr, chptr) != 0);
+        if (isthere || SEE_CHANNEL(sptr, chptr, bitsel))
+        {
+          struct Membership* member;
+          for (member = chptr->members; member; member = member->next_member)
+          {
+            acptr = member->user;
+            if ((bitsel & WHOSELECT_OPER) && !SeeOper(sptr,acptr))
+              continue;
+            if ((acptr != sptr)
+                && ((member->status & CHFL_ZOMBIE)
+                    || ((member->status & CHFL_DELAYED)
+                        && !(bitsel & WHOSELECT_DELAY))))
+              continue;
+                       if ((acptr != sptr) && IsInvisibleJoin(member)) 
+                         continue;
+            if (!(isthere || (SEE_USER(sptr, acptr, bitsel))))
+              continue;
+            if (!Process(acptr))        /* This can't be moved before other checks */
+              continue;
+            if (!(isthere || (SHOW_MORE(sptr, counter))))
+              break;
+            do_who(sptr, acptr, chptr, fields, qrt);
+          }
+        }
+      }
+      else
+      {
+        if ((acptr = FindUser(nick)) &&
+            ((!(bitsel & WHOSELECT_OPER)) || SeeOper(sptr,acptr)) &&
+            Process(acptr) && SHOW_MORE(sptr, counter))
+        {
+          do_who(sptr, acptr, 0, fields, qrt);
+        }
+      }
+    }
+  }
+
+  /* If we didn't have any comma in the mask treat it as a
+     real mask and try to match all relevant fields */
+  if (!(commas || (counter < 1)))
+  {
+    struct irc_in_addr imask;
+    int minlen, cset;
+    unsigned char ibits;
+
+    if (mask)
+    {
+      matchcomp(mymask, &minlen, &cset, mask);
+      if (!ipmask_parse(mask, &imask, &ibits))
+        matchsel &= ~WHO_FIELD_NIP;
+      if ((minlen > NICKLEN) || !(cset & NTL_IRCNK))
+        matchsel &= ~WHO_FIELD_NIC;
+      if ((matchsel & WHO_FIELD_SER) &&
+          ((minlen > HOSTLEN) || (!(cset & NTL_IRCHN))
+          || (!markMatchexServer(mymask, minlen))))
+        matchsel &= ~WHO_FIELD_SER;
+      if ((minlen > USERLEN) || !(cset & NTL_IRCUI))
+        matchsel &= ~WHO_FIELD_UID;
+      if ((minlen > HOSTLEN) || !(cset & NTL_IRCHN))
+        matchsel &= ~WHO_FIELD_HOS;
+      if ((minlen > ACCOUNTLEN))
+        matchsel &= ~WHO_FIELD_ACC;
+    }
+
+    /* First of all loop through the clients in common channels */
+    if ((!(counter < 1)) && matchsel) {
+      struct Membership* member;
+      struct Membership* chan;
+      for (chan = cli_user(sptr)->channel; chan; chan = chan->next_channel) {
+        chptr = chan->channel;
+        for (member = chptr->members; member; member = member->next_member)
+        {
+          acptr = member->user;
+          if (!(IsUser(acptr) && Process(acptr)))
+            continue;           /* Now Process() is at the beginning, if we fail
+                                   we'll never have to show this acptr in this query */
+         if ((bitsel & WHOSELECT_OPER) && !SeeOper(sptr,acptr))
+           continue;
+          if ((mask) &&
+              ((!(matchsel & WHO_FIELD_NIC))
+              || matchexec(cli_name(acptr), mymask, minlen))
+              && ((!(matchsel & WHO_FIELD_UID))
+              || matchexec(cli_user(acptr)->username, mymask, minlen))
+              && ((!(matchsel & WHO_FIELD_SER))
+              || (!(HasFlag(cli_user(acptr)->server, FLAG_MAP))))
+              && ((!(matchsel & WHO_FIELD_HOS))
+              || matchexec(cli_user(acptr)->host, mymask, minlen))
+              && ((!(matchsel & WHO_FIELD_HOS))
+             || !HasHiddenHost(acptr)
+             || !IsAnOper(sptr)
+              || matchexec(cli_user(acptr)->realhost, mymask, minlen))
+              && ((!(matchsel & WHO_FIELD_REN))
+              || matchexec(cli_info(acptr), mymask, minlen))
+              && ((!(matchsel & WHO_FIELD_NIP))
+             || (HasHiddenHost(acptr) && !IsAnOper(sptr))
+              || !ipmask_check(&cli_ip(acptr), &imask, ibits))
+              && ((!(matchsel & WHO_FIELD_ACC))
+              || matchexec(cli_user(acptr)->account, mymask, minlen)))
+            continue;
+          if (!SHOW_MORE(sptr, counter))
+            break;
+          do_who(sptr, acptr, chptr, fields, qrt);
+        }
+      }
+    }
+    /* Loop through all clients :-\, if we still have something to match to 
+       and we can show more clients */
+    if ((!(counter < 1)) && matchsel)
+      for (acptr = cli_prev(&me); acptr; acptr = cli_prev(acptr))
+      {
+        if (!(IsUser(acptr) && Process(acptr)))
+          continue;
+       if ((bitsel & WHOSELECT_OPER) && !SeeOper(sptr,acptr))
+         continue;
+        if (!(SEE_USER(sptr, acptr, bitsel)))
+          continue;
+        if ((mask) &&
+            ((!(matchsel & WHO_FIELD_NIC))
+            || matchexec(cli_name(acptr), mymask, minlen))
+            && ((!(matchsel & WHO_FIELD_UID))
+            || matchexec(cli_user(acptr)->username, mymask, minlen))
+            && ((!(matchsel & WHO_FIELD_SER))
+                || (!(HasFlag(cli_user(acptr)->server, FLAG_MAP))))
+            && ((!(matchsel & WHO_FIELD_HOS))
+            || matchexec(cli_user(acptr)->host, mymask, minlen))
+            && ((!(matchsel & WHO_FIELD_HOS))
+           || !HasHiddenHost(acptr)
+           || !IsAnOper(sptr)
+            || matchexec(cli_user(acptr)->realhost, mymask, minlen))
+            && ((!(matchsel & WHO_FIELD_REN))
+            || matchexec(cli_info(acptr), mymask, minlen))
+            && ((!(matchsel & WHO_FIELD_NIP))
+           || (HasHiddenHost(acptr) && !IsAnOper(sptr))
+            || !ipmask_check(&cli_ip(acptr), &imask, ibits))
+            && ((!(matchsel & WHO_FIELD_ACC))
+            || matchexec(cli_user(acptr)->account, mymask, minlen)))
+          continue;
+        if (!SHOW_MORE(sptr, counter))
+          break;
+        do_who(sptr, acptr, 0, fields, qrt);
+      }
+  }
+
+  /* Make a clean mask suitable to be sent in the "end of" */
+  if (mask && (p = strchr(mask, ' ')))
+    *p = '\0';
+  /* Notify the user if we decided that his query was too long */
+  if (counter < 0)
+    send_reply(sptr, ERR_QUERYTOOLONG, BadPtr(mask) ? "*" : mask);
+  send_reply(sptr, RPL_ENDOFWHO, BadPtr(mask) ? "*" : mask);
+
+  return 0;
+}
diff --git a/ircd/m_whois.c b/ircd/m_whois.c
new file mode 100644 (file)
index 0000000..01ee78e
--- /dev/null
@@ -0,0 +1,524 @@
+/*
+ * IRC - Internet Relay Chat, ircd/m_whois.c
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ *                    University of Oulu, Computing Center
+ *
+ * See file AUTHORS in IRC package for additional names of
+ * the programmers.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id: m_whois.c 1667 2006-06-09 02:16:17Z entrope $
+ */
+
+/*
+ * m_functions execute protocol messages on this server:
+ *
+ *    cptr    is always NON-NULL, pointing to a *LOCAL* client
+ *            structure (with an open socket connected!). This
+ *            identifies the physical socket where the message
+ *            originated (or which caused the m_function to be
+ *            executed--some m_functions may call others...).
+ *
+ *    sptr    is the source of the message, defined by the
+ *            prefix part of the message if present. If not
+ *            or prefix not found, then sptr==cptr.
+ *
+ *            (!IsServer(cptr)) => (cptr == sptr), because
+ *            prefixes are taken *only* from servers...
+ *
+ *            (IsServer(cptr))
+ *                    (sptr == cptr) => the message didn't
+ *                    have the prefix.
+ *
+ *                    (sptr != cptr && IsServer(sptr) means
+ *                    the prefix specified servername. (?)
+ *
+ *                    (sptr != cptr && !IsServer(sptr) means
+ *                    that message originated from a remote
+ *                    user (not local).
+ *
+ *            combining
+ *
+ *            (!IsServer(sptr)) means that, sptr can safely
+ *            taken as defining the target structure of the
+ *            message in this server.
+ *
+ *    *Always* true (if 'parse' and others are working correct):
+ *
+ *    1)      sptr->from == cptr  (note: cptr->from == cptr)
+ *
+ *    2)      MyConnect(sptr) <=> sptr == cptr (e.g. sptr
+ *            *cannot* be a local connection, unless it's
+ *            actually cptr!). [MyConnect(x) should probably
+ *            be defined as (x == x->from) --msa ]
+ *
+ *    parc    number of variable parameter strings (if zero,
+ *            parv is allowed to be NULL)
+ *
+ *    parv    a NULL terminated list of parameter pointers,
+ *
+ *                    parv[0], sender (prefix string), if not present
+ *                            this points to an empty string.
+ *                    parv[1]...parv[parc-1]
+ *                            pointers to additional parameters
+ *                    parv[parc] == NULL, *always*
+ *
+ *            note:   it is guaranteed that parv[0]..parv[parc-1] are all
+ *                    non-NULL pointers.
+ */
+#include "config.h"
+
+#include "channel.h"
+#include "client.h"
+#include "hash.h"
+#include "ircd.h"
+#include "ircd_features.h"
+#include "ircd_log.h"
+#include "ircd_reply.h"
+#include "ircd_string.h"
+#include "match.h"
+#include "msg.h"
+#include "numeric.h"
+#include "numnicks.h"
+#include "s_user.h"
+#include "send.h"
+#include "whocmds.h"
+
+/* #include <assert.h> -- Now using assert in ircd_log.h */
+#include <string.h>
+
+/*
+ * 2000-07-01: Isomer
+ *  * Rewritten to make this understandable
+ *  * You can no longer /whois unregistered clients.
+ *  
+ *
+ * General rules:
+ *  /whois nick always shows the nick.
+ *  /whois wild* shows the nick if:
+ *   * they aren't +i and aren't on any channels.
+ *   * they are on a common channel.
+ *   * they aren't +i and are on a public channel. (not +p and not +s)
+ *   * they aren't +i and are on a private channel. (+p but not +s)
+ *  Or to look at it another way (I think):
+ *   * +i users are only shown if your on a common channel.
+ *   * users on +s channels only aren't shown.
+ *
+ *  whois doesn't show what channels a +k client is on, for the reason that
+ *  /whois X or /whois W floods a user off the server. :)
+ *
+ * nb: if the code and this comment disagree, the codes right and I screwed
+ *     up.
+ */
+
+/*
+ * Send whois information for acptr to sptr
+ */
+static void do_whois(struct Client* sptr, struct Client *acptr, int parc)
+{
+  struct Client *a2cptr=0;
+  struct Channel *chptr=0;
+  int mlen;
+  int len;
+  static char buf[512];
+  
+  const struct User* user = cli_user(acptr);
+  const char* name = (!*(cli_name(acptr))) ? "?" : cli_name(acptr);  
+  a2cptr = feature_bool(FEAT_HIS_WHOIS_SERVERNAME) && !IsAnOper(sptr)
+      && sptr != acptr ? &his : user->server;
+  assert(user);
+  send_reply(sptr, RPL_WHOISUSER, name, user->username, user->host,
+                  cli_info(acptr));
+
+  /* Display the channels this user is on. */
+  if (!IsChannelService(acptr) && (!IsNoChan(acptr) || IsAnOper(sptr) || acptr == sptr))
+  {
+    struct Membership* chan;
+    mlen = strlen(cli_name(&me)) + strlen(cli_name(sptr)) + 12 + strlen(name);
+    len = 0;
+    *buf = '\0';
+    for (chan = user->channel; chan; chan = chan->next_channel)
+    {
+       chptr = chan->channel;
+       
+       if (!ShowChannel(sptr, chptr) && !IsAnOper(sptr))
+          continue;
+
+       if (acptr != sptr && IsZombie(chan))
+          continue;
+
+       /* Don't show local channels when HIS is defined, unless it's a
+       * remote WHOIS --ULtimaTe_
+       */
+       if (IsLocalChannel(chptr->chname) && (acptr != sptr) && (parc == 2)
+           && feature_bool(FEAT_HIS_WHOIS_LOCALCHAN) && !IsAnOper(sptr))
+         continue;
+
+       if (len+strlen(chptr->chname) + mlen > BUFSIZE - 5)
+       {
+          send_reply(sptr, SND_EXPLICIT | RPL_WHOISCHANNELS, "%s :%s", name, buf);
+          *buf = '\0';
+          len = 0;
+       }
+       if (IsDeaf(acptr))
+         *(buf + len++) = '-';
+       if (!ShowChannel(sptr, chptr))
+         *(buf + len++) = '*';
+       if (IsDelayedJoin(chan) && (sptr != acptr))
+         *(buf + len++) = '<';
+       else if (IsChanOp(chan))
+         *(buf + len++) = '@';
+       else if (HasVoice(chan))
+         *(buf + len++) = '+';
+       else if (IsZombie(chan))
+         *(buf + len++) = '!';
+       if (len)
+          *(buf + len) = '\0';
+       strcpy(buf + len, chptr->chname);
+       len += strlen(chptr->chname);
+       strcat(buf + len, " ");
+       len++;
+     }
+     if (buf[0] != '\0')
+        send_reply(sptr, RPL_WHOISCHANNELS, name, buf);
+  }
+  if (MyUser(acptr) && IsAnOper(sptr) && *cli_connclass(acptr)) {
+     send_reply(sptr, RPL_WHOISSERVER, name, cli_name(a2cptr),cli_info(a2cptr),"class: ",cli_connclass(acptr));
+  } else {
+     send_reply(sptr, RPL_WHOISSERVER, name, cli_name(a2cptr),cli_info(a2cptr),"","*");
+  }
+
+  if (user)
+  {
+    if (user->away)
+       send_reply(sptr, RPL_AWAY, name, user->away);
+
+    if (SeeOper(sptr,acptr)) {
+          if (IsNetServ(acptr)) {
+          if (HasFlag(acptr, FLAG_SECURITY_SERV)) {
+          send_reply(sptr, RPL_WHOISOPERATOR, name, "is a Network Service");
+          } else {
+          send_reply(sptr, RPL_WHOISOPERATOR, name, "is an illegal Network Service - HACKER!");
+          }
+          } else if (IsHiddenOper(acptr)) {
+       send_reply(sptr, RPL_WHOISOPERATOR, name, "is a hidden IRC Operator");
+          } else {
+          send_reply(sptr, RPL_WHOISOPERATOR, name, "is an IRC Operator");
+          }
+          }
+
+    if (IsAccount(acptr))
+      send_reply(sptr, RPL_WHOISACCOUNT, name, user->account);
+
+    if (HasHiddenHost(acptr) && (IsAnOper(sptr) || acptr == sptr))
+      send_reply(sptr, RPL_WHOISACTUALLY, name, user->username,
+                 user->realhost, ircd_ntoa(&cli_ip(acptr)));
+
+    /* Hint: if your looking to add more flags to a user, eg +h, here's
+     *       probably a good place to add them :)
+     */
+
+    if (IsSSL(acptr))
+      send_reply(sptr, RPL_WHOISSSL, name);
+
+    if (IsWebIRC(acptr)) {
+        /* Unless the real host is not broadcasted we need to check here, whether we know the real host. */
+        if(*cli_webirc(acptr) && (IsOper(sptr) || acptr == sptr))
+            send_reply(sptr, RPL_WHOISWEBIRCLONG, name, cli_webirc(acptr), cli_real_sockhost(acptr), cli_real_sock_ip(acptr));
+        else
+            send_reply(sptr, RPL_WHOISWEBIRC, name);
+    }
+
+    if (MyConnect(acptr) && CanSeeIdletime(sptr, acptr))
+       send_reply(sptr, RPL_WHOISIDLE, name, CurrentTime - user->last,
+                  cli_firsttime(acptr));
+  }
+}
+
+/*
+ * Search and return as many people as matched by the wild 'nick'.
+ * returns the number of people found (or, obviously, 0, if none where
+ * found).
+ */
+static int do_wilds(struct Client* sptr, char *nick, int count, int parc)
+{
+  struct Client *acptr; /* Current client we're considering */
+  struct User *user;   /* the user portion of the client */
+  const char *name;    /* the name of this client */
+  struct Membership* chan; 
+  int invis;           /* does +i apply? */
+  int member;          /* Is this user on any channels? */
+  int showperson;       /* Should we show this person? */
+  int found = 0 ;      /* How many were found? */
+  
+  /* Ech! This is hideous! */
+  for (acptr = GlobalClientList; (acptr = next_client(acptr, nick));
+      acptr = cli_next(acptr))
+  {
+    if (!IsRegistered(acptr)) 
+      continue;
+      
+    if (IsServer(acptr))
+      continue;
+    /*
+     * I'm always last :-) and acptr->next == 0!!
+     *
+     * Isomer: Does this strike anyone else as being a horrible hideous
+     *         hack?
+     */
+    if (IsMe(acptr)) {
+      assert(!cli_next(acptr));
+      break;
+    }
+    
+    /*
+     * 'Rules' established for sending a WHOIS reply:
+     *
+     * - if wildcards are being used don't send a reply if
+     *   the querier isn't any common channels and the
+     *   client in question is invisible.
+     *
+     * - only send replies about common or public channels
+     *   the target user(s) are on;
+     */
+    user = cli_user(acptr);
+    name = (!*(cli_name(acptr))) ? "?" : cli_name(acptr);
+    assert(user);
+
+    invis = (acptr != sptr) && IsInvisible(acptr);
+    member = (user && user->channel) ? 1 : 0;
+    showperson = !invis && !member;
+    
+    /* Should we show this person now? */
+    if (showperson) {
+       found++;
+       do_whois(sptr, acptr, parc);
+       if (count+found>MAX_WHOIS_LINES)
+         return found;
+       continue;
+    }
+    
+    /* Step through the channels this user is on */
+    for (chan = user->channel; chan; chan = chan->next_channel)
+    {
+      struct Channel *chptr = chan->channel;
+
+      /* If this is a public channel, show the person */
+      if (!invis && PubChannel(chptr)) {
+        showperson = 1;
+        break;
+      }
+      
+      /* if this channel is +p and not +s, show them */
+      if (!invis && HiddenChannel(chptr) && !SecretChannel(chptr)) {
+          showperson = 1;
+          break;
+      }
+      
+      member = find_channel_member(sptr, chptr) ? 1 : 0;
+      if (invis && !member)
+        continue;
+
+      /* If sptr isn't really on this channel, skip it */
+      if (IsZombie(chan))
+        continue;
+       
+      /* Is this a common channel? */ 
+      if (member) {
+        showperson = 1;
+        break;
+      }
+    } /* of for (chan in channels) */
+    
+    /* Don't show this person */
+    if (!showperson)
+      continue;
+      
+    do_whois(sptr, acptr, parc);
+    found++;
+    if (count+found>MAX_WHOIS_LINES)
+       return found;  
+  } /* of global client list */
+  
+  return found;
+}
+
+/*
+ * m_whois - generic message handler
+ *
+ * parv[0] = sender prefix
+ * parv[1] = nickname masklist
+ *
+ * or
+ *
+ * parv[1] = target server, or a nickname representing a server to target.
+ * parv[2] = nickname masklist
+ */
+int m_whois(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  char*           nick;
+  char*           tmp;
+  char*           p = 0;
+  int             found = 0;
+  int            total = 0;
+  int             wildscount = 0;
+
+  if (parc < 2)
+  {
+    send_reply(sptr, ERR_NONICKNAMEGIVEN);
+    return 0;
+  }
+
+  if (parc > 2)
+  {
+    /* For convenience: Accept a nickname as first parameter, by replacing
+     * it with the correct servername - as is needed by hunt_server().
+     * This is the secret behind the /whois nick nick trick.
+     */
+    if (feature_int(FEAT_HIS_REMOTE))
+    {
+      /* If remote queries are disabled, then use the *second* parameter of
+       * of whois, so /whois nick nick still works.
+       */
+      if (!IsAnOper(sptr))
+      {
+        if (!FindUser(parv[2]))
+        {
+          send_reply(sptr, ERR_NOSUCHNICK, parv[2]);
+          send_reply(sptr, RPL_ENDOFWHOIS, parv[2]);
+          return 0;
+        }
+        parv[1] = parv[2];
+      }
+    }
+
+    if (hunt_server_cmd(sptr, CMD_WHOIS, cptr, 0, "%C :%s", 1, parc, parv) !=
+       HUNTED_ISME)
+    return 0;
+    
+    parv[1] = parv[2];
+  }
+
+  for (tmp = parv[1]; (nick = ircd_strtok(&p, tmp, ",")); tmp = 0)
+  {
+    int wilds;
+
+    found = 0;
+    
+    collapse(nick);
+    
+    wilds = (strchr(nick, '?') || strchr(nick, '*'));
+    if (!wilds) {
+      struct Client *acptr = 0;
+      /* No wildcards */
+      acptr = FindUser(nick);
+      if (acptr && !IsServer(acptr)) {
+        do_whois(sptr, acptr, parc);
+        found = 1;
+      }
+    }
+    else /* wilds */
+    {
+      if (++wildscount > 3) {
+        send_reply(sptr, ERR_QUERYTOOLONG, parv[1]);
+        break;
+      }
+      found=do_wilds(sptr, nick, total, parc);
+    }
+
+    if (!found)
+      send_reply(sptr, ERR_NOSUCHNICK, nick);
+    total+=found;
+    if (total >= MAX_WHOIS_LINES) {
+      send_reply(sptr, ERR_QUERYTOOLONG, parv[1]);
+      break;
+    }
+    if (p)
+      p[-1] = ',';
+  } /* of tokenised parm[1] */
+  send_reply(sptr, RPL_ENDOFWHOIS, parv[1]);
+
+  return 0;
+}
+
+/*
+ * ms_whois - server message handler
+ *
+ * parv[0] = sender prefix
+ * parv[1] = nickname masklist
+ *
+ * or
+ *
+ * parv[1] = target server, or a nickname representing a server to target.
+ * parv[2] = nickname masklist
+ */
+int ms_whois(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  char*           nick;
+  char*           tmp;
+  char*           p = 0;
+  int             found = 0;
+  int            total = 0;
+
+  if (parc < 2)
+  {
+    send_reply(sptr, ERR_NONICKNAMEGIVEN);
+    return 0;
+  }
+
+  if (parc > 2)
+  {
+    if (hunt_server_cmd(sptr, CMD_WHOIS, cptr, 0, "%C :%s", 1, parc, parv) !=
+        HUNTED_ISME)
+      return 0;
+    parv[1] = parv[2];
+  }
+
+  total = 0;
+  
+  for (tmp = parv[1]; (nick = ircd_strtok(&p, tmp, ",")); tmp = 0)
+  {
+    struct Client *acptr = 0;
+
+    found = 0;
+    
+    collapse(nick);
+    
+
+    acptr = FindUser(nick);
+    if (acptr && !IsServer(acptr)) {
+      found++;
+      do_whois(sptr, acptr, parc);
+    }
+
+    if (!found)
+      send_reply(sptr, ERR_NOSUCHNICK, nick);
+      
+    total+=found;
+      
+    if (total >= MAX_WHOIS_LINES) {
+      send_reply(sptr, ERR_QUERYTOOLONG, parv[1]);
+      break;
+    }
+      
+    if (p)
+      p[-1] = ',';
+  } /* of tokenised parm[1] */
+  send_reply(sptr, RPL_ENDOFWHOIS, parv[1]);
+
+  return 0;
+}
+
diff --git a/ircd/m_whowas.c b/ircd/m_whowas.c
new file mode 100644 (file)
index 0000000..72594da
--- /dev/null
@@ -0,0 +1,164 @@
+/*
+ * IRC - Internet Relay Chat, ircd/m_whowas.c
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ *                    University of Oulu, Computing Center
+ *
+ * See file AUTHORS in IRC package for additional names of
+ * the programmers.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id: m_whowas.c 1599 2006-01-01 04:39:07Z entrope $
+ */
+
+/*
+ * m_functions execute protocol messages on this server:
+ *
+ *    cptr    is always NON-NULL, pointing to a *LOCAL* client
+ *            structure (with an open socket connected!). This
+ *            identifies the physical socket where the message
+ *            originated (or which caused the m_function to be
+ *            executed--some m_functions may call others...).
+ *
+ *    sptr    is the source of the message, defined by the
+ *            prefix part of the message if present. If not
+ *            or prefix not found, then sptr==cptr.
+ *
+ *            (!IsServer(cptr)) => (cptr == sptr), because
+ *            prefixes are taken *only* from servers...
+ *
+ *            (IsServer(cptr))
+ *                    (sptr == cptr) => the message didn't
+ *                    have the prefix.
+ *
+ *                    (sptr != cptr && IsServer(sptr) means
+ *                    the prefix specified servername. (?)
+ *
+ *                    (sptr != cptr && !IsServer(sptr) means
+ *                    that message originated from a remote
+ *                    user (not local).
+ *
+ *            combining
+ *
+ *            (!IsServer(sptr)) means that, sptr can safely
+ *            taken as defining the target structure of the
+ *            message in this server.
+ *
+ *    *Always* true (if 'parse' and others are working correct):
+ *
+ *    1)      sptr->from == cptr  (note: cptr->from == cptr)
+ *
+ *    2)      MyConnect(sptr) <=> sptr == cptr (e.g. sptr
+ *            *cannot* be a local connection, unless it's
+ *            actually cptr!). [MyConnect(x) should probably
+ *            be defined as (x == x->from) --msa ]
+ *
+ *    parc    number of variable parameter strings (if zero,
+ *            parv is allowed to be NULL)
+ *
+ *    parv    a NULL terminated list of parameter pointers,
+ *
+ *                    parv[0], sender (prefix string), if not present
+ *                            this points to an empty string.
+ *                    parv[1]...parv[parc-1]
+ *                            pointers to additional parameters
+ *                    parv[parc] == NULL, *always*
+ *
+ *            note:   it is guaranteed that parv[0]..parv[parc-1] are all
+ *                    non-NULL pointers.
+ */
+#include "config.h"
+
+#include "client.h"
+#include "hash.h"
+#include "ircd.h"
+#include "ircd_features.h"
+#include "ircd_log.h"
+#include "ircd_reply.h"
+#include "ircd_string.h"
+#include "msg.h"
+#include "numeric.h"
+#include "numnicks.h"
+#include "s_user.h"
+#include "s_misc.h"
+#include "send.h"
+#include "whowas.h"
+
+/* #include <assert.h> -- Now using assert in ircd_log.h */
+#include <stdlib.h>
+
+/*
+ * m_whowas - generic message handler
+ *
+ * parv[0] = sender prefix
+ * parv[1] = nickname queried
+ * parv[2] = maximum returned items (optional, default is unlimited)
+ * parv[3] = remote server target (Opers only, max returned items 20)
+ */
+int m_whowas(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  struct Whowas *temp;
+  int cur = 0;
+  int max = -1, found = 0;
+  char *p, *nick, *s;
+
+  if (parc < 2)
+  {
+    send_reply(sptr, ERR_NONICKNAMEGIVEN);
+    return 0;
+  }
+  if (parc > 2)
+    max = atoi(parv[2]);
+  if (parc > 3)
+    if (hunt_server_cmd(sptr, CMD_WHOWAS, cptr, 1, "%s %s :%C", 3, parc, parv))
+      return 0;
+
+  parv[1] = canonize(parv[1]);
+  if (!MyConnect(sptr) && (max > 20))
+    max = 20;                   /* Set max replies at 20 */
+  for (s = parv[1]; (nick = ircd_strtok(&p, s, ",")); s = 0)
+  {
+    /* Search through bucket, finding all nicknames that match */
+    found = 0;
+    for (temp = whowashash[hash_whowas_name(nick)]; temp; temp = temp->hnext)
+    {
+      if (0 == ircd_strcmp(nick, temp->name))
+      {
+       send_reply(sptr, RPL_WHOWASUSER, temp->name, temp->username,
+                  temp->hostname, temp->realname);
+        if (IsAnOper(sptr) && temp->realhost)
+          send_reply(sptr, RPL_WHOISACTUALLY, temp->name, temp->username, temp->realhost, "<untracked>");
+        send_reply(sptr, RPL_WHOISSERVER, temp->name,
+                   (feature_bool(FEAT_HIS_WHOIS_SERVERNAME) && !IsOper(sptr)) ?
+                     feature_str(FEAT_HIS_SERVERNAME) :
+                     temp->servername,
+                  myctime(temp->logoff));
+        if (temp->away)
+         send_reply(sptr, RPL_AWAY, temp->name, temp->away);
+        cur++;
+        found++;
+      }
+      if (max >= 0 && cur >= max)
+        break;
+    }
+    if (!found)
+      send_reply(sptr, ERR_WASNOSUCHNICK, nick);
+    /* To keep parv[1] intact for ENDOFWHOWAS */
+    if (p)
+      p[-1] = ',';
+  }
+  send_reply(sptr, RPL_ENDOFWHOWAS, parv[1]);
+  return 0;
+}
diff --git a/ircd/match.c b/ircd/match.c
new file mode 100644 (file)
index 0000000..c9a4aef
--- /dev/null
@@ -0,0 +1,864 @@
+/*
+ * IRC - Internet Relay Chat, common/match.c
+ * Copyright (C) 1990 Jarkko Oikarinen
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+/** @file
+ * @brief Functions to match strings against IRC mask strings.
+ * @version $Id: match.c 1891 2008-11-18 02:30:15Z entrope $
+ */
+#include "config.h"
+
+#include "match.h"
+#include "ircd_chattr.h"
+#include "ircd_string.h"
+#include "ircd_snprintf.h"
+
+/*
+ * mmatch()
+ *
+ * Written by Run (carlo@runaway.xs4all.nl), 25-10-96
+ *
+ *
+ * From: Carlo Wood <carlo@runaway.xs4all.nl>
+ * Message-Id: <199609021026.MAA02393@runaway.xs4all.nl>
+ * Subject: [C-Com] Analysis for `mmatch' (was: gline4 problem)
+ * To: coder-com@mail.undernet.org (coder committee)
+ * Date: Mon, 2 Sep 1996 12:26:01 +0200 (MET DST)
+ *
+ * We need a new function `mmatch(const char *old_mask, const char *new_mask)'
+ * which returns `true' likewise the current `match' (start with copying it),
+ * but which treats '*' and '?' in `new_mask' differently (not "\*" and "\?" !)
+ * as follows:  a '*' in `new_mask' does not match a '?' in `old_mask' and
+ * a '?' in `new_mask' does not match a '\?' in `old_mask'.
+ * And ofcourse... a '*' in `new_mask' does not match a '\*' in `old_mask'...
+ * And last but not least, '\?' and '\*' in `new_mask' now become one character.
+ */
+
+/** Compares one mask against another.
+ * One wildcard mask may be said to be a superset of another if the
+ * set of strings matched by the first is a proper superset of the set
+ * of strings matched by the second.  In practical terms, this means
+ * that the second is made redundant by the first.
+ *
+ * The logic for this test is similar to that in match(), but a
+ * backslash in old_mask only matches a backslash in new_mask (and
+ * requires the next character to match exactly), and -- after
+ * contiguous runs of wildcards are logically collapsed -- a '?' in
+ * old_mask does not match a '*' in new_mask.
+ *
+ * @param[in] old_mask One wildcard mask.
+ * @param[in] new_mask Another wildcard mask.
+ * @return Zero if \a old_mask is a superset of \a new_mask, non-zero otherwise.
+ */
+int mmatch(const char *old_mask, const char *new_mask)
+{
+  const char *m = old_mask;
+  const char *n = new_mask;
+  const char *ma = m;
+  const char *na = n;
+  int wild = 0;
+  int mq = 0, nq = 0;
+
+  while (1)
+  {
+    if (*m == '*')
+    {
+      while (*m == '*')
+        m++;
+      wild = 1;
+      ma = m;
+      na = n;
+    }
+
+    if (!*m)
+    {
+      if (!*n)
+        return 0;
+      for (m--; (m > old_mask) && (*m == '?'); m--)
+        ;
+      if ((*m == '*') && (m > old_mask) && (m[-1] != '\\'))
+        return 0;
+      if (!wild)
+        return 1;
+      m = ma;
+
+      /* Added to `mmatch' : Because '\?' and '\*' now is one character: */
+      if ((*na == '\\') && ((na[1] == '*') || (na[1] == '?')))
+        ++na;
+
+      n = ++na;
+    }
+    else if (!*n)
+    {
+      while (*m == '*')
+        m++;
+      return (*m != 0);
+    }
+    if ((*m == '\\') && ((m[1] == '*') || (m[1] == '?')))
+    {
+      m++;
+      mq = 1;
+    }
+    else
+      mq = 0;
+
+    /* Added to `mmatch' : Because '\?' and '\*' now is one character: */
+    if ((*n == '\\') && ((n[1] == '*') || (n[1] == '?')))
+    {
+      n++;
+      nq = 1;
+    }
+    else
+      nq = 0;
+
+/*
+ * This `if' has been changed compared to match() to do the following:
+ * Match when:
+ *   old (m)         new (n)         boolean expression
+ *    *               any             (*m == '*' && !mq) ||
+ *    ?               any except '*'  (*m == '?' && !mq && (*n != '*' || nq)) ||
+ * any except * or ?  same as m       (!((*m == '*' || *m == '?') && !mq) &&
+ *                                      ToLower(*m) == ToLower(*n) &&
+ *                                        !((mq && !nq) || (!mq && nq)))
+ *
+ * Here `any' also includes \* and \? !
+ *
+ * After reworking the boolean expressions, we get:
+ * (Optimized to use boolean short-circuits, with most frequently occurring
+ *  cases upfront (which took 2 hours!)).
+ */
+    if ((*m == '*' && !mq) ||
+        ((!mq || nq) && ToLower(*m) == ToLower(*n)) ||
+        (*m == '?' && !mq && (*n != '*' || nq)))
+    {
+      if (*m)
+        m++;
+      if (*n)
+        n++;
+    }
+    else
+    {
+      if (!wild)
+        return 1;
+      m = ma;
+
+      /* Added to `mmatch' : Because '\?' and '\*' now is one character: */
+      if ((*na == '\\') && ((na[1] == '*') || (na[1] == '?')))
+        ++na;
+
+      n = ++na;
+    }
+  }
+}
+
+/*
+ * Compare if a given string (name) matches the given
+ * mask (which can contain wild cards: '*' - match any
+ * number of chars, '?' - match any single character.
+ *
+ * return  0, if match
+ *         1, if no match
+ *
+ *  Originally by Douglas A Lewis (dalewis@acsu.buffalo.edu)
+ *  Rewritten by Timothy Vogelsang (netski), net@astrolink.org
+ */
+
+/** Check a string against a mask.
+ * This test checks using traditional IRC wildcards only: '*' means
+ * match zero or more characters of any type; '?' means match exactly
+ * one character of any type.  A backslash escapes the next character
+ * so that a wildcard may be matched exactly.
+ * @param[in] mask Wildcard-containing mask.
+ * @param[in] name String to check against \a mask.
+ * @return Zero if \a mask matches \a name, non-zero if no match.
+ */
+int match(const char *mask, const char *name)
+{
+  const char *m = mask, *n = name;
+  const char *m_tmp = mask, *n_tmp = name;
+  int star_p;
+
+  for (;;) switch (*m) {
+  case '\0':
+    if (!*n)
+      return 0;
+  backtrack:
+    if (m_tmp == mask)
+      return 1;
+    m = m_tmp;
+    n = ++n_tmp;
+    if (*n == '\0')
+      return 1;
+    break;
+  case '\\':
+    m++;
+    /* allow escaping to force capitalization */
+    if (*m++ != *n++)
+      goto backtrack;
+    break;
+  case '*': case '?':
+    for (star_p = 0; ; m++) {
+      if (*m == '*')
+        star_p = 1;
+      else if (*m == '?') {
+        if (!*n++)
+          goto backtrack;
+      } else break;
+    }
+    if (star_p) {
+      if (!*m)
+        return 0;
+      else if (*m == '\\') {
+        m_tmp = ++m;
+        if (!*m)
+          return 1;
+        for (n_tmp = n; *n && *n != *m; n++) ;
+      } else {
+        m_tmp = m;
+        for (n_tmp = n; *n && ToLower(*n) != ToLower(*m); n++) ;
+      }
+    }
+    /* and fall through */
+  default:
+    if (!*n)
+      return *m != '\0';
+    if (ToLower(*m) != ToLower(*n))
+      goto backtrack;
+    m++;
+    n++;
+    break;
+  }
+}
+
+/*
+ * collapse()
+ * Collapse a pattern string into minimal components.
+ * This particular version is "in place", so that it changes the pattern
+ * which is to be reduced to a "minimal" size.
+ *
+ * (C) Carlo Wood - 6 Oct 1998
+ * Speedup rewrite by Andrea Cocito, December 1998.
+ * Note that this new optimized algorithm can *only* work in place.
+ */
+
+/** Collapse a mask string to remove redundancies.
+ * Specifically, it replaces a sequence of '*' followed by additional
+ * '*' or '?' with the same number of '?'s as the input, followed by
+ * one '*'.  This minimizes useless backtracking when matching later.
+ * @param[in,out] mask Mask string to collapse.
+ * @return Pointer to the start of the string.
+ */
+char *collapse(char *mask)
+{
+  int star = 0;
+  char *m = mask;
+  char *b;
+
+  if (m)
+  {
+    do
+    {
+      if ((*m == '*') && ((m[1] == '*') || (m[1] == '?')))
+      {
+        b = m;
+        do
+        {
+          if (*m == '*')
+            star = 1;
+          else
+          {
+            if (star && (*m != '?'))
+            {
+              *b++ = '*';
+              star = 0;
+            };
+            *b++ = *m;
+            if ((*m == '\\') && ((m[1] == '*') || (m[1] == '?')))
+              *b++ = *++m;
+          };
+        }
+        while (*m++);
+        break;
+      }
+      else
+      {
+        if ((*m == '\\') && ((m[1] == '*') || (m[1] == '?')))
+          m++;
+      };
+    }
+    while (*m++);
+  };
+  return mask;
+}
+
+/*
+ ***************** Nemesi's matchcomp() / matchexec() **************
+ */
+
+/** @page compiledmasks Compiled Masks
+ * These functions allow the use of "compiled" masks, you compile a mask
+ * by means of matchcomp() that gets the plain text mask as input and writes
+ * its result in the memory locations addressed by the 3 parameters:
+ * - *cmask will contain the text of the compiled mask
+ * - *minlen will contain the length of the shortest string that can match 
+ *   the mask
+ * - *charset will contain the minimal set of chars needed to match the mask
+ * You can pass NULL as *charset and it will be simply not returned, but you
+ * MUST pass valid pointers for *minlen and *cmask (which must be big enough 
+ * to contain the compiled mask text that is in the worst case as long as the 
+ * text of the mask itself in plaintext format) and the return value of 
+ * matchcomp() will be the number of chars actually written there (excluded 
+ * the trailing zero). cmask can be == mask, matchcomp() can work in place.
+ * The {cmask, minlen} couple of values make the real compiled mask and
+ * need to be passed to the functions that use the compiled mask, if you pass
+ * the wrong minlen or something wrong in cmask to one of these expect a
+ * coredump. This means that when you record a compiled mask you must store
+ * *both* these values.
+ * Once compiled the mask can be used to match a string by means of 
+ * matchexec(), it can be printed back to human-readable format by means
+ * of sprintmatch() or it can be compared to another compiled mask by means
+ * of mmexec() that will tell if it completely overrides that mask (a lot like
+ * what mmatch() does for plain text masks).
+ * You can gain a lot of speed in many situations avoiding to matchexec() when:
+ * - The maximum length of the field you are about to match() the mask to is
+ *   shorter than minlen, in example when matching abc*def*ghil with a nick:
+ *   It just cannot match since a nick is at most 9 chars long and the mask
+ *   needs at least 10 chars (10 will be the value returned in minlen).
+ * - The charset allowed for the field you are about to match to doesn't
+ *   "contain" the charset returned by matchcomp(), in example when you
+ *   have *.* as mask it makes no sense to try to match it against a nick
+ *   because, again, a nick can't contain a '.', you can check this with
+ *   a simple (charset & NTL_IRCNK) in this case.
+ * - As a special case, since compiled masks are forced to lowercase,
+ *   it would make no sense to use the NTL_LOWER and NTL_UPPER on a compiled
+ *   mask, thus they are reused as follows: if the NTL_LOWER bit of charset
+ *   is set it means that the mask contains only non-wilds chars (i.e. you can
+ *   use strCasecmp() to match it or a direct hash lookup), if the NTL_UPPER
+ *   bit is set it means that it contains only wild chars (and you can
+ *   match it with strlen(field)>=minlen).
+ * Do these optimizations ONLY when the data you are about to pass to
+ * matchexec() are *known* to be invalid in advance, using strChattr() 
+ * or strlen() on the text would be slower than calling matchexec() directly
+ * and let it fail.
+ * Internally a compiled mask contain in the *cmask area the text of
+ * the plain text form of the mask itself with applied the following hacks:
+ * - All characters are forced to lowercase (so that uppercase letters and
+ *   specifically the symbols 'A' and 'Z' are reserved for special use)
+ * - All non-escaped stars '*' are replaced by the letter 'Z'
+ * - All non-escaped question marks '?' are replaced by the letter 'A' 
+ * - All escape characters are removed, the wilds escaped by them are
+ *   then passed by without the escape since they don't collide anymore
+ *   with the real wilds (encoded as A/Z) 
+ * - Finally the part of the mask that follows the last asterisk is
+ *   reversed (byte order mirroring) and moved right after the first
+ *   asterisk.
+ * After all this a mask like:   Head*CHUNK1*chu\*nK2*ch??k3*TaIl 
+ *               .... becomes:   headZliatZchunk1Zchu*nk2ZchAAk3
+ * This can still be printed on a console, more or less understood by an
+ * human and handled with the usual str*() library functions.
+ * When you store somewhere the compiled mask you can avoid storing the
+ * textform of it since it can be "decompiled" by means of sprintmatch(),
+ * but at that time the following things are changed in the mask:
+ * - All chars have been forced to lowercase.
+ * - The mask is collapsed.
+ * The balance point of using compiled masks in terms of CPU is when you expect
+ * to use matchexec() instead of match() at least 20 times on the same mask
+ * or when you expect to use mmexec() instead of mmatch() 3 times.
+ */
+
+/** Compile a mask for faster matching.
+ * See also @ref compiledmasks.
+ * @param[out] cmask Output buffer for compiled mask.
+ * @param[out] minlen Minimum length of matching strings.
+ * @param[out] charset Character attributes used in compiled mask.
+ * @param[out] mask Input mask.
+ * @return Length of compiled mask, not including NUL terminator.
+ */
+int matchcomp(char *cmask, int *minlen, int *charset, const char *mask)
+{
+  const char *m = mask;
+  char *b = cmask;
+  char *fs = 0;
+  char *ls = 0;
+  char *x1, *x2;
+  int l1, l2, lmin, loop, sign;
+  int star = 0;
+  int cnt = 0;
+  char ch;
+  int chset = ~0;
+  int chset2 = (NTL_LOWER | NTL_UPPER);
+
+  if (m)
+    while ((ch = *m++))
+      switch (ch)
+      {
+        case '*':
+          star = 1;
+          break;
+        case '?':
+          cnt++;
+          *b++ = 'A';
+          chset2 &= ~NTL_LOWER;
+          break;
+        case '\\':
+          if ((*m == '?') || (*m == '*'))
+            ch = *m++;
+        default:
+          if (star)
+          {
+            ls = b;
+            fs = fs ? fs : b;
+            *b++ = 'Z';
+            chset2 &= ~NTL_LOWER;
+            star = 0;
+          };
+          cnt++;
+          *b = ToLower(ch);
+          chset &= IRCD_CharAttrTab[*b++ - CHAR_MIN];
+          chset2 &= ~NTL_UPPER;
+      };
+
+  if (charset)
+    *charset = (chset | chset2);
+
+  if (star)
+  {
+    ls = b;
+    fs = (fs ? fs : b);
+    *b++ = 'Z';
+  };
+
+  if (ls)
+  {
+    for (x1 = ls + 1, x2 = (b - 1); x1 < x2; x1++, x2--)
+    {
+      ch = *x1;
+      *x1 = *x2;
+      *x2 = ch;
+    };
+    l1 = (ls - fs);
+    l2 = (b - ls);
+    x1 = fs;
+    while ((lmin = (l1 < l2) ? l1 : l2))
+    {
+      x2 = x1 + l1;
+      for (loop = 0; loop < lmin; loop++)
+      {
+        ch = x1[loop];
+        x1[loop] = x2[loop];
+        x2[loop] = ch;
+      };
+      x1 += lmin;
+      sign = l1 - l2;
+      l1 -= (sign < 0) ? 0 : lmin;
+      l2 -= (sign > 0) ? 0 : lmin;
+    };
+  };
+
+  *b = '\0';
+  *minlen = cnt;
+  return (b - cmask);
+
+}
+
+/** Compare a string to a compiled mask.
+ * If \a cmask is not from matchcomp(), or if \a minlen is not the value
+ * passed out of matchcomp(), this may core.
+ * See also @ref compiledmasks.
+ * @param[in] string String to test.
+ * @param[in] cmask Compiled mask string.
+ * @param[in] minlen Minimum length of strings that match \a cmask.
+ * @return Zero if the string matches, non-zero otherwise.
+ */
+int matchexec(const char *string, const char *cmask, int minlen)
+{
+  const char *s = string - 1;
+  const char *b = cmask - 1;
+  int trash;
+  const char *bb, *bs;
+  char ch;
+
+tryhead:
+  while ((ToLower(*++s) == *++b) && *s);
+  if (!*s)
+    return ((*b != '\0') && ((*b++ != 'Z') || (*b != '\0')));
+  if (*b != 'Z')
+  {
+    if (*b == 'A')
+      goto tryhead;
+    return 1;
+  };
+
+  bs = s;
+  while (*++s);
+
+  if ((trash = (s - string - minlen)) < 0)
+    return 2;
+
+trytail:
+  while ((ToLower(*--s) == *++b) && *b && (ToLower(*--s) == *++b) && *b
+      && (ToLower(*--s) == *++b) && *b && (ToLower(*--s) == *++b) && *b);
+  if (*b != 'Z')
+  {
+    if (*b == 'A')
+      goto trytail;
+    return (*b != '\0');
+  };
+
+  s = --bs;
+  bb = b;
+
+  while ((ch = *++b))
+  {
+    while ((ToLower(*++s) != ch))
+      if (--trash < 0)
+        return 4;
+    bs = s;
+
+trychunk:
+    while ((ToLower(*++s) == *++b) && *b);
+    if (!*b)
+      return 0;
+    if (*b == 'Z')
+    {
+      bs = --s;
+      bb = b;
+      continue;
+    };
+    if (*b == 'A')
+      goto trychunk;
+
+    b = bb;
+    s = bs;
+    if (--trash < 0)
+      return 5;
+  };
+
+  return 0;
+}
+
+/*
+ * matchdecomp()
+ * Prints the human readable version of *cmask into *mask, (decompiles
+ * cmask).
+ * The area pointed by *mask MUST be big enough (the mask might be up to
+ * twice the size of its compiled form if it's made all of \? or \*, and
+ * this function can NOT work in place since it might inflate the mask)
+ * The printed mask is not identical to the one that was compiled to cmask,
+ * in fact it is 1) forced to all lowercase, 2) collapsed, both things
+ * are supposed to NOT change it's meaning.
+ * It returns the number of chars actually written to *mask;
+ */
+
+/** Decompile a compiled mask into printable form.
+ * See also @ref compiledmasks.
+ * @param[out] mask Output mask buffer.
+ * @param[in] cmask Compiled mask.
+ * @return Number of characters written to \a mask.
+ */
+int matchdecomp(char *mask, const char *cmask)
+{
+  char *rtb = mask;
+  const char *rcm = cmask;
+  const char *begtail, *endtail;
+
+  if (rtb ==0)
+    return (-1);
+
+  if (rcm == 0)
+    return (-2);
+
+  for (; (*rcm != 'Z'); rcm++, rtb++)
+  {
+    if ((*rcm == '?') || (*rcm == '*'))
+      *rtb++ = '\\';
+    if (!((*rtb = ((*rcm == 'A') ? '?' : *rcm))))
+      return (rtb - mask);
+  };
+
+  begtail = rcm++;
+  *rtb++ = '*';
+
+  while (*rcm && (*rcm != 'Z'))
+    rcm++;
+
+  endtail = rcm;
+
+  if (*rcm)
+  {
+    while (*++rcm)
+      switch (*rcm)
+      {
+        case 'A':
+          *rtb++ = '?';
+          break;
+        case 'Z':
+          *rtb++ = '*';
+          break;
+        case '*':
+        case '?':
+          *rtb++ = '\\';
+        default:
+          *rtb++ = *rcm;
+      };
+    *rtb++ = '*';
+  };
+
+  for (rcm = endtail; (--rcm) > begtail; *rtb++ = ((*rcm == 'A') ? '?' : *rcm))
+    if ((*rcm == '?') || (*rcm == '*'))
+      *rtb++ = '\\';
+
+  *rtb = '\0';
+  return (rtb - mask);
+}
+
+/*
+ * mmexec()
+ * Checks if a wider compiled mask (wcm/wminlen) completely overrides
+ * a more restrict one (rcm/rminlen), basically what mmatch() does for
+ * non-compiled masks, returns 0 if the override is true (like mmatch()).
+ * "the wider overrides the restrict" means that any string that matches
+ * the restrict one _will_ also match the wider one, always. 
+ * In this we behave differently from mmatch() because in example we return 
+ * true for " a?*cd overrides a*bcd " for which the override happens for how 
+ * we literally defined it, here mmatch() would have returned false.
+ * The original concepts and the base algorithm are copied from mmatch() 
+ * written by Run (Carlo Wood), this function is written by
+ * Nemesi (Andrea Cocito)
+ */
+/** Tests for a superset relationship between compiled masks.  This
+ * function does for compiled masks what mmatch() is does for normal
+ * masks.
+ * See also @ref compiledmasks.
+ * @param[in] wcm Compiled mask believed to be wider.
+ * @param[in] wminlen Minimum match length for \a wcm.
+ * @param[in] rcm Compiled mask believed to be restricted.
+ * @param[in] rminlen Minimum match length for \a rcm.
+ * @return Zero if \a wcm is a superset of \a rcm, non-zero if not.
+ */
+int mmexec(const char *wcm, int wminlen, const char *rcm, int rminlen)
+{
+  const char *w, *r, *br, *bw, *rx, *rz;
+  int eat, trash;
+
+  /* First of all rm must have enough non-stars to 'contain' wm */
+  if ((trash = rminlen - wminlen) < 0)
+    return 1;
+  w = wcm;
+  r = rcm;
+  eat = 0;
+
+  /* Let's start the game, remember that '*' is mapped to 'Z', '?'
+     is mapped to 'A' and that head?*??*?chunk*???*tail becomes
+     headAAAAZliatAAAZchunk for compiled masks */
+
+  /* Match the head of wm with the head of rm */
+  for (; (*r) && (*r != 'Z') && ((*w == *r) || (*w == 'A')); r++, w++);
+  if (*r == 'Z')
+    while (*w == 'A')           /* Eat extra '?' before '*' in wm if got '*' in rm */
+      w++, eat++;
+  if (*w != 'Z')                /* head1<any>.. can't match head2<any>.. */
+    return ((*w) || (*r)) ? 1 : 0;      /* and head<nul> matches only head<nul> */
+  if (!*++w)
+    return 0;                   /* headZ<nul> matches head<anything>    */
+
+  /* Does rm have any stars in it ? let's check */
+  for (rx = r; *r && (*r != 'Z'); r++);
+  if (!*r)
+  {
+    /* rm has no stars and thus isn't a mask but it's just a flat
+       string: special handling occurs here, note that eat must be 0 here */
+
+    /* match the tail */
+    if (*w != 'Z')
+    {
+      for (; r--, (*w) && ((*w == *r) || (*w == 'A')); w++);
+      if (*w != 'Z')            /* headZliat1<any> fails on head<any>2tail  */
+        return (*w) ? 1 : 0;    /* but headZliat<nul> matches head<any>tail */
+    }
+
+    /* match the chunks */
+    while (1)
+    {                           /* This loop can't break but only return   */
+
+      for (bw = w++; (*w != *rx); rx++) /* Seek the 1st char of the chunk */
+        if (--trash < 0)        /* See if we can trash one more char of rm */
+          return 1;             /* If not we can only fail of course       */
+      for (r = ++rx, w++; (*w) && ((*w == *r) || (*w == 'A')); r++, w++);
+      if (!*w)                  /* Did last loop match the rest of chunk ? */
+        return 0;               /* ... Yes, end of wm, matched !           */
+      if (*w != 'Z')
+      {                         /* ... No, hit non-star                    */
+        w = bw;                 /* Rollback at beginning of chunk          */
+        if (--trash < 0)        /* Trashed the char where this try started */
+          return 1;             /* if we can't trash more chars fail       */
+      }
+      else
+      {
+        rx = r;                 /* Successfully matched a chunk, move rx   */
+      }                 /* and go on with the next one             */
+    }
+  }
+
+  /* rm has at least one '*' and thus is a 'real' mask */
+  rz = r++;                     /* rx = unused of head, rz = beg-tail */
+
+  /* Match the tail of wm (if any) against the tail of rm */
+  if (*w != 'Z')
+  {
+    for (; (*w) && (*r != 'Z') && ((*w == *r) || (*w == 'A')); w++, r++);
+    if (*r == 'Z')              /* extra '?' before tail are fluff, just flush 'em */
+      while (*w == 'A')
+        w++;
+    if (*w != 'Z')              /* We aren't matching a chunk, can't rollback      */
+      return (*w) ? 1 : 0;
+  }
+
+  /* Match the chunks of wm against what remains of the head of rm */
+  while (1)
+  {
+    bw = w;
+    for (bw++; (rx < rz) && (*bw != *rx); rx++) /* Seek the first           */
+      if (--trash < 0)          /* waste some trash reserve */
+        return 1;
+    if (!(rx < rz))             /* head finished            */
+      break;
+    for (bw++, (br = ++rx);
+        (br < rz) && (*bw) && ((*bw == *br) || (*bw == 'A')); br++, bw++);
+    if (!(br < rz))             /* Note that we didn't use any 'eat' char yet, if  */
+      while (*bw == 'A')        /* there were eat-en chars the head would be over  */
+        bw++, eat++;            /* Happens only at end of head, and eat is still 0 */
+    if (!*bw)
+      return 0;
+    if (*bw != 'Z')
+    {
+      eat = 0;
+      if (!(br < rz))
+      {                         /* If we failed because we got the end of head */
+        trash -= (br - rx);     /* it makes no sense to rollback, just trash   */
+        if (--trash < 0)        /* all the rest of the head which isn't long   */
+          return 1;             /* enough for this chunk and go out of this    */
+        break;                  /* loop, then we try with the chunks of rm     */
+      };
+      if (--trash < 0)
+        return 1;
+    }
+    else
+    {
+      w = bw;
+      rx = br;
+    }
+  }
+
+  /* Match the unused chunks of wm against the chunks of rm */
+  rx = r;
+  for (; *r && (*r != 'Z'); r++);
+  rz = r;
+  if (*r++)
+  {
+    while (*r)
+    {
+      bw = w;
+      while (eat && *r)         /* the '?' we ate makes us skip as many chars  */
+        if (*r++ != 'Z')        /* here, but can't skip stars or trailing zero */
+          eat--;
+      for (bw++; (*r) && (*bw != *r); r++)
+        if ((*r != 'Z') && (--trash < 0))
+          return 1;
+      if (!*r)
+        break;
+      for ((br = ++r), bw++;
+          (*br) && (*br != 'Z') && ((*bw == *br) || (*bw == 'A')); br++, bw++);
+      if (*br == 'Z')
+        while (*bw == 'A')
+          bw++, eat++;
+      if (!*bw)
+        return 0;
+      if (*bw != 'Z')
+      {
+        eat = 0;
+        if ((!*br) || (*r == 'Z'))
+        {                       /* If we hit the end of rm or a star in it */
+          trash -= (br - r);    /* makes no sense to rollback within this  */
+          if (trash < 0)        /* same chunk of br, skip it all and then  */
+            return 1;           /* either rollback or break this loop if   */
+          if (!*br)             /* it was the end of rm                    */
+            break;
+          r = br;
+        }
+        if (--trash < 0)
+          return 1;
+      }
+      else
+      {
+        r = br;
+        w = bw;
+      }
+    }
+  }
+
+  /* match the remaining chunks of wm against what remains of the tail of rm */
+  r = rz - eat - 1;             /* can't have <nul> or 'Z' within the tail, so just move r */
+  while (r >= rx)
+  {
+    bw = w;
+    for (bw++; (*bw != *r); r--)
+      if (--trash < 0)
+        return 1;
+    if (!(r >= rx))
+      return 1;
+    for ((br = --r), bw++;
+        (*bw) && (br >= rx) && ((*bw == *br) || (*bw == 'A')); br--, bw++);
+    if (!*bw)
+      return 0;
+    if (!(br >= rx))
+      return 1;
+    if (*bw != 'Z')
+    {
+      if (--trash < 0)
+        return 1;
+    }
+    else
+    {
+      r = br;
+      w = bw;
+    }
+  }
+  return 1;                     /* Auch... something left out ? Fail */
+}
+
+/** Test whether an address matches the most significant bits of a mask.
+ * @param[in] addr Address to test.
+ * @param[in] mask Address to test against.
+ * @param[in] bits Number of bits to test.
+ * @return 0 on mismatch, 1 if bits < 128 and all bits match; -1 if
+ * bits == 128 and all bits match.
+ */
+int ipmask_check(const struct irc_in_addr *addr, const struct irc_in_addr *mask, unsigned char bits)
+{
+  int k;
+
+  for (k = 0; k < 8; k++) {
+    if (bits < 16)
+      return !(htons(addr->in6_16[k] ^ mask->in6_16[k]) >> (16-bits));
+    if (addr->in6_16[k] != mask->in6_16[k])
+      return 0;
+    if (!(bits -= 16))
+      return 1;
+  }
+  return -1;
+}
diff --git a/ircd/memdebug.c b/ircd/memdebug.c
new file mode 100644 (file)
index 0000000..af7e530
--- /dev/null
@@ -0,0 +1,235 @@
+#include <sys/types.h>
+#include "ircd.h"
+#include "ircd_alloc.h"
+#include "ircd_log.h"
+#include "client.h"
+#include "s_debug.h"
+#include "send.h"
+#include <stdlib.h>
+#include <string.h>
+
+/* #include <assert.h> -- Now using assert in ircd_log.h */
+
+#ifdef MDEBUG
+
+/* To use this you need to get gc6.0 from:
+ * http://www.hpl.hp.com/personal/Hans_Boehm/gc/
+ * and you need to apply the patch in
+ * doc/debug_memleak_gc.patch to your gc6.0 tree, and reconfigure your ircd using
+ --with-leak-detect=path-to-gc6.0/.lib/
+ * You should only do this for debugging builds as it can slow things down
+ * a bit.
+ */
+
+#include "ircd_string.h"
+
+void *GC_malloc(size_t size);
+void GC_free(void *ptr);
+void GC_set_leak_handler(void (*)(void*, int));
+void GC_gcollect(void);
+extern int GC_find_leak;
+
+/** Header block to track an allocated block's information. */
+struct MemHeader
+{
+  uint32_t magic;
+  char type[32];
+  char file[32];
+  int line;
+  size_t length;
+  time_t since;
+};
+
+/** Overwrite \a len byte at \a p with 0xDEADBEEF.
+ * @param[out] p Memory buffer to overwrite.
+ * @param[in] len Number of bytes to overwrite.
+ */
+void
+memfrob(void *p, size_t len)
+{
+  /* deadbeef */
+  int i = 0;
+  const char *pat = "\xde\xad\xbe\xef";
+  char *s, *se;
+
+  for (s = (char*)p, se = s + (len & ~3) - 4;
+       s <= se;
+       s += 4)
+    *(uint32_t*)s = *(uint32_t*)pat;
+  for (se = s; se < s; s++)
+    *s = pat[i++];
+}
+
+/** Total number of bytes allocated. */
+static size_t mdbg_bytes_allocated = 0;
+/** Total number of blocks allocated. */
+static size_t mdbg_blocks_allocated = 0;
+/** Last Unix time that we ran garbage collection. */
+static time_t last_gcollect = 0;
+/** Minimum interval for garbage collection. */
+#define GC_FREQ 5
+
+/** Check whether we should run garbage collection.
+ * If so, do it.
+ */
+void
+dbg_check_gcollect(void)
+{
+  if (CurrentTime - last_gcollect < GC_FREQ)
+    return;
+  GC_gcollect();
+  last_gcollect = CurrentTime;
+}
+
+/** Allocate a block of memory.
+ * @param[in] size Number of bytes needed.
+ * @param[in] type Memory operation for block.
+ * @param[in] file File name of allocating function.
+ * @param[in] line Line number of allocating function.
+ * @return Pointer to the newly allocated block.
+ */
+void*
+dbg_malloc(size_t size, const char *type, const char *file, int line)
+{
+  struct MemHeader *mh = GC_malloc(size + sizeof(*mh));
+  if (mh == NULL)
+    return mh;
+  memfrob((void*)(mh + 1), size);
+  mh->magic = 0xA110CA7E;
+  ircd_strncpy(mh->type, type, sizeof(mh->type) - 1)[sizeof(mh->type) - 1] = 0;
+  ircd_strncpy(mh->file, file, sizeof(mh->file) - 1)[sizeof(mh->file) - 1] = 0;
+  mh->line = line;
+  mh->length = size;
+  mh->since = CurrentTime;
+  mdbg_bytes_allocated += size;
+  mdbg_blocks_allocated++;
+  dbg_check_gcollect();
+  return (void*)(mh + 1);
+}
+
+/** Allocate a zero-initialized block of memory.
+ * @param[in] size Number of bytes needed.
+ * @param[in] type Memory operation for block.
+ * @param[in] file File name of allocating function.
+ * @param[in] line Line number of allocating function.
+ * @return Pointer to the newly allocated block.
+ */
+void*
+dbg_malloc_zero(size_t size, const char *type, const char *file, int line)
+{
+  struct MemHeader *mh = GC_malloc(size + sizeof(*mh));
+  if (mh == NULL)
+    return mh;
+  memset((void*)(mh + 1), 0, size);
+  mh->magic = 0xA110CA7E;
+  ircd_strncpy(mh->type, type, sizeof(mh->type) - 1)[sizeof(mh->type) - 1] = 0;
+  ircd_strncpy(mh->file, file, sizeof(mh->file) - 1)[sizeof(mh->file) - 1] = 0;
+  mh->line = line;
+  mh->length = size;
+  mdbg_bytes_allocated += size;
+  mdbg_blocks_allocated++;
+  dbg_check_gcollect();
+  return (void*)(mh + 1);
+}
+
+/** Extend an allocated block of memory.
+ * @param[in] ptr Pointer to currently allocated block of memory (may be NULL).
+ * @param[in] size Minimum number of bytes for new block.
+ * @param[in] file File name of allocating function.
+ * @param[in] line Line number of allocating function.
+ * @return Pointer to the extended block of memory.
+ */
+void*
+dbg_realloc(void *ptr, size_t size, const char *file, int line)
+{
+  struct MemHeader *mh, *mh2;
+  if (ptr == NULL)
+    return dbg_malloc(size, "realloc", file, line);
+  mh = (struct MemHeader*)ptr - 1;
+  assert(mh->magic == 0xA110CA7E);
+  if (mh->length >= size)
+    return mh;
+  mh2 = dbg_malloc(size, "realloc", file, line);
+  if (mh2 == NULL)
+  {
+    dbg_free(mh+1, file, line);
+    return NULL;
+  }
+  memcpy(mh2+1, mh+1, mh->length);
+  dbg_free(mh+1, file, line);
+  return (void*)(mh2+1);
+}
+
+/** Deallocate a block of memory.
+ * @param[in] ptr Pointer to currently allocated block of memory (may be NULL).
+ * @param[in] file File name of deallocating function.
+ * @param[in] line Line number of deallocating function.
+ */
+void
+dbg_free(void *ptr, const char *file, int line)
+{
+  struct MemHeader *mh = (struct MemHeader*)ptr - 1;
+  /* XXX but bison gives us NULLs */
+  if (ptr == NULL)
+    return;
+  assert(mh->magic == 0xA110CA7E);
+  /* XXX can we get boehmgc to check for references to it? */
+  memfrob(mh, mh->length + sizeof(*mh));
+  mdbg_bytes_allocated -= mh->length;
+  mdbg_blocks_allocated--;
+  GC_free(mh);
+  dbg_check_gcollect();
+}
+
+/** Report number of bytes currently allocated.
+ * @return Number of bytes allocated.
+ */
+size_t
+fda_get_byte_count(void)
+{
+  dbg_check_gcollect();
+  return mdbg_bytes_allocated;
+}
+
+/** Report number of blocks currently allocated.
+ * @return Number of blocks allocated.
+ */
+size_t
+fda_get_block_count(void)
+{
+  return mdbg_blocks_allocated;
+}
+
+#include <stdio.h>
+
+/** Callback for when the garbage collector detects a memory leak.
+ * @param[in] p Pointer to leaked memory.
+ * @param[in] sz Length of the block.
+ */
+void
+dbg_memory_leaked(void *p, int sz)
+{
+  struct MemHeader *mh;
+  /* We have to return because the gc "leaks". */
+  mh = p;
+  if (mh->magic != 0xA110CA7E)
+    return;
+  sendto_opmask_butone(NULL, SNO_OLDSNO,
+                       "%s leak at %s:%u(%u bytes for %u seconds)",
+                       mh->type, mh->file, mh->line, mh->length,
+                       CurrentTime - mh->since);
+  Debug((DEBUG_ERROR,
+         "%s leak at %s:%u(%u bytes for %u seconds)",
+         mh->type, mh->file, mh->line, mh->length,
+         CurrentTime - mh->since));
+}
+
+/** Initialize the memory debugging subsystem. */
+void
+mem_dbg_initialise(void)
+{
+  GC_find_leak = 1;
+  GC_set_leak_handler(dbg_memory_leaked);
+}
+
+#endif
diff --git a/ircd/motd.c b/ircd/motd.c
new file mode 100644 (file)
index 0000000..78e43e4
--- /dev/null
@@ -0,0 +1,488 @@
+/*
+ * IRC - Internet Relay Chat, ircd/motd.c
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ *                    University of Oulu, Computing Center
+ * Copyright (C) 2000 Kevin L. Mitchell <klmitch@mit.edu>
+ *
+ * See file AUTHORS in IRC package for additional names of
+ * the programmers.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+/** @file
+ * @brief Message-of-the-day manipulation implementation.
+ * @version $Id: motd.c 1402 2005-05-10 03:43:09Z entrope $
+ */
+#include "config.h"
+
+#include "motd.h"
+#include "class.h"
+#include "client.h"
+#include "fileio.h"
+#include "ircd.h"
+#include "ircd_alloc.h"
+#include "ircd_features.h"
+#include "ircd_log.h"
+#include "ircd_reply.h"
+#include "ircd_string.h"
+#include "match.h"
+#include "msg.h"
+#include "numeric.h"
+#include "numnicks.h"
+#include "s_conf.h"
+#include "s_debug.h"
+#include "s_user.h"
+#include "s_stats.h"
+#include "send.h"
+
+/* #include <assert.h> -- Now using assert in ircd_log.h */
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+
+/** Global list of messages of the day. */
+static struct {
+  struct Motd*     local;     /**< Local MOTD. */
+  struct Motd*     remote;    /**< Remote MOTD. */
+  struct Motd*     other;     /**< MOTDs specified in configuration file. */
+  struct Motd*     freelist;  /**< Currently unused Motd structs. */
+  struct MotdCache* cachelist; /**< List of MotdCache entries. */
+} MotdList = { 0, 0, 0, 0, 0 };
+
+/** Create a struct Motd and initialize it.
+ * @param[in] hostmask Hostmask (or connection class name) to filter on.
+ * @param[in] path Path to MOTD file.
+ * @param[in] maxcount Maximum number of lines permitted for MOTD.
+ */
+static struct Motd *
+motd_create(const char *hostmask, const char *path, int maxcount)
+{
+  struct Motd* tmp;
+
+  assert(0 != path);
+
+  /* allocate memory and initialize the structure */
+  if (MotdList.freelist)
+  {
+    tmp = MotdList.freelist;
+    MotdList.freelist = tmp->next;
+  } else
+    tmp = (struct Motd *)MyMalloc(sizeof(struct Motd));
+  tmp->next = 0;
+
+  if (hostmask == NULL)
+    tmp->type = MOTD_UNIVERSAL;
+  else if (find_class(hostmask))
+    tmp->type = MOTD_CLASS;
+  else if (ipmask_parse(hostmask, &tmp->address, &tmp->addrbits))
+    tmp->type = MOTD_IPMASK;
+  else
+    tmp->type = MOTD_HOSTMASK;
+
+  if (hostmask != NULL)
+    DupString(tmp->hostmask, hostmask);
+  else
+    tmp->hostmask = NULL;
+
+  DupString(tmp->path, path);
+  tmp->maxcount = maxcount;
+  tmp->cache = 0;
+
+  return tmp;
+}
+
+/** This function reads a motd out of a file (if needed) and caches it.
+ * If a matching cache entry already exists, reuse it.  Otherwise,
+ * allocate and populate a new MotdCache for it.
+ * @param[in] motd Specification for MOTD file.
+ * @return Matching MotdCache entry.
+ */
+static struct MotdCache *
+motd_cache(struct Motd *motd)
+{
+  FBFILE*              file;
+  struct MotdCache*    cache;
+  struct stat          sb;
+  char                 line[MOTD_LINESIZE + 2]; /* \r\n */
+  char*                        tmp;
+  int                  i;
+
+  assert(0 != motd);
+  assert(0 != motd->path);
+
+  if (motd->cache)
+    return motd->cache;
+
+  /* try to find it in the list of cached files... */
+  for (cache = MotdList.cachelist; cache; cache = cache->next) {
+    if (!strcmp(cache->path, motd->path) &&
+       cache->maxcount == motd->maxcount) { /* found one... */
+      cache->ref++; /* increase reference count... */
+      motd->cache = cache; /* remember cache... */
+      return motd->cache; /* return it */
+    }
+  }
+
+  /* gotta read in the file, now */
+  if (!(file = fbopen(motd->path, "r"))) {
+    Debug((DEBUG_ERROR, "Couldn't open \"%s\": %s", motd->path,
+          strerror(errno)));
+    return 0;
+  }
+
+  /* need the file's modification time */
+  if (-1 == fbstat(&sb, file)) {
+    fbclose(file);
+    return 0;
+  }
+
+  /* Ok, allocate a structure; we'll realloc later to trim memory */
+  cache = (struct MotdCache *)MyMalloc(sizeof(struct MotdCache) +
+                                      (MOTD_LINESIZE * (MOTD_MAXLINES - 1)));
+
+  cache->ref = 1;
+  DupString(cache->path, motd->path);
+  cache->maxcount = motd->maxcount;
+
+  cache->modtime = *localtime((time_t *) &sb.st_mtime); /* store modtime */
+
+  cache->count = 0;
+  while (cache->count < cache->maxcount && fbgets(line, sizeof(line), file)) {
+    /* copy over line, stopping when we overflow or hit line end */
+    for (tmp = line, i = 0;
+        i < (MOTD_LINESIZE - 1) && *tmp && *tmp != '\r' && *tmp != '\n';
+        tmp++, i++)
+      cache->motd[cache->count][i] = *tmp;
+    cache->motd[cache->count][i] = '\0';
+
+    cache->count++;
+  }
+
+  fbclose(file); /* close the file */
+
+  /* trim memory usage a little */
+  motd->cache = (struct MotdCache*)MyMalloc(sizeof(struct MotdCache) +
+                                            (MOTD_LINESIZE * (cache->count - 1)));
+  memcpy(motd->cache, cache, sizeof(struct MotdCache) +
+         (MOTD_LINESIZE * (cache->count - 1)));
+  MyFree(cache);
+
+  /* now link it in... */
+  motd->cache->next = MotdList.cachelist;
+  motd->cache->prev_p = &MotdList.cachelist;
+  if (MotdList.cachelist)
+    MotdList.cachelist->prev_p = &motd->cache->next;
+  MotdList.cachelist = motd->cache;
+
+  return motd->cache;
+}
+
+/** Clear and dereference the Motd::cache element of \a motd.
+ * If the MotdCache::ref count goes to zero, free it.
+ * @param[in] motd MOTD to uncache.
+ */
+static void
+motd_decache(struct Motd *motd)
+{
+  struct MotdCache* cache;
+
+  assert(0 != motd);
+
+  if (!(cache = motd->cache)) /* we can be called for records with no cache */
+    return;
+
+  motd->cache = 0; /* zero the cache */
+
+  if (!--cache->ref) { /* reduce reference count... */
+    if (cache->next) /* ref is 0, delink from list and free */
+      cache->next->prev_p = cache->prev_p;
+    *cache->prev_p = cache->next;
+
+    MyFree(cache->path); /* free path info... */
+
+    MyFree(cache); /* very simple for a reason... */
+  }
+}
+
+/** Deallocate a MOTD structure.
+ * If it has cached content, uncache it.
+ * @param[in] motd MOTD to destroy.
+ */
+static void
+motd_destroy(struct Motd *motd)
+{
+  assert(0 != motd);
+
+  MyFree(motd->path); /* we always must have a path */
+  MyFree(motd->hostmask);
+  if (motd->cache) /* drop the cache */
+    motd_decache(motd);
+
+  motd->next = MotdList.freelist;
+  MotdList.freelist = motd;
+}
+
+/** Find the first matching MOTD block for a user.
+ * If the user is remote, always use remote MOTD.
+ * Otherwise, if there is a hostmask- or class-based MOTD that matches
+ * the user, use it.
+ * Otherwise, use the local MOTD.
+ * @param[in] cptr Client to find MOTD for.
+ * @return Pointer to first matching MOTD for the client.
+ */
+static struct Motd *
+motd_lookup(struct Client *cptr)
+{
+  struct Motd *ptr;
+  char *c_class = NULL;
+
+  assert(0 != cptr);
+
+  if (!MyUser(cptr)) /* not my user, always return remote motd */
+    return MotdList.remote;
+
+  c_class = get_client_class(cptr);
+  assert(c_class != NULL);
+
+  /* check the motd blocks first */
+  for (ptr = MotdList.other; ptr; ptr = ptr->next)
+  {
+    if (ptr->type == MOTD_CLASS
+        && !match(ptr->hostmask, c_class))
+      return ptr;
+    else if (ptr->type == MOTD_HOSTMASK
+             && !match(ptr->hostmask, cli_sockhost(cptr)))
+      return ptr;
+    else if (ptr->type == MOTD_IPMASK
+             && ipmask_check(&cli_ip(cptr), &ptr->address, ptr->addrbits))
+      return ptr;
+  }
+
+  return MotdList.local; /* Ok, return the default motd */
+}
+
+/** Send the content of a MotdCache to a user.
+ * If \a cache is NULL, simply send ERR_NOMOTD to the client.
+ * @param[in] cptr Client to send MOTD to.
+ * @param[in] cache MOTD body to send to client.
+ */
+static int
+motd_forward(struct Client *cptr, struct MotdCache *cache)
+{
+  int i;
+
+  assert(0 != cptr);
+
+  if (!cache) /* no motd to send */
+    return send_reply(cptr, ERR_NOMOTD);
+
+  /* send the motd */
+  send_reply(cptr, RPL_MOTDSTART, cli_name(&me));
+  send_reply(cptr, SND_EXPLICIT | RPL_MOTD, ":- %d-%d-%d %d:%02d",
+            cache->modtime.tm_year + 1900, cache->modtime.tm_mon + 1,
+            cache->modtime.tm_mday, cache->modtime.tm_hour,
+            cache->modtime.tm_min);
+
+  for (i = 0; i < cache->count; i++)
+    send_reply(cptr, RPL_MOTD, cache->motd[i]);
+
+  return send_reply(cptr, RPL_ENDOFMOTD); /* end */
+}
+
+/** Find the MOTD for a client and send it.
+ * @param[in] cptr Client being greeted.
+ */
+int
+motd_send(struct Client* cptr)
+{
+  assert(0 != cptr);
+
+  return motd_forward(cptr, motd_cache(motd_lookup(cptr)));
+}
+
+/** Send the signon MOTD to a user.
+ * If FEAT_NODEFAULTMOTD is true and a matching MOTD exists for the
+ * user, direct the client to type /MOTD to read it.  Otherwise, call
+ * motd_forward() for the user.
+ * @param[in] cptr Client that has just connected.
+ */
+void
+motd_signon(struct Client* cptr)
+{
+  struct MotdCache *cache;
+  const char *banner = NULL;
+
+  cache = motd_cache(motd_lookup(cptr));
+
+  if (!feature_bool(FEAT_NODEFAULTMOTD) || !cache)
+    motd_forward(cptr, cache);
+  else {
+    send_reply(cptr, RPL_MOTDSTART, cli_name(&me));
+    if ((banner = feature_str(FEAT_MOTD_BANNER)))
+      send_reply(cptr, SND_EXPLICIT | RPL_MOTD, ":%s", banner);
+    send_reply(cptr, SND_EXPLICIT | RPL_MOTD, ":\002Type /MOTD to read the "
+              "AUP before continuing using this service.\002");
+    send_reply(cptr, SND_EXPLICIT | RPL_MOTD, ":The message of the day was "
+              "last changed: %d-%d-%d %d:%d", cache->modtime.tm_year + 1900,
+              cache->modtime.tm_mon + 1, cache->modtime.tm_mday,
+              cache->modtime.tm_hour, cache->modtime.tm_min);
+    send_reply(cptr, RPL_ENDOFMOTD);
+  }
+}
+
+/** Clear all cached MOTD bodies.
+ * The local and remote MOTDs are re-cached immediately.
+ */
+void
+motd_recache(void)
+{
+  struct Motd* tmp;
+
+  motd_decache(MotdList.local); /* decache local and remote MOTDs */
+  motd_decache(MotdList.remote);
+
+  for (tmp = MotdList.other; tmp; tmp = tmp->next) /* now all the others */
+    motd_decache(tmp);
+
+  /* now recache local and remote MOTDs */
+  motd_cache(MotdList.local);
+  motd_cache(MotdList.remote);
+}
+
+/** Re-cache the local and remote MOTDs.
+ * If they already exist, they are deallocated first.
+ */
+void
+motd_init(void)
+{
+  if (MotdList.local) /* destroy old local... */
+    motd_destroy(MotdList.local);
+
+  MotdList.local = motd_create(0, feature_str(FEAT_MPATH), MOTD_MAXLINES);
+  motd_cache(MotdList.local); /* init local and cache it */
+
+  if (MotdList.remote) /* destroy old remote... */
+    motd_destroy(MotdList.remote);
+
+  MotdList.remote = motd_create(0, feature_str(FEAT_RPATH), MOTD_MAXREMOTE);
+  motd_cache(MotdList.remote); /* init remote and cache it */
+}
+
+/** Add a new MOTD.
+ * @param[in] hostmask Hostmask (or connection class name) to send this to.
+ * @param[in] path Pathname of file to send.
+ */
+void
+motd_add(const char *hostmask, const char *path)
+{
+  struct Motd *tmp;
+
+  tmp = motd_create(hostmask, path, MOTD_MAXLINES); /* create the motd */
+
+  tmp->next = MotdList.other; /* link it into the list */
+  MotdList.other = tmp;
+}
+
+/** Clear out all MOTDs.
+ * Compared to motd_recache(), this destroys all hostmask- or
+ * class-based MOTDs rather than simply uncaching them.
+ * Re-cache the local and remote MOTDs.
+ */
+void
+motd_clear(void)
+{
+  struct Motd *ptr, *next;
+
+  motd_decache(MotdList.local); /* decache local and remote MOTDs */
+  motd_decache(MotdList.remote);
+
+  if (MotdList.other) /* destroy other MOTDs */
+    for (ptr = MotdList.other; ptr; ptr = next)
+    {
+      next = ptr->next;
+      motd_destroy(ptr);
+    }
+
+  MotdList.other = 0;
+
+  /* now recache local and remote MOTDs */
+  motd_cache(MotdList.local);
+  motd_cache(MotdList.remote);
+}
+
+/** Report list of non-default MOTDs.
+ * @param[in] to Client requesting statistics.
+ * @param[in] sd Stats descriptor for request (ignored).
+ * @param[in] param Extra parameter from user (ignored).
+ */
+void
+motd_report(struct Client *to, const struct StatDesc *sd, char *param)
+{
+  struct Motd *ptr;
+
+  for (ptr = MotdList.other; ptr; ptr = ptr->next)
+    send_reply(to, SND_EXPLICIT | RPL_STATSTLINE, "T %s %s",
+               ptr->hostmask, ptr->path);
+}
+
+/** Report MOTD memory usage to a client.
+ * @param[in] cptr Client requesting memory usage.
+ */
+void
+motd_memory_count(struct Client *cptr)
+{
+  struct Motd *ptr;
+  struct MotdCache *cache;
+  unsigned int mt = 0,   /* motd count */
+               mtc = 0,  /* motd cache count */
+               mtf = 0;  /* motd free list count */
+  size_t mtm = 0,  /* memory consumed by motd */
+         mtcm = 0; /* memory consumed by motd cache */
+  if (MotdList.local)
+  {
+    mt++;
+    mtm += sizeof(struct Motd);
+    mtm += MotdList.local->path ? (strlen(MotdList.local->path) + 1) : 0;
+  }
+
+  if (MotdList.remote)
+  {
+    mt++;
+    mtm += sizeof(struct Motd);
+    mtm += MotdList.remote->path ? (strlen(MotdList.remote->path) + 1) : 0;
+  }
+
+  for (ptr = MotdList.other; ptr; ptr = ptr->next)
+  {
+    mt++;
+    mtm += sizeof(struct Motd);
+    mtm += ptr->path ? (strlen(ptr->path) + 1) : 0;
+  }
+
+  for (cache = MotdList.cachelist; cache; cache = cache->next)
+  {
+    mtc++;
+    mtcm += sizeof(struct MotdCache) + (MOTD_LINESIZE * (cache->count - 1));
+  }
+
+  if (MotdList.freelist)
+    for (ptr = MotdList.freelist; ptr; ptr = ptr->next)
+      mtf++;
+
+  send_reply(cptr, SND_EXPLICIT | RPL_STATSDEBUG,
+             ":Motds %d(%zu) Cache %d(%zu) Free %d(%zu)",
+             mt, mtm, mtc, mtcm, mtf, (mtf * sizeof(struct Motd)));
+}
diff --git a/ircd/msgq.c b/ircd/msgq.c
new file mode 100644 (file)
index 0000000..5b7e702
--- /dev/null
@@ -0,0 +1,628 @@
+/*
+ * IRC - Internet Relay Chat, ircd/msgq.c
+ * Copyright (C) 2000 Kevin L. Mitchell <klmitch@mit.edu>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+/** @file
+ * @brief Outbound message queue implementation.
+ * @version $Id: msgq.c 1627 2006-03-14 03:56:58Z entrope $
+ */
+#include "config.h"
+
+#include "msgq.h"
+#include "ircd.h"
+#include "ircd_alloc.h"
+#include "ircd_defs.h"
+#include "ircd_features.h"
+#include "ircd_log.h"
+#include "ircd_reply.h"
+#include "ircd_snprintf.h"
+#include "numeric.h"
+#include "send.h"
+#include "s_debug.h"
+#include "s_stats.h"
+
+/* #include <assert.h> -- Now using assert in ircd_log.h */
+#include <stdarg.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/uio.h>   /* struct iovec */
+
+#define MB_BASE_SHIFT  5 /**< Log2 of smallest message body to allocate. */
+#define MB_MAX_SHIFT   9 /**< Log2 of largest message body to allocate. */
+
+/** Buffer for a single message. */
+struct MsgBuf {
+  struct MsgBuf *next;         /**< next msg in global queue */
+  struct MsgBuf **prev_p;      /**< what points to us in linked list */
+  struct MsgBuf *real;         /**< the actual MsgBuf we're attaching */
+  unsigned int ref;            /**< reference count */
+  unsigned int length;         /**< length of message */
+  unsigned int power;          /**< size of buffer (power of 2) */
+  char msg[1];                 /**< the message */
+};
+
+/** Return allocated length of the buffer of \a buf. */
+#define bufsize(buf)   (1 << (buf)->power)
+
+/** Message body for a particular destination. */
+struct Msg {
+  struct Msg *next;            /**< next msg */
+  unsigned int sent;           /**< bytes in msg that have already been sent */
+  struct MsgBuf *msg;          /**< actual message in queue */
+};
+
+/** Statistics tracking for message sizes. */
+struct MsgSizes {
+  unsigned int msgs;           /**< total number of messages */
+  unsigned int sizes[BUFSIZE]; /**< histogram of message sizes */
+};
+
+/** Global tracking data for message buffers. */
+static struct {
+  struct MsgBuf *msglist;      /**< list of in-use MsgBuf's */
+  struct {
+    unsigned int alloc;                /**< number of Msg's allocated */
+    unsigned int used;         /**< number of Msg's in use */
+    struct Msg *free;          /**< freelist of Msg's */
+  } msgs;                       /**< tracking info for Msg structs */
+  size_t tot_bufsize;          /**< total amount of memory in buffers */
+  /** Array of MsgBuf information, one entry for each used bucket size. */
+  struct {
+    unsigned int alloc;                /**< total MsgBuf's of this size */
+    unsigned int used;         /**< number of MsgBuf's of this size in use */
+    struct MsgBuf *free;       /**< list of free MsgBuf's */
+  } msgBufs[MB_MAX_SHIFT - MB_BASE_SHIFT + 1];
+  struct MsgSizes sizes;       /**< histogram of message sizes */
+} MQData;
+
+/*
+ * This routine is used to remove a certain amount of data from a given
+ * queue and release the Msg (and MsgBuf) structure if needed
+ */
+/** Remove some data from a list within a message queue.
+ * @param[in,out] mq Message queue to remove from.
+ * @param[in,out] qlist Particular list within queue to remove from.
+ * @param[in,out] length_p Number of bytes left to remove.
+ */
+static void
+msgq_delmsg(struct MsgQ *mq, struct MsgQList *qlist, unsigned int *length_p)
+{
+  struct Msg *m;
+  unsigned int msglen;
+
+  assert(0 != mq);
+  assert(0 != qlist);
+  assert(0 != qlist->head);
+  assert(0 != length_p);
+
+  m = qlist->head; /* find the msg we're deleting from */
+
+  msglen = m->msg->length - m->sent; /* calculate how much is left */
+
+  if (*length_p >= msglen) { /* deleted it all? */
+    mq->length -= msglen; /* decrement length */
+    mq->count--; /* decrement the message count */
+    *length_p -= msglen;
+
+    msgq_clean(m->msg); /* free up the struct MsgBuf */
+    m->msg = 0; /* don't let it point anywhere nasty, please */
+
+    if (qlist->head == qlist->tail) /* figure out if we emptied the queue */
+      qlist->head = qlist->tail = 0;
+    else
+      qlist->head = m->next; /* just shift the list down some */
+
+    MQData.msgs.used--; /* struct Msg is not in use anymore */
+
+    m->next = MQData.msgs.free; /* throw it onto the free list */
+    MQData.msgs.free = m;
+  } else {
+    mq->length -= *length_p; /* decrement queue length */
+    m->sent += *length_p; /* this much of the message has been sent */
+    *length_p = 0; /* we've dealt with it all */
+  }
+}
+
+/** Initialize \a mq.
+ * @param[in] mq MsgQ to initialize.
+ */
+void
+msgq_init(struct MsgQ *mq)
+{
+  assert(0 != mq);
+
+  mq->length = 0;
+  mq->count = 0;
+  mq->queue.head = 0;
+  mq->queue.tail = 0;
+  mq->prio.head = 0;
+  mq->prio.tail = 0;
+}
+
+/** Delete bytes from the front of a message queue.
+ * @param[in] mq Queue to drop data from.
+ * @param[in] length Number of bytes to drop.
+ */
+void
+msgq_delete(struct MsgQ *mq, unsigned int length)
+{
+  assert(0 != mq);
+
+  while (length > 0) {
+    if (mq->queue.head && mq->queue.head->sent > 0) /* partial msg on norm q */
+      msgq_delmsg(mq, &mq->queue, &length);
+    else if (mq->prio.head) /* message (partial or complete) on prio queue */
+      msgq_delmsg(mq, &mq->prio, &length);
+    else if (mq->queue.head) /* message on normal queue */
+      msgq_delmsg(mq, &mq->queue, &length);
+    else
+      break;
+  }
+}
+
+/** Map data from a message queue to an I/O vector.
+ * @param[in] mq Message queue to send from.
+ * @param[out] iov Output vector.
+ * @param[in] count Number of elements in \a iov.
+ * @param[out] len Number of bytes mapped from \a mq to \a iov.
+ * @return Number of elements filled in \a iov.
+ */
+int
+msgq_mapiov(const struct MsgQ *mq, struct iovec *iov, int count,
+           unsigned int *len)
+{
+  struct Msg *queue;
+  struct Msg *prio;
+  int i = 0;
+
+  assert(0 != mq);
+  assert(0 != iov);
+  assert(0 != count);
+  assert(0 != len);
+
+  if (mq->length <= 0) /* no data to map */
+    return 0;
+
+  if (mq->queue.head && mq->queue.head->sent > 0) { /* partial msg on norm q */
+    iov[i].iov_base = mq->queue.head->msg->msg + mq->queue.head->sent;
+    iov[i].iov_len = mq->queue.head->msg->length - mq->queue.head->sent;
+    *len += iov[i].iov_len;
+
+    queue = mq->queue.head->next; /* where we start later... */
+
+    i++; /* filled an iovec... */
+    if (!--count) /* check for space */
+      return i;
+  } else
+    queue = mq->queue.head; /* start at head of queue */
+
+  if (mq->prio.head && mq->prio.head->sent > 0) { /* partial msg on prio q */
+    iov[i].iov_base = mq->prio.head->msg->msg + mq->prio.head->sent;
+    iov[i].iov_len = mq->prio.head->msg->length - mq->prio.head->sent;
+    *len += iov[i].iov_len;
+
+    prio = mq->prio.head->next; /* where we start later... */
+
+    i++; /* filled an iovec... */
+    if (!--count) /* check for space */
+      return i;
+  } else
+    prio = mq->prio.head; /* start at head of prio */
+
+  for (; prio; prio = prio->next) { /* go through prio queue */
+    iov[i].iov_base = prio->msg->msg; /* store message */
+    iov[i].iov_len = prio->msg->length;
+    *len += iov[i].iov_len;
+
+    i++; /* filled an iovec... */
+    if (!--count) /* check for space */
+      return i;
+  }
+
+  for (; queue; queue = queue->next) { /* go through normal queue */
+    iov[i].iov_base = queue->msg->msg;
+    iov[i].iov_len = queue->msg->length;
+    *len += iov[i].iov_len;
+
+    i++; /* filled an iovec... */
+    if (!--count) /* check for space */
+      return i;
+  }
+
+  return i;
+}
+
+/** Allocate a message buffer large enough to hold \a length bytes.
+ * TODO: \a in_mb needs better documentation.
+ * @param[in] in_mb Some other message buffer(?).
+ * @param[in] length Number of bytes of space to reserve in output.
+ * @return Pointer to some usable message buffer.
+ */
+static struct MsgBuf *
+msgq_alloc(struct MsgBuf *in_mb, int length)
+{
+  struct MsgBuf *mb;
+  int power;
+
+  /* Find the power of two size that will accommodate the message */
+  for (power = MB_BASE_SHIFT; power < MB_MAX_SHIFT + 1; power++)
+    if ((length - 1) >> power == 0)
+      break;
+  assert((1 << power) >= length);
+  assert((1 << power) <= 512);
+  length = 1 << power; /* reset the length */
+
+  /* If the message needs a buffer of exactly the existing size, just use it */
+  if (in_mb && in_mb->power == power) {
+    in_mb->real = in_mb; /* real buffer is this buffer */
+    return in_mb;
+  }
+
+  /* Try popping one off the freelist first */
+  if ((mb = MQData.msgBufs[power - MB_BASE_SHIFT].free)) {
+    MQData.msgBufs[power - MB_BASE_SHIFT].free = mb->next;
+  } else if (MQData.tot_bufsize < feature_int(FEAT_BUFFERPOOL)) {
+    /* Allocate another if we won't bust the BUFFERPOOL */
+    Debug((DEBUG_MALLOC, "Allocating MsgBuf of length %d (total size %zu)",
+          length, sizeof(struct MsgBuf) + length));
+    mb = (struct MsgBuf *)MyMalloc(sizeof(struct MsgBuf) + length);
+    MQData.msgBufs[power - MB_BASE_SHIFT].alloc++;
+    mb->power = power; /* remember size */
+    MQData.tot_bufsize += length;
+  }
+
+  if (mb) {
+    MQData.msgBufs[power - MB_BASE_SHIFT].used++; /* how many are we using? */
+
+    mb->real = 0; /* essential initializations */
+    mb->ref = 1;
+
+    if (in_mb) /* remember who's the *real* buffer */
+      in_mb->real = mb;
+  } else if (in_mb) /* just use the input buffer */
+    mb = in_mb->real = in_mb;
+
+  return mb; /* return the buffer */
+}
+
+/** Deallocate unused message buffers.
+ */
+static void
+msgq_clear_freembs(void)
+{
+  struct MsgBuf *mb;
+  int i;
+
+  /* Walk through the various size classes */
+  for (i = MB_BASE_SHIFT; i < MB_MAX_SHIFT + 1; i++)
+    /* walk down the free list */
+    while ((mb = MQData.msgBufs[i - MB_BASE_SHIFT].free)) {
+      MQData.msgBufs[i - MB_BASE_SHIFT].free = mb->next; /* shift free list */
+      MQData.msgBufs[i - MB_BASE_SHIFT].alloc--; /* reduce allocation count */
+      MQData.tot_bufsize -= 1 << i; /* reduce total buffer allocation count */
+      MyFree(mb); /* and free the buffer */
+    }
+}
+
+/** Format a message buffer for a client from a format string.
+ * @param[in] dest %Client that receives the data (may be NULL).
+ * @param[in] format Format string for message.
+ * @param[in] vl Argument list for \a format.
+ * @return Allocated MsgBuf.
+ */
+struct MsgBuf *
+msgq_vmake(struct Client *dest, const char *format, va_list vl)
+{
+  struct MsgBuf *mb;
+
+  assert(0 != format);
+
+  if (!(mb = msgq_alloc(0, BUFSIZE))) {
+    if (feature_bool(FEAT_HAS_FERGUSON_FLUSHER)) {
+      /*
+       * from "Married With Children" episode were Al bought a REAL toilet
+       * on the black market because he was tired of the wimpy water
+       * conserving toilets they make these days --Bleep
+       */
+      /*
+       * Apparently this doesn't work, the server _has_ to
+       * dump a few clients to handle the load. A fully loaded
+       * server cannot handle a net break without dumping some
+       * clients. If we flush the connections here under a full
+       * load we may end up starving the kernel for mbufs and
+       * crash the machine
+       */
+      /*
+       * attempt to recover from buffer starvation before
+       * bailing this may help servers running out of memory
+       */
+      flush_connections(0);
+      mb = msgq_alloc(0, BUFSIZE);
+    }
+    if (!mb) { /* OK, try clearing the buffer free list */
+      msgq_clear_freembs();
+      mb = msgq_alloc(0, BUFSIZE);
+    }
+    if (!mb) { /* OK, try killing a client */
+      kill_highest_sendq(0); /* Don't kill any server connections */
+      msgq_clear_freembs();  /* Release whatever was just freelisted */
+      mb = msgq_alloc(0, BUFSIZE);
+    }
+    if (!mb) { /* hmmm... */
+      kill_highest_sendq(1); /* Try killing a server connection now */
+      msgq_clear_freembs();  /* Clear freelist again */
+      mb = msgq_alloc(0, BUFSIZE);
+    }
+    if (!mb) /* AIEEEE! */
+      server_panic("Unable to allocate buffers!");
+  }
+
+  mb->next = MQData.msglist; /* initialize the msgbuf */
+  mb->prev_p = &MQData.msglist;
+
+  /* fill the buffer */
+  mb->length = ircd_vsnprintf(dest, mb->msg, bufsize(mb) - 1, format, vl);
+
+  if (mb->length > bufsize(mb) - 2)
+    mb->length = bufsize(mb) - 2;
+
+  mb->msg[mb->length++] = '\r'; /* add \r\n to buffer */
+  mb->msg[mb->length++] = '\n';
+  mb->msg[mb->length] = '\0'; /* not strictly necessary */
+
+  assert(mb->length <= bufsize(mb));
+
+  if (MQData.msglist) /* link it into the list */
+    MQData.msglist->prev_p = &mb->next;
+  MQData.msglist = mb;
+
+  return mb;
+}
+
+/** Format a message buffer for a client from a format string.
+ * @param[in] dest %Client that receives the data (may be NULL).
+ * @param[in] format Format string for message.
+ * @return Allocated MsgBuf.
+ */
+struct MsgBuf *
+msgq_make(struct Client *dest, const char *format, ...)
+{
+  va_list vl;
+  struct MsgBuf *mb;
+
+  va_start(vl, format);
+  mb = msgq_vmake(dest, format, vl);
+  va_end(vl);
+
+  return mb;
+}
+
+/** Append text to an existing message buffer.
+ * @param[in] dest %Client for whom to format the message.
+ * @param[in] mb Message buffer to append to.
+ * @param[in] format Format string of what to append.
+ */
+void
+msgq_append(struct Client *dest, struct MsgBuf *mb, const char *format, ...)
+{
+  va_list vl;
+
+  assert(0 != mb);
+  assert(0 != format);
+  assert(0 == mb->real);
+
+  assert(2 < mb->length);
+  assert(bufsize(mb) >= mb->length);
+
+  mb->length -= 2; /* back up to before \r\n */
+
+  va_start(vl, format); /* append to the buffer */
+  mb->length += ircd_vsnprintf(dest, mb->msg + mb->length,
+                              bufsize(mb) - mb->length - 1, format, vl);
+  va_end(vl);
+
+  if (mb->length > bufsize(mb) - 2)
+    mb->length = bufsize(mb) - 2;
+
+  mb->msg[mb->length++] = '\r'; /* add \r\n to buffer */
+  mb->msg[mb->length++] = '\n';
+  mb->msg[mb->length] = '\0'; /* not strictly necessary */
+
+  assert(mb->length <= bufsize(mb));
+}
+
+/** Decrement the reference count on \a mb, freeing it if needed.
+ * @param[in] mb MsgBuf to release.
+ */
+void
+msgq_clean(struct MsgBuf *mb)
+{
+  assert(0 != mb);
+  assert(0 < mb->ref);
+
+  if (!--mb->ref) { /* deallocate the message */
+    if (mb->prev_p) {
+      *mb->prev_p = mb->next; /* clip it out of active MsgBuf's list */
+      if (mb->next)
+       mb->next->prev_p = mb->prev_p;
+    }
+
+    if (mb->real && mb->real != mb) /* clean up the real buffer */
+      msgq_clean(mb->real);
+
+    mb->next = MQData.msgBufs[mb->power - MB_BASE_SHIFT].free;
+    MQData.msgBufs[mb->power - MB_BASE_SHIFT].free = mb;
+    MQData.msgBufs[mb->power - MB_BASE_SHIFT].used--;
+
+    mb->prev_p = 0;
+  }
+}
+
+/** Append a message to a peer's message queue.
+ * @param[in] mq Message queue to append to.
+ * @param[in] mb Message to append.
+ * @param[in] prio If non-zero, use the high-priority (lag-busting) message list; else use the normal list.
+ */
+void
+msgq_add(struct MsgQ *mq, struct MsgBuf *mb, int prio)
+{
+  struct MsgQList *qlist;
+  struct Msg *msg;
+
+  assert(0 != mq);
+  assert(0 != mb);
+  assert(0 < mb->ref);
+  assert(0 < mb->length);
+
+  Debug((DEBUG_SEND, "Adding buffer %p [%.*s] length %u to %s queue", mb,
+        mb->length - 2, mb->msg, mb->length, prio ? "priority" : "normal"));
+
+  qlist = prio ? &mq->prio : &mq->queue;
+
+  if (!(msg = MQData.msgs.free)) { /* do I need to allocate one? */
+    msg = (struct Msg *)MyMalloc(sizeof(struct Msg));
+    MQData.msgs.alloc++; /* we allocated another */
+  } else /* shift the free list */
+    MQData.msgs.free = MQData.msgs.free->next;
+
+  MQData.msgs.used++; /* we're using another */
+
+  msg->next = 0; /* initialize the msg */
+  msg->sent = 0;
+
+  /* Get the real buffer, allocating one if necessary */
+  if (!mb->real) {
+    struct MsgBuf *tmp;
+
+    MQData.sizes.msgs++; /* update histogram counts */
+    MQData.sizes.sizes[mb->length - 1]++;
+
+    tmp = msgq_alloc(mb, mb->length); /* allocate a close-fitting buffer */
+
+    if (tmp != mb) { /* OK, prepare the new "real" buffer */
+      Debug((DEBUG_SEND, "Copying old buffer %p [%.*s] length %u into new "
+            "buffer %p size %u", mb, mb->length - 2, mb->msg, mb->length,
+            tmp, bufsize(tmp)));
+      memcpy(tmp->msg, mb->msg, mb->length + 1); /* copy string over */
+      tmp->length = mb->length;
+
+      tmp->next = mb->next; /* replace it in the list, now */
+      if (tmp->next)
+       tmp->next->prev_p = &tmp->next;
+      tmp->prev_p = mb->prev_p;
+      *tmp->prev_p = tmp;
+
+      mb->next = 0; /* this one's no longer in the list */
+      mb->prev_p = 0;
+    }
+  }
+
+  mb = mb->real; /* work with the real buffer */
+  mb->ref++; /* increment the ref count on the buffer */
+
+  msg->msg = mb; /* point at the real message buffer now */
+
+  if (!qlist->head) /* queue list was empty; head and tail point to msg */
+    qlist->head = qlist->tail = msg;
+  else {
+    assert(0 != qlist->tail);
+
+    qlist->tail->next = msg; /* queue had something in it; add to end */
+    qlist->tail = msg;
+  }
+
+  mq->length += mb->length; /* update the queue length */
+  mq->count++; /* and the queue count */
+}
+
+/** Report memory statistics for message buffers.
+ * @param[in] cptr Client requesting information.
+ * @param[out] msg_alloc Receives number of bytes allocated in Msg structs.
+ * @param[out] msgbuf_alloc Receives number of bytes allocated in MsgBuf structs.
+ */
+void
+msgq_count_memory(struct Client *cptr, size_t *msg_alloc, size_t *msgbuf_alloc)
+{
+  int i;
+  size_t total = 0, size;
+
+  assert(0 != cptr);
+  assert(0 != msg_alloc);
+  assert(0 != msgbuf_alloc);
+
+  /* Data for Msg's is simple, so just send it */
+  send_reply(cptr, SND_EXPLICIT | RPL_STATSDEBUG,
+            ":Msgs allocated %d(%zu) used %d(%zu) text %zu",
+             MQData.msgs.alloc, MQData.msgs.alloc * sizeof(struct Msg),
+             MQData.msgs.used,  MQData.msgs.used * sizeof(struct Msg),
+             MQData.tot_bufsize);
+  /* count_memory() wants to know the total */
+  *msg_alloc = MQData.msgs.alloc * sizeof(struct Msg);
+
+  /* Ok, now walk through each size class */
+  for (i = MB_BASE_SHIFT; i < MB_MAX_SHIFT + 1; i++) {
+    size = sizeof(struct MsgBuf) + (1 << i); /* total size of a buffer */
+
+    /* Send information for this buffer size class */
+    send_reply(cptr, SND_EXPLICIT | RPL_STATSDEBUG,
+              ":MsgBufs of size %zu allocated %d(%zu) used %d(%zu)", 1 << i,
+              MQData.msgBufs[i - MB_BASE_SHIFT].alloc,
+              MQData.msgBufs[i - MB_BASE_SHIFT].alloc * size,
+              MQData.msgBufs[i - MB_BASE_SHIFT].used,
+              MQData.msgBufs[i - MB_BASE_SHIFT].used * size);
+
+    /* count_memory() wants to know the total */
+    total += MQData.msgBufs[i - MB_BASE_SHIFT].alloc * size;
+  }
+  *msgbuf_alloc = total;
+}
+
+/** Report remaining space in a MsgBuf.
+ * @param[in] mb Message buffer to check.
+ * @return Number of additional bytes that can be appended to the message.
+ */
+unsigned int
+msgq_bufleft(struct MsgBuf *mb)
+{
+  assert(0 != mb);
+
+  return bufsize(mb) - mb->length; /* \r\n counted in mb->length */
+}
+
+/** Send histogram of message lengths to a client.
+ * @param[in] cptr Client requesting statistics.
+ * @param[in] sd Stats descriptor for request (ignored).
+ * @param[in] param Extra parameter from user (ignored).
+ */
+void
+msgq_histogram(struct Client *cptr, const struct StatDesc *sd, char *param)
+{
+  struct MsgSizes tmp = MQData.sizes; /* All hail structure copy! */
+  int i;
+
+  send_reply(cptr, SND_EXPLICIT | RPL_STATSDEBUG,
+            ":Histogram of message lengths (%lu messages)", tmp.msgs);
+  for (i = 0; i + 16 <= BUFSIZE; i += 16)
+    send_reply(cptr, SND_EXPLICIT | RPL_STATSDEBUG, ":% 4d: %u %u %u %u "
+              "%u %u %u %u %u %u %u %u %u %u %u %u", i + 1,
+              tmp.sizes[i +  0], tmp.sizes[i +  1], tmp.sizes[i +  2],
+              tmp.sizes[i +  3], tmp.sizes[i +  4], tmp.sizes[i +  5],
+              tmp.sizes[i +  6], tmp.sizes[i +  7], tmp.sizes[i +  8],
+              tmp.sizes[i +  9], tmp.sizes[i + 10], tmp.sizes[i + 11],
+              tmp.sizes[i + 12], tmp.sizes[i + 13], tmp.sizes[i + 14],
+              tmp.sizes[i + 15]);
+}
diff --git a/ircd/numnicks.c b/ircd/numnicks.c
new file mode 100644 (file)
index 0000000..11d8851
--- /dev/null
@@ -0,0 +1,527 @@
+/*
+ * IRC - Internet Relay Chat, ircd/channel.c
+ * Copyright (C) 1996 Carlo Wood (I wish this was C++ - this sucks :/)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+/** @file
+ * @brief Implementation of numeric nickname operations.
+ * @version $Id: numnicks.c 1398 2005-05-08 00:56:05Z entrope $
+ */
+#include "config.h"
+
+#include "numnicks.h"
+#include "client.h"
+#include "ircd.h"
+#include "ircd_alloc.h"
+#include "ircd_log.h"
+#include "ircd_string.h"
+#include "match.h"
+#include "s_bsd.h"
+#include "s_debug.h"
+#include "s_misc.h"
+#include "struct.h"
+
+/* #include <assert.h> -- Now using assert in ircd_log.h */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+
+/** @page numnicks Numeric Nicks
+ * %Numeric nicks (numnicks) are new as of version ircu2.10.00beta1.
+ *
+ * The idea is as follows:
+ * In most messages (for protocol 10+) the original nick will be
+ * replaced by a 5 character string: YYXXX
+ * Where 'YY' represents the server, and 'XXX' the nick on that server.
+ *
+ * 'YYXXX' should not interfere with the input parser, and therefore is
+ * not allowed to contain spaces or a ':'.
+ * Also, 'YY' can't start with a '+' because of m_server().
+ *
+ * We keep the characters printable for debugging reasons too.
+ *
+ * The 'XXX' value can be larger then the maximum number of clients
+ * per server, we use a mask (Server::nn_mask) to get the real
+ * client numeric. The overhead is used to have some redundancy so
+ * just-disconnected-client aren't confused with just-connected ones.
+ */
+
+
+/* These must be the same on ALL servers ! Do not change ! */
+
+/** Number of bits encoded in one numnick character. */
+#define NUMNICKLOG 6
+/** Bitmask to select value of next numnick character. */
+#define NUMNICKMASK 63          /* (NUMNICKBASE-1) */
+/** Number of servers representable in a numnick. */
+#define NN_MAX_SERVER 4096      /* (NUMNICKBASE * NUMNICKBASE) */
+/** Number of clients representable in a numnick. */
+#define NN_MAX_CLIENT 262144    /* NUMNICKBASE ^ 3 */
+
+/*
+ * The internal counter for the 'XX' of local clients
+ */
+/** Maximum used server numnick, plus one. */
+static unsigned int lastNNServer = 0;
+/** Array of servers indexed by numnick. */
+static struct Client* server_list[NN_MAX_SERVER];
+
+/* *INDENT-OFF* */
+
+/**
+ * Converts a numeric to the corresponding character.
+ * The following characters are currently known to be forbidden:
+ *
+ * '\\0' : Because we use '\\0' as end of line.
+ *
+ * ' '  : Because parse_*() uses this as parameter separator.
+ *
+ * ':'  : Because parse_server() uses this to detect if a prefix is a
+ *        numeric or a name.
+ *
+ * '+'  : Because m_nick() uses this to determine if parv[6] is a
+ *        umode or not.
+ *
+ * '&', '#', '$', '@' and '%' :
+ *        Because m_message() matches these characters to detect special cases.
+ */
+static const char convert2y[] = {
+  'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P',
+  'Q','R','S','T','U','V','W','X','Y','Z','a','b','c','d','e','f',
+  'g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v',
+  'w','x','y','z','0','1','2','3','4','5','6','7','8','9','[',']'
+};
+
+/** Converts a character to its (base64) numnick value. */
+static const unsigned int convert2n[] = {
+   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+  52,53,54,55,56,57,58,59,60,61, 0, 0, 0, 0, 0, 0,
+   0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,
+  15,16,17,18,19,20,21,22,23,24,25,62, 0,63, 0, 0,
+   0,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,
+  41,42,43,44,45,46,47,48,49,50,51, 0, 0, 0, 0, 0,
+
+   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+/* *INDENT-ON* */
+
+/** Convert a string to its value as a numnick.
+ * @param[in] s Numnick string to decode.
+ * @return %Numeric nickname value.
+ */
+unsigned int base64toint(const char* s)
+{
+  unsigned int i = convert2n[(unsigned char) *s++];
+  while (*s) {
+    i <<= NUMNICKLOG;
+    i += convert2n[(unsigned char) *s++];
+  }
+  return i;
+}
+
+/** Encode a number as a numnick.
+ * @param[out] buf Output buffer.
+ * @param[in] v Value to encode.
+ * @param[in] count Number of numnick digits to write to \a buf.
+ */
+const char* inttobase64(char* buf, unsigned int v, unsigned int count)
+{
+  buf[count] = '\0';
+  while (count > 0) {
+    buf[--count] = convert2y[(v & NUMNICKMASK)];
+    v >>= NUMNICKLOG;
+  }
+  return buf;
+}
+
+/** Look up a server by numnick string.
+ * See @ref numnicks for more details.
+ * @param[in] numeric %Numeric nickname of server (may contain trailing junk).
+ * @return %Server with that numnick (or NULL).
+ */
+static struct Client* FindXNServer(const char* numeric)
+{
+  char buf[3];
+  buf[0] = *numeric++;
+  buf[1] = *numeric;
+  buf[2] = '\0';
+  Debug((DEBUG_DEBUG, "FindXNServer: %s(%d)", buf, base64toint(buf)));
+  return server_list[base64toint(buf)];
+}
+
+/** Look up a server by numnick string.
+ * See @ref numnicks for more details.
+ * @param[in] numeric %Numeric nickname of server.
+ * @return %Server with that numnick (or NULL).
+ */
+struct Client* FindNServer(const char* numeric)
+{
+  unsigned int len = strlen(numeric);
+
+  if (len < 3) {
+    Debug((DEBUG_DEBUG, "FindNServer: %s(%d)", numeric, base64toint(numeric)));
+    return server_list[base64toint(numeric)];
+  }
+  else if (len == 3) {
+    Debug((DEBUG_DEBUG, "FindNServer: %c(%d)", *numeric, 
+           convert2n[(unsigned char) *numeric]));
+    return server_list[convert2n[(unsigned char) *numeric]];
+  }
+  return FindXNServer(numeric);
+}
+
+/** Look up a user by numnick string.
+ * See @ref numnicks for more details.
+ * @param[in] yxx %Numeric nickname of user.
+ * @return %User with that numnick (or NULL).
+ */
+struct Client* findNUser(const char* yxx)
+{
+  struct Client* server = 0;
+  if (5 == strlen(yxx)) {
+    if (0 != (server = FindXNServer(yxx))) {
+      Debug((DEBUG_DEBUG, "findNUser: %s(%d)", yxx, 
+             base64toint(yxx + 2) & cli_serv(server)->nn_mask));
+      return cli_serv(server)->client_list[base64toint(yxx + 2) & cli_serv(server)->nn_mask];
+    }
+  }
+  else if (0 != (server = FindNServer(yxx))) {
+    Debug((DEBUG_DEBUG, "findNUser: %s(%d)",
+           yxx, base64toint(yxx + 1) & cli_serv(server)->nn_mask));
+    return cli_serv(server)->client_list[base64toint(yxx + 1) & cli_serv(server)->nn_mask];
+  }
+  return 0;
+}
+
+/** Remove a client from a server's user array.
+ * @param[in] server %Server that owns the user to remove.
+ * @param[in] yxx Numnick of client to remove.
+ */
+void RemoveYXXClient(struct Client* server, const char* yxx)
+{
+  assert(0 != server);
+  assert(0 != yxx);
+  if (*yxx) {
+    Debug((DEBUG_DEBUG, "RemoveYXXClient: %s(%d)", yxx,
+           base64toint(yxx) & cli_serv(server)->nn_mask));
+    cli_serv(server)->client_list[base64toint(yxx) & cli_serv(server)->nn_mask] = 0;
+  }
+}
+
+/** Set a server's numeric nick.
+ * @param[in] cptr %Client that announced the server (ignored).
+ * @param[in,out] server %Server that is being assigned a numnick.
+ * @param[in] yxx %Numeric nickname for server.
+ */
+void SetServerYXX(struct Client* cptr, struct Client* server, const char* yxx)
+{
+  unsigned int index;
+  if (5 == strlen(yxx)) {
+    ircd_strncpy(cli_yxx(server), yxx, 2);
+    ircd_strncpy(cli_serv(server)->nn_capacity, yxx + 2, 3);
+  }
+  else {
+    (cli_yxx(server))[0]               = yxx[0];
+    cli_serv(server)->nn_capacity[0] = yxx[1];
+    cli_serv(server)->nn_capacity[1] = yxx[2];
+  }
+  cli_serv(server)->nn_mask = base64toint(cli_serv(server)->nn_capacity);
+
+  index = base64toint(cli_yxx(server));
+  if (index >= lastNNServer)
+    lastNNServer = index + 1;
+  server_list[index] = server;
+
+  /* Note, exit_one_client uses the fact that `client_list' != NULL to
+   * determine that SetServerYXX has been called - and then calls
+   * ClearServerYXX. However, freeing the allocation happens in free_client() */
+  cli_serv(server)->client_list =
+      (struct Client**) MyCalloc(cli_serv(server)->nn_mask + 1, sizeof(struct Client*));
+}
+
+/** Set a server's capacity.
+ * @param[in] c %Server whose capacity is being set.
+ * @param[in] capacity Maximum number of clients the server supports.
+ */
+void SetYXXCapacity(struct Client* c, unsigned int capacity)
+{
+  unsigned int max_clients = 16;
+  /*
+   * Calculate mask to be used for the maximum number of clients
+   */
+  while (max_clients < capacity)
+    max_clients <<= 1;
+  /*
+   * Sanity checks
+   */
+  if (max_clients > NN_MAX_CLIENT) {
+    fprintf(stderr, "MAXCLIENTS (or MAXCONNECTIONS) is (at least) %d "
+            "too large ! Please decrease this value.\n",
+             max_clients - NN_MAX_CLIENT);
+    exit(-1);
+  }
+  --max_clients;
+  inttobase64(cli_serv(c)->nn_capacity, max_clients, 3);
+  cli_serv(c)->nn_mask = max_clients;       /* Our Numeric Nick mask */
+  cli_serv(c)->client_list = (struct Client**) MyCalloc(max_clients + 1,
+                                                     sizeof(struct Client*));
+  server_list[base64toint(cli_yxx(c))] = c;
+}
+
+/** Set a server's numeric nick.
+ * See @ref numnicks for more details.
+ * @param[in] c %Server that is being assigned a numnick.
+ * @param[in] numeric Numnick value for server.
+ */
+void SetYXXServerName(struct Client* c, unsigned int numeric)
+{
+  assert(0 != c);
+  assert(numeric < NN_MAX_SERVER);
+
+  inttobase64(cli_yxx(c), numeric, 2);
+  if (numeric >= lastNNServer)
+    lastNNServer = numeric + 1;
+  server_list[numeric] = c;
+}
+
+/** Unassign a server's numnick.
+ * @param[in] server %Server that should be removed from the numnick table.
+ */
+void ClearServerYXX(const struct Client *server)
+{
+  unsigned int index = base64toint(cli_yxx(server));
+  if (server_list[index] == server)     /* Sanity check */
+    server_list[index] = 0;
+}
+
+/** Register numeric of new (remote) client.
+ * See @ref numnicks for more details.
+ * Add it to the appropriate client_list.
+ * @param[in] acptr %User being registered.
+ * @param[in] yxx User's numnick.
+ */
+void SetRemoteNumNick(struct Client* acptr, const char *yxx)
+{
+  struct Client** acptrp;
+  struct Client*  server = cli_user(acptr)->server;
+
+  if (5 == strlen(yxx)) {
+    strcpy(cli_yxx(acptr), yxx + 2);
+  }
+  else {
+    (cli_yxx(acptr))[0] = *++yxx;
+    (cli_yxx(acptr))[1] = *++yxx;
+    (cli_yxx(acptr))[2] = 0;
+  }
+  Debug((DEBUG_DEBUG, "SetRemoteNumNick: %s(%d)", cli_yxx(acptr),
+         base64toint(cli_yxx(acptr)) & cli_serv(server)->nn_mask));
+
+  acptrp = &(cli_serv(server))->client_list[base64toint(cli_yxx(acptr)) & cli_serv(server)->nn_mask];
+  if (*acptrp) {
+    /*
+     * this exits the old client in the array, not the client
+     * that is being set
+     */
+    exit_client(cli_from(acptr), *acptrp, server, "Numeric nick collision (Ghost)");
+  }
+  *acptrp = acptr;
+}
+
+
+/** Register numeric of new (local) client.
+ * See @ref numnicks for more details.
+ * Assign a numnick and add it to our client_list.
+ * @param[in] cptr %User being registered.
+ */
+int SetLocalNumNick(struct Client *cptr)
+{
+  static unsigned int last_nn     = 0;
+  struct Client**     client_list = cli_serv(&me)->client_list;
+  unsigned int        mask        = cli_serv(&me)->nn_mask;
+  unsigned int        count       = 0;
+
+  assert(cli_user(cptr)->server == &me);
+
+  while (client_list[last_nn & mask]) {
+    if (++count == NN_MAX_CLIENT) {
+      assert(count < NN_MAX_CLIENT);
+      return 0;
+    }
+    if (++last_nn == NN_MAX_CLIENT)
+      last_nn = 0;
+  }
+  client_list[last_nn & mask] = cptr;  /* Reserve the numeric ! */
+
+  inttobase64(cli_yxx(cptr), last_nn, 3);
+  if (++last_nn == NN_MAX_CLIENT)
+    last_nn = 0;
+  return 1;
+}
+
+/** Mark servers whose name matches the given (compiled) mask by
+ * setting their FLAG_MAP flag.
+ * @param[in] cmask Compiled mask for server names.
+ * @param[in] minlen Minimum match length for \a cmask.
+ * @return Number of servers marked.
+ */
+int markMatchexServer(const char *cmask, int minlen)
+{
+  int cnt = 0;
+  int i;
+  struct Client *acptr;
+
+  for (i = 0; i < lastNNServer; i++) {
+    if ((acptr = server_list[i]))
+    {
+      if (matchexec(cli_name(acptr), cmask, minlen))
+        ClrFlag(acptr, FLAG_MAP);
+      else
+      {
+        SetFlag(acptr, FLAG_MAP);
+        cnt++;
+      }
+    }
+  }
+  return cnt;
+}
+
+/** Find first server whose name matches the given mask.
+ * @param[in,out] mask %Server name mask (collapse()d in-place).
+ * @return Matching server with lowest numnick value (or NULL).
+ */
+struct Client* find_match_server(char *mask)
+{
+  struct Client *acptr;
+  int i;
+
+  if (!(BadPtr(mask))) {
+    collapse(mask);
+    for (i = 0; i < lastNNServer; i++) {
+      if ((acptr = server_list[i]) && (!match(mask, cli_name(acptr))))
+        return acptr;
+    }
+  }
+  return 0;
+}
+
+/** Encode an IP address in the base64 used by numnicks.
+ * For IPv4 addresses (including IPv4-mapped and IPv4-compatible IPv6
+ * addresses), the 32-bit host address is encoded directly as six
+ * characters.
+ *
+ * For IPv6 addresses, each 16-bit address segment is encoded as three
+ * characters, but the longest run of zero segments is encoded using an
+ * underscore.
+ * @param[out] buf Output buffer to write to.
+ * @param[in] addr IP address to encode.
+ * @param[in] count Number of bytes writable to \a buf.
+ * @param[in] v6_ok If non-zero, peer understands base-64 encoded IPv6 addresses.
+ */
+const char* iptobase64(char* buf, const struct irc_in_addr* addr, unsigned int count, int v6_ok)
+{
+  if (irc_in_addr_is_ipv4(addr)) {
+    assert(count >= 6);
+    inttobase64(buf, (ntohs(addr->in6_16[6]) << 16) | ntohs(addr->in6_16[7]), 6);
+  } else if (!v6_ok) {
+    assert(count >= 6);
+    if (addr->in6_16[0] == htons(0x2002))
+        inttobase64(buf, (ntohs(addr->in6_16[1]) << 16) | ntohs(addr->in6_16[2]), 6);
+    else
+        strcpy(buf, "AAAAAA");
+  } else {
+    unsigned int max_start, max_zeros, curr_zeros, zero, ii;
+    char *output = buf;
+
+    assert(count >= 25);
+    /* Can start by printing out the leading non-zero parts. */
+    for (ii = 0; (addr->in6_16[ii]) && (ii < 8); ++ii) {
+      inttobase64(output, ntohs(addr->in6_16[ii]), 3);
+      output += 3;
+    }
+    /* Find the longest run of zeros. */
+    for (max_start = zero = ii, max_zeros = curr_zeros = 0; ii < 8; ++ii) {
+      if (!addr->in6_16[ii])
+        curr_zeros++;
+      else if (curr_zeros > max_zeros) {
+        max_start = ii - curr_zeros;
+        max_zeros = curr_zeros;
+        curr_zeros = 0;
+      }
+    }
+    if (curr_zeros > max_zeros) {
+      max_start = ii - curr_zeros;
+      max_zeros = curr_zeros;
+      curr_zeros = 0;
+    }
+    /* Print the rest of the address */
+    for (ii = zero; ii < 8; ) {
+      if ((ii == max_start) && max_zeros) {
+        *output++ = '_';
+        ii += max_zeros;
+      } else {
+        inttobase64(output, ntohs(addr->in6_16[ii]), 3);
+        output += 3;
+        ii++;
+      }
+    }
+    *output = '\0';
+  }
+  return buf;
+}
+
+/** Decode an IP address from base64.
+ * @param[in] input Input buffer to decode.
+ * @param[out] addr IP address structure to populate.
+ */
+void base64toip(const char* input, struct irc_in_addr* addr)
+{
+  memset(addr, 0, sizeof(*addr));
+  if (strlen(input) == 6) {
+    unsigned int in = base64toint(input);
+    /* An all-zero address should stay that way. */
+    if (in) {
+      addr->in6_16[5] = htons(65535);
+      addr->in6_16[6] = htons(in >> 16);
+      addr->in6_16[7] = htons(in & 65535);
+    }
+  } else {
+    unsigned int pos = 0;
+    do {
+      if (*input == '_') {
+        unsigned int left;
+        for (left = (25 - strlen(input)) / 3 - pos; left; left--)
+          addr->in6_16[pos++] = 0;
+        input++;
+      } else {
+        unsigned short accum = convert2n[(unsigned char)*input++];
+        accum = (accum << NUMNICKLOG) | convert2n[(unsigned char)*input++];
+        accum = (accum << NUMNICKLOG) | convert2n[(unsigned char)*input++];
+        addr->in6_16[pos++] = ntohs(accum);
+      }
+    } while (pos < 8);
+  }
+}
diff --git a/ircd/opercmds.c b/ircd/opercmds.c
new file mode 100644 (file)
index 0000000..98def17
--- /dev/null
@@ -0,0 +1,118 @@
+/*
+ * IRC - Internet Relay Chat, ircd/opercmds.c (formerly ircd/s_serv.c)
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ *                    University of Oulu, Computing Center
+ *
+ * See file AUTHORS in IRC package for additional names of
+ * the programmers.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+/** @file
+ * @brief Implementation of AsLL ping helper commands.
+ * @version $Id: opercmds.c 1210 2004-10-03 16:34:03Z entrope $
+ */
+#include "config.h"
+
+#include "opercmds.h"
+#include "class.h"
+#include "client.h"
+#include "ircd.h"
+#include "ircd_chattr.h"
+#include "ircd_reply.h"
+#include "ircd_string.h"
+#include "listener.h"
+#include "match.h"
+#include "msg.h"
+#include "numeric.h"
+#include "numnicks.h"
+#include "s_conf.h"
+#include "send.h"
+#include "struct.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/time.h>
+
+/** Calculate current time or elapsed time.
+ *
+ * If neither \a sec nor \a usec are NULL, calculate milliseconds
+ * elapsed since that time, and return a string containing that
+ * number.
+ *
+ * If either \a sec or \a usec are NULL, format a timestamp containing
+ * Unix timestamp and microseconds since that second (separated by
+ * spaces), and return a string containing that timestamp.
+ *
+ * @todo This should be made into two functions.
+ * @param[in] sec Either NULL or a Unix timestamp in seconds.
+ * @param[in] usec Either NULL or an offset to \a sec in microseconds.
+ * @return A static buffer with contents as described above.
+ */
+char *militime(char* sec, char* usec)
+{
+  struct timeval tv;
+  static char timebuf[18];
+
+  gettimeofday(&tv, NULL);
+  if (sec && usec)
+    sprintf(timebuf, "%ld",
+        (tv.tv_sec - atoi(sec)) * 1000 + (tv.tv_usec - atoi(usec)) / 1000);
+  else
+    sprintf(timebuf, "%ld %ld", tv.tv_sec, tv.tv_usec);
+  return timebuf;
+}
+
+/** Calculate current time or elapsed time.
+ *
+ * If \a start is NULL, create a timestamp containing Unix timestamp
+ * and microseconds since that second (separated by a period), and
+ * return a string containing that timestamp.
+ *
+ * Otherwise, if \a start does not contain a period, return a string
+ * equal to "0".
+ *
+ * Otherwise, calculate milliseconds elapsed since the Unix time
+ * described in \a start (in the format described above), and return a
+ * string containing that number.
+ *
+ * @todo This should be made into two functions.
+ * @param[in] start Either NULL or a Unix timestamp in
+ * pseudo-floating-point format.
+ * @return A static buffer with contents as described above.
+ */
+char *militime_float(char* start)
+{
+  struct timeval tv;
+  static char timebuf[18];
+  char *p;
+
+  gettimeofday(&tv, NULL);
+  if (start)
+  {
+    if ((p = strchr(start, '.')))
+    {
+      p++;
+      sprintf(timebuf, "%ld",
+          (tv.tv_sec - atoi(start)) * 1000 + (tv.tv_usec - atoi(p)) / 1000);
+    }
+    else
+      strcpy(timebuf, "0");
+  }
+  else
+    sprintf(timebuf, "%ld.%ld", tv.tv_sec, tv.tv_usec);
+  return timebuf;
+}
diff --git a/ircd/os_generic.c b/ircd/os_generic.c
new file mode 100644 (file)
index 0000000..cebf158
--- /dev/null
@@ -0,0 +1,717 @@
+/*
+ * IRC - Internet Relay Chat, ircd/os_generic.c
+ * Copyright (C) 1999 Thomas Helvey
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+/** @file
+ * @brief Implementation of OS-dependent operations.
+ * @version $Id: os_generic.c 1767 2007-02-28 22:38:50Z entrope $
+ */
+#include "config.h"
+
+#ifdef IRCU_SOLARIS
+/* Solaris requires C99 support for SUSv3, but C99 support breaks other
+ * parts of the build.  So fall back to SUSv2, but request IPv6 support
+ * by defining __EXTENSIONS__.
+ */
+#define _XOPEN_SOURCE   500
+#define __EXTENSIONS__  1
+#elif defined(__FreeBSD__) && __FreeBSD__ >= 5
+/* FreeBSD 6.0 requires SUSv3 to support IPv6 -- but if you ask for
+ * that specifically (by defining _XOPEN_SOURCE to anything at all),
+ * they cleverly hide IPPROTO_IPV6.  If you don't ask for anything,
+ * they give you everything.
+ */
+#else
+#define _XOPEN_SOURCE   600
+#endif
+
+#include "ircd_osdep.h"
+#include "msgq.h"
+#include "ircd_log.h"
+#include "res.h"
+#include "s_bsd.h"
+#include "sys.h"
+
+/* Include file dependency notes:
+ * FreeBSD requires struct timeval from sys/time.h before struct
+ * rusage in sys/resource.h.
+ * Solaris requires sys/time.h before struct rusage (indirectly) in
+ * netinet/in.h.
+ */
+/* #include <assert.h> -- Now using assert in ircd_log.h */
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <netinet/in.h>
+#include <sys/resource.h>
+#include <sys/socket.h>
+#include <sys/uio.h>
+
+#if HAVE_SYS_PARAM_H
+#include <sys/param.h>
+#endif
+
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#if defined(IPV6_BINDV6ONLY) &&!defined(IPV6_V6ONLY)
+# define IPV6_V6ONLY IPV6_BINDV6ONLY
+#endif
+
+#ifndef IOV_MAX
+#define IOV_MAX 16     /**< minimum required length of an iovec array */
+#endif
+
+#ifdef HPUX
+#include <sys/syscall.h>
+#define getrusage(a,b) syscall(SYS_GETRUSAGE, a, b)
+#endif
+
+static int is_blocked(int error)
+{
+  return EWOULDBLOCK == error
+#ifdef ENOMEM
+    || ENOMEM == error
+#endif
+#ifdef ENOBUFS
+    || ENOBUFS == error
+#endif
+    || EAGAIN == error;
+}
+
+static void sockaddr_in_to_irc(const struct sockaddr_in *v4,
+                               struct irc_sockaddr *irc)
+{
+    memset(&irc->addr, 0, 5*sizeof(int16_t));
+    irc->addr.in6_16[5] = 0xffff;
+    memcpy(&irc->addr.in6_16[6], &v4->sin_addr, sizeof(v4->sin_addr));
+    irc->port = ntohs(v4->sin_port);
+}
+
+
+#ifdef IPV6
+/** Native socket address type. */
+#define sockaddr_native sockaddr_in6
+/** Field name inside sockaddr_native to find address family. */
+#define sn_family sin6_family
+
+/** Convert native socket address to IRC format.
+ * @param[in] v6 Native socket address.
+ * @param[out] irc IRC format socket address.
+ */
+void sockaddr_to_irc(const struct sockaddr_in6 *v6, struct irc_sockaddr *irc)
+{
+    if (v6->sin6_family == AF_INET6) {
+        memcpy(&irc->addr.in6_16[0], &v6->sin6_addr, sizeof(v6->sin6_addr));
+        irc->port = ntohs(v6->sin6_port);
+    }
+    else if (v6->sin6_family == AF_INET) {
+        sockaddr_in_to_irc((struct sockaddr_in *)v6, irc);
+    }
+    else assert(0 && "Unhandled native address family");
+}
+
+/** Convert IRC socket address to native format.
+ * @param[out] v6 Native socket address.
+ * @param[in] irc IRC socket address.
+ * @param[in] compat_fd If non-negative, an FD specifying address family.
+ * @return Length of address written to \a v6.
+ */
+int sockaddr_from_irc(struct sockaddr_in6 *v6, const struct irc_sockaddr *irc, int compat_fd, int family)
+{
+    struct sockaddr_in6 sin6;
+    socklen_t slen;
+
+    assert(irc != 0);
+    slen = sizeof(sin6);
+    if (family) {
+        /* accept whatever user specified */
+    } else if ((0 <= compat_fd)
+        && (0 == getsockname(compat_fd, (struct sockaddr*)&sin6, &slen)))
+        family = sin6.sin6_family;
+    else if ((irc == &VirtualHost_v4) || irc_in_addr_is_ipv4(&irc->addr))
+        family = AF_INET;
+    else
+        family = AF_INET6;
+
+    memset(v6, 0, sizeof(*v6));
+    if (family == AF_INET) {
+        struct sockaddr_in *v4 = (struct sockaddr_in*)v6;
+        v4->sin_family = AF_INET;
+        memcpy(&v4->sin_addr, &irc->addr.in6_16[6], sizeof(v4->sin_addr));
+        v4->sin_port = htons(irc->port);
+        return sizeof(*v4);
+    }
+    else {
+        v6->sin6_family = AF_INET6;
+        memcpy(&v6->sin6_addr, &irc->addr.in6_16[0], sizeof(v6->sin6_addr));
+        v6->sin6_port = htons(irc->port);
+        return sizeof(*v6);
+    }
+}
+
+#else
+#define sockaddr_native sockaddr_in
+#define sn_family sin_family
+#define sockaddr_to_irc sockaddr_in_to_irc
+
+int sockaddr_from_irc(struct sockaddr_in *v4, const struct irc_sockaddr *irc, int compat_fd, int family)
+{
+    assert(irc != 0);
+    memset(v4, 0, sizeof(*v4));
+    v4->sin_family = AF_INET;
+    if (irc) {
+        assert(!irc->addr.in6_16[0] && !irc->addr.in6_16[1] && !irc->addr.in6_16[2] && !irc->addr.in6_16[3] && !irc->addr.in6_16[4] && (!irc->addr.in6_16[5] || irc->addr.in6_16[5] == 0xffff));
+        memcpy(&v4->sin_addr, &irc->addr.in6_16[6], sizeof(v4->sin_addr));
+        v4->sin_port = htons(irc->port);
+    }
+    (void)compat_fd; (void)family;
+    return sizeof(*v4);
+}
+
+#endif
+
+#ifdef DEBUGMODE
+/** Send resource usage information to an enumerator function.
+ * @param[in] cptr Client requesting information.
+ * @param[in] uptime Wall time in seconds since the server started.
+ * @param[in] enumerator Function to call to send a line to \a cptr.
+ * @return Zero if some usage reports could not be sent, non-zero on success.
+ */
+int os_get_rusage(struct Client *cptr, int uptime, EnumFn enumerator)
+{
+#ifdef HAVE_GETRUSAGE
+  char buf[256];
+  struct rusage rus;
+  time_t secs;
+
+#ifdef  hz
+#  define hzz hz
+#else
+#  ifdef HZ
+#    define hzz HZ
+#  else
+  int hzz = 1;
+#  ifdef HPUX
+  hzz = sysconf(_SC_CLK_TCK);
+#  endif
+#endif
+#endif
+
+  assert(0 != enumerator);
+  if (getrusage(RUSAGE_SELF, &rus) == -1)
+    return 0;
+
+  secs = rus.ru_utime.tv_sec + rus.ru_stime.tv_sec;
+  if (secs == 0)
+    secs = 1;
+
+  sprintf(buf, "CPU Secs %ld:%ld User %ld:%ld System %ld:%ld",
+          (long)(secs / 60), (long)(secs % 60),
+          rus.ru_utime.tv_sec / 60, rus.ru_utime.tv_sec % 60,
+          rus.ru_stime.tv_sec / 60, rus.ru_stime.tv_sec % 60);
+  (*enumerator)(cptr, buf);
+
+  sprintf(buf, "RSS %ld ShMem %ld Data %ld Stack %ld",
+          rus.ru_maxrss,
+          rus.ru_ixrss / (uptime * hzz), rus.ru_idrss / (uptime * hzz),
+          rus.ru_isrss / (uptime * hzz));
+  (*enumerator)(cptr, buf);
+
+  sprintf(buf, "Swaps %ld Reclaims %ld Faults %ld",
+          rus.ru_nswap, rus.ru_minflt, rus.ru_majflt);
+  (*enumerator)(cptr, buf);
+
+  sprintf(buf, "Block in %ld out %ld", rus.ru_inblock, rus.ru_oublock);
+  (*enumerator)(cptr, buf);
+
+  sprintf(buf, "Msg Rcv %ld Send %ld", rus.ru_msgrcv, rus.ru_msgsnd);
+  (*enumerator)(cptr, buf);
+
+  sprintf(buf, "Signals %ld Context Vol. %ld Invol %ld",
+          rus.ru_nsignals, rus.ru_nvcsw, rus.ru_nivcsw);
+  (*enumerator)(cptr, buf);
+
+#else /* HAVE_GETRUSAGE */
+#if HAVE_TIMES
+  char buf[256];
+  struct tms tmsbuf;
+  time_t secs, mins;
+  int hzz = 1, ticpermin;
+  int umin, smin, usec, ssec;
+
+  assert(0 != enumerator);
+#ifdef HPUX
+  hzz = sysconf(_SC_CLK_TCK);
+#endif
+  ticpermin = hzz * 60;
+
+  umin = tmsbuf.tms_utime / ticpermin;
+  usec = (tmsbuf.tms_utime % ticpermin) / (float)hzz;
+  smin = tmsbuf.tms_stime / ticpermin;
+  ssec = (tmsbuf.tms_stime % ticpermin) / (float)hzz;
+  secs = usec + ssec;
+  mins = (secs / 60) + umin + smin;
+  secs %= hzz;
+
+  if (times(&tmsbuf) == -1)
+    return 0;
+  secs = tmsbuf.tms_utime + tmsbuf.tms_stime;
+
+  sprintf(buf, "CPU Secs %d:%d User %d:%d System %d:%d", 
+          mins, secs, umin, usec, smin, ssec);
+  (*enumerator)(cptr, buf);
+#endif /* HAVE_TIMES */
+#endif /* HAVE_GETRUSAGE */
+  return 1;
+}
+#endif
+
+/** Look up the most recent socket error for a socket file descriptor.
+ * @param[in] fd File descriptor to check.
+ * @return Error code from the socket, or 0 if the OS does not support this.
+ */
+int os_get_sockerr(int fd)
+{
+  int    err = 0;
+#if defined(SO_ERROR)
+  unsigned int len = sizeof(err);
+  getsockopt(fd, SOL_SOCKET, SO_ERROR, &err, &len);
+#endif
+  return err;
+}
+
+/** Set a file descriptor to non-blocking mode.
+ * @param[in] fd %Socket file descriptor.
+ * @return Non-zero on success, or zero on failure.
+ */
+int os_set_nonblocking(int fd)
+{
+  int res;
+#ifndef NBLOCK_SYSV
+  int nonb = 0;
+#endif
+
+  /*
+   * NOTE: consult ALL your relevant manual pages *BEFORE* changing
+   * these ioctl's. There are quite a few variations on them,
+   * as can be seen by the PCS one. They are *NOT* all the same.
+   * Heed this well. - Avalon.
+   */
+#ifdef  NBLOCK_POSIX
+  nonb |= O_NONBLOCK;
+#endif
+#ifdef  NBLOCK_BSD
+  nonb |= O_NDELAY;
+#endif
+#ifdef  NBLOCK_SYSV
+  /* This portion of code might also apply to NeXT. -LynX */
+  res = 1;
+
+  if (ioctl(fd, FIONBIO, &res) == -1)
+    return 0;
+#else
+  if ((res = fcntl(fd, F_GETFL, 0)) == -1)
+    return 0;
+  else if (fcntl(fd, F_SETFL, res | nonb) == -1)
+    return 0;
+#endif
+  return 1;
+}
+
+/** Mark a socket's address as reusable.
+ * @param[in] fd %Socket file descriptor to manipulate.
+ * @return Non-zero on success, or zero on failure.
+ */
+int os_set_reuseaddr(int fd)
+{
+  unsigned int opt = 1;
+  return (0 == setsockopt(fd, SOL_SOCKET, SO_REUSEADDR,
+                          (const char*) &opt, sizeof(opt)));
+}
+
+/** Set a socket's send and receive buffer sizes.
+ * @param[in] fd %Socket file descriptor to manipulate.
+ * @param[in] ssize New send buffer size.
+ * @param[in] rsize New receive buffer size.
+ * @return Non-zero on success, or zero on failure.
+ */
+int os_set_sockbufs(int fd, unsigned int ssize, unsigned int rsize)
+{
+  unsigned int sopt = ssize;
+  unsigned int ropt = rsize;
+  return (0 == setsockopt(fd, SOL_SOCKET, SO_RCVBUF,
+                          (const char*) &ropt, sizeof(ropt)) &&
+          0 == setsockopt(fd, SOL_SOCKET, SO_SNDBUF,
+                          (const char*) &sopt, sizeof(sopt)));
+}
+
+/** Set a socket's "type of service" value.
+ * @param[in] fd %Socket file descriptor to manipulate.
+ * @param[in] tos New type of service value to use.
+ * @return Non-zero on success, or zero on failure.
+ */
+int os_set_tos(int fd,int tos)
+{
+#if defined(IP_TOS) && defined(IPPROTO_IP)
+  unsigned int opt = tos;
+  return (0 == setsockopt(fd, IPPROTO_IP, IP_TOS, &opt, sizeof(opt)));
+#else
+  return 1;
+#endif
+}
+
+/** Disable IP options on a socket.
+ * @param[in] fd %Socket file descriptor to manipulate.
+ * @return Non-zero on success, or zero on failure.
+ */
+int os_disable_options(int fd)
+{
+#if defined(IP_OPTIONS) && defined(IPPROTO_IP)
+  return (0 == setsockopt(fd, IPPROTO_IP, IP_OPTIONS, NULL, 0));
+#else
+  return 1;
+#endif
+}
+
+/*
+ * Try and find the correct name to use with getrlimit() for setting the max.
+ * number of files allowed to be open by this process.
+ */
+#ifdef RLIMIT_FDMAX
+#define RLIMIT_FD_MAX   RLIMIT_FDMAX
+#else
+#ifdef RLIMIT_NOFILE
+#define RLIMIT_FD_MAX RLIMIT_NOFILE
+#else
+#ifdef RLIMIT_OPEN_MAX
+#define RLIMIT_FD_MAX RLIMIT_OPEN_MAX
+#else
+#undef RLIMIT_FD_MAX
+#endif
+#endif
+#endif
+
+/** Set file descriptor limit for the process.
+ * @param[in] max_descriptors Ideal number of file descriptors.
+ * @return Zero on success; -1 on error; positive number of possible
+ * file descriptors if \a max_descriptors is too high.
+ */
+int os_set_fdlimit(unsigned int max_descriptors)
+{
+#if defined(HAVE_SETRLIMIT) && defined(RLIMIT_FD_MAX)
+  struct rlimit limit;
+
+  if (!getrlimit(RLIMIT_FD_MAX, &limit)) {
+    if (limit.rlim_max < max_descriptors)
+      return limit.rlim_max;
+    if(limit.rlim_max == RLIM_INFINITY)
+      limit.rlim_cur = max_descriptors;
+    else
+      limit.rlim_cur = limit.rlim_max;    /* make soft limit the max */
+    return setrlimit(RLIMIT_FD_MAX, &limit);
+  }
+#endif /* defined(HAVE_SETRLIMIT) && defined(RLIMIT_FD_MAX) */
+  return 0;
+}
+
+/** Attempt to read from a non-blocking socket.
+ * @param[in] fd File descriptor to read from.
+ * @param[out] buf Output buffer to read into.
+ * @param[in] length Number of bytes to read.
+ * @param[out] count_out Receives number of bytes actually read.
+ * @return An IOResult value indicating status.
+ */
+IOResult os_recv_nonb(int fd, char* buf, unsigned int length,
+                 unsigned int* count_out)
+{
+  int res;
+  assert(0 != buf);
+  assert(0 != count_out);
+
+  if (0 < (res = recv(fd, buf, length, 0))) {
+    *count_out = (unsigned) res;
+    return IO_SUCCESS;
+  } else if (res == 0) {
+    *count_out = 0;
+    errno = 0; /* or ECONNRESET? */
+    return IO_FAILURE;
+  } else {
+    *count_out = 0;
+    return is_blocked(errno) ? IO_BLOCKED : IO_FAILURE;
+  }
+}
+
+/** Attempt to read from a non-blocking UDP socket.
+ * @param[in] fd File descriptor to read from.
+ * @param[out] buf Output buffer to read into.
+ * @param[in] length Number of bytes to read.
+ * @param[out] length_out Receives number of bytes actually read.
+ * @param[out] addr_out Peer address that sent the message.
+ * @return An IOResult value indicating status.
+ */
+IOResult os_recvfrom_nonb(int fd, char* buf, unsigned int length,
+                          unsigned int* length_out,
+                          struct irc_sockaddr* addr_out)
+{
+  struct sockaddr_native addr;
+  unsigned int len = sizeof(addr);
+  int    res;
+  assert(0 != buf);
+  assert(0 != length_out);
+  assert(0 != addr_out);
+
+  res = recvfrom(fd, buf, length, 0, (struct sockaddr*) &addr, &len);
+  if (-1 < res) {
+    sockaddr_to_irc(&addr, addr_out);
+    *length_out = res;
+    return IO_SUCCESS;
+  } else {
+    *length_out = 0;
+    return is_blocked(errno) ? IO_BLOCKED : IO_FAILURE;
+  }
+}
+
+/** Attempt to write on a non-blocking UDP socket.
+ * @param[in] fd File descriptor to write to.
+ * @param[in] buf Output buffer to send from.
+ * @param[in] length Number of bytes to write.
+ * @param[out] count_out Receives number of bytes actually written.
+ * @param[in] flags Flags for call to sendto().
+ * @param[in] peer Destination address of the message.
+ * @return An IOResult value indicating status.
+ */
+IOResult os_sendto_nonb(int fd, const char* buf, unsigned int length,
+                        unsigned int* count_out, unsigned int flags,
+                        const struct irc_sockaddr* peer)
+{
+  struct sockaddr_native addr;
+  int res, size;
+  assert(0 != buf);
+
+  size = sockaddr_from_irc(&addr, peer, fd, 0);
+  assert((addr.sn_family == AF_INET) == irc_in_addr_is_ipv4(&peer->addr));
+  if (-1 < (res = sendto(fd, buf, length, flags, (struct sockaddr*)&addr, size))) {
+    if (count_out)
+      *count_out = (unsigned) res;
+    return IO_SUCCESS;
+  } else {
+    if (count_out)
+      *count_out = 0;
+    return is_blocked(errno) ? IO_BLOCKED : IO_FAILURE;
+  }
+}
+
+/** Attempt to write on a connected socket.
+ * @param[in] fd File descriptor to write to.
+ * @param[in] buf Output buffer to send from.
+ * @param[in] length Number of bytes to write.
+ * @param[out] count_out Receives number of bytes actually written.
+ * @return An IOResult value indicating status.
+ */
+IOResult os_send_nonb(int fd, const char* buf, unsigned int length, 
+                 unsigned int* count_out)
+{
+  int res;
+  assert(0 != buf);
+  assert(0 != count_out);
+
+  if (-1 < (res = send(fd, buf, length, 0))) {
+    *count_out = (unsigned) res;
+    return IO_SUCCESS;
+  } else {
+    *count_out = 0;
+    return is_blocked(errno) ? IO_BLOCKED : IO_FAILURE;
+  }
+}
+
+/** Attempt a vectored write on a connected socket.
+ * @param[in] fd File descriptor to write to.
+ * @param[in] buf Message queue to send from.
+ * @param[out] count_in Number of bytes mapped from \a buf.
+ * @param[out] count_out Receives number of bytes actually written.
+ * @return An IOResult value indicating status.
+ */
+IOResult os_sendv_nonb(int fd, struct MsgQ* buf, unsigned int* count_in,
+                      unsigned int* count_out)
+{
+  int res;
+  int count;
+  struct iovec iov[IOV_MAX];
+
+  assert(0 != buf);
+  assert(0 != count_in);
+  assert(0 != count_out);
+
+  *count_in = 0;
+  count = msgq_mapiov(buf, iov, IOV_MAX, count_in);
+
+  if (-1 < (res = writev(fd, iov, count))) {
+    *count_out = (unsigned) res;
+    return IO_SUCCESS;
+  } else {
+    *count_out = 0;
+    return is_blocked(errno) ? IO_BLOCKED : IO_FAILURE;
+  }
+}
+
+/** Open a TCP or UDP socket on a particular address.
+ * @param[in] local Local address to bind to.
+ * @param[in] type SOCK_STREAM or SOCK_DGRAM.
+ * @param[in] port_name Port name (used in error diagnostics).
+ * @param[in] family A specific address family to use, or 0 for automatic.
+ * @return Bound descriptor, or -1 on error.
+ */
+int os_socket(const struct irc_sockaddr* local, int type, const char* port_name, int family)
+{
+  struct sockaddr_native addr;
+  int size, fd;
+
+  assert(local != 0);
+  size = sockaddr_from_irc(&addr, local, -1, family);
+  fd = socket(addr.sn_family, type, 0);
+  if (fd < 0) {
+    report_error(SOCKET_ERROR_MSG, port_name, errno);
+    return -1;
+  }
+  if (fd > MAXCLIENTS - 1) {
+    report_error(CONNLIMIT_ERROR_MSG, port_name, 0);
+    close(fd);
+    return -1;
+  }
+  if (!os_set_reuseaddr(fd)) {
+    report_error(REUSEADDR_ERROR_MSG, port_name, errno);
+    close(fd);
+    return -1;
+  }
+  if (!os_set_nonblocking(fd)) {
+    report_error(NONB_ERROR_MSG, port_name, errno);
+    close(fd);
+    return -1;
+  }
+  if (local) {
+#if defined(IPV6_V6ONLY)
+    int on = 1;
+    if (family == AF_INET6 && irc_in_addr_unspec(&local->addr))
+      setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on));
+#endif
+    if (bind(fd, (struct sockaddr*)&addr, size)) {
+      report_error(BIND_ERROR_MSG, port_name, errno);
+      close(fd);
+      return -1;
+    }
+  }
+  return fd;
+}
+
+/** Accept a connection on a socket.
+ * @param[in] fd Listening file descriptor.
+ * @param[out] peer Peer address of connection.
+ * @return File descriptor for accepted connection.
+ */
+int os_accept(int fd, struct irc_sockaddr* peer)
+{
+  struct sockaddr_native addr;
+  socklen_t addrlen;
+  int new_fd;
+
+  addrlen = sizeof(addr);
+  new_fd = accept(fd, (struct sockaddr*)&addr, &addrlen);
+  if (new_fd < 0)
+    memset(peer, 0, sizeof(*peer));
+  else
+    sockaddr_to_irc(&addr, peer);
+  return new_fd;
+}
+
+/** Start a non-blocking connection.
+ * @param[in] fd Disconnected file descriptor.
+ * @param[in] sin Target address for connection.
+ * @return IOResult code indicating status.
+ */
+IOResult os_connect_nonb(int fd, const struct irc_sockaddr* sin)
+{
+  struct sockaddr_native addr;
+  int size;
+
+  size = sockaddr_from_irc(&addr, sin, fd, 0);
+  if (0 == connect(fd, (struct sockaddr*) &addr, size))
+    return IO_SUCCESS;
+  else if (errno == EINPROGRESS)
+    return IO_BLOCKED;
+  else
+    return IO_FAILURE;
+}
+
+/** Get local address of a socket.
+ * @param[in] fd File descriptor to operate on.
+ * @param[out] sin_out Receives local socket address.
+ * @return Non-zero on success; zero on error.
+ */
+int os_get_sockname(int fd, struct irc_sockaddr* sin_out)
+{
+  struct sockaddr_native addr;
+  unsigned int len = sizeof(addr);
+
+  assert(0 != sin_out);
+  if (getsockname(fd, (struct sockaddr*) &addr, &len))
+    return 0;
+  sockaddr_to_irc(&addr, sin_out);
+  return 1;
+}
+
+/** Get remote address of a socket.
+ * @param[in] fd File descriptor to operate on.
+ * @param[out] sin_out Receives remote socket address.
+ * @return Non-zero on success; zero on error.
+ */
+int os_get_peername(int fd, struct irc_sockaddr* sin_out)
+{
+  struct sockaddr_native addr;
+  unsigned int len = sizeof(addr);
+
+  assert(0 != sin_out);
+  if (getpeername(fd, (struct sockaddr*) &addr, &len))
+    return 0;
+  sockaddr_to_irc(&addr, sin_out);
+  return 1;
+}
+
+/** Start listening on a socket.
+ * @param[in] fd Disconnected file descriptor.
+ * @param[in] backlog Maximum number of un-accept()ed connections to keep.
+ * @return Non-zero on success; zero on error.
+ */
+int os_set_listen(int fd, int backlog)
+{
+  return (0 == listen(fd, backlog));
+}
+
+/** Allocate a connected pair of local sockets.
+ * @param[out] sv Array of two file descriptors.
+ * @return Zero on success; non-zero number on error.
+ */
+int os_socketpair(int sv[2])
+{
+    return socketpair(AF_UNIX, SOCK_STREAM, 0, sv);
+}
diff --git a/ircd/packet.c b/ircd/packet.c
new file mode 100644 (file)
index 0000000..676da47
--- /dev/null
@@ -0,0 +1,188 @@
+/*
+ * IRC - Internet Relay Chat, common/packet.c
+ * Copyright (C) 1990  Jarkko Oikarinen and
+ *                     University of Oulu, Computing Center
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+/** @file
+ * @brief Input packet handling functions.
+ * @version $Id: packet.c 1271 2004-12-11 05:14:07Z klmitch $
+ */
+#include "config.h"
+
+#include "packet.h"
+#include "client.h"
+#include "ircd.h"
+#include "ircd_chattr.h"
+#include "ircd_log.h"
+#include "parse.h"
+#include "s_bsd.h"
+#include "s_misc.h"
+#include "send.h"
+
+/* #include <assert.h> -- Now using assert in ircd_log.h */
+
+/** Add a certain number of bytes to a client's received statistics.
+ * @param[in,out] cptr Client to update.
+ * @param[in] length Number of newly received bytes to add.
+ */
+static void update_bytes_received(struct Client* cptr, unsigned int length)
+{
+  cli_receiveB(&me)  += length;     /* Update bytes received */
+  cli_receiveB(cptr) += length;
+}
+
+/** Add one message to a client's received statistics.
+ * @param[in,out] cptr Client to update.
+ */
+static void update_messages_received(struct Client* cptr)
+{
+  ++(cli_receiveM(&me));
+  ++(cli_receiveM(cptr));
+}
+
+/** Handle received data from a directly connected server.
+ * @param[in] cptr Peer server that sent us data.
+ * @param[in] buffer Input buffer.
+ * @param[in] length Number of bytes in input buffer.
+ * @return 1 on success or CPTR_KILLED if the client is squit.
+ */
+int server_dopacket(struct Client* cptr, const char* buffer, int length)
+{
+  const char* src;
+  char*       endp;
+  char*       client_buffer;
+
+  assert(0 != cptr);
+
+  update_bytes_received(cptr, length);
+
+  client_buffer = cli_buffer(cptr);
+  endp = client_buffer + cli_count(cptr);
+  src = buffer;
+
+  while (length-- > 0) {
+    *endp = *src++;
+    /*
+     * Yuck.  Stuck.  To make sure we stay backward compatible,
+     * we must assume that either CR or LF terminates the message
+     * and not CR-LF.  By allowing CR or LF (alone) into the body
+     * of messages, backward compatibility is lost and major
+     * problems will arise. - Avalon
+     */
+    if (IsEol(*endp)) {
+      if (endp == client_buffer)
+        continue;               /* Skip extra LF/CR's */
+      *endp = '\0';
+
+      update_messages_received(cptr);
+
+      if (parse_server(cptr, cli_buffer(cptr), endp) == CPTR_KILLED)
+        return CPTR_KILLED;
+      /*
+       *  Socket is dead so exit
+       */
+      if (IsDead(cptr))
+        return exit_client(cptr, cptr, &me, cli_info(cptr));
+      endp = client_buffer;
+    }
+    else if (endp < client_buffer + BUFSIZE)
+      ++endp;                   /* There is always room for the null */
+  }
+  cli_count(cptr) = endp - cli_buffer(cptr);
+  return 1;
+}
+
+/** Handle received data from a new (unregistered) connection.
+ * @param[in] cptr Unregistered connection that sent us data.
+ * @param[in] buffer Input buffer.
+ * @param[in] length Number of bytes in input buffer.
+ * @return 1 on success or CPTR_KILLED if the client is squit.
+ */
+int connect_dopacket(struct Client *cptr, const char *buffer, int length)
+{
+  const char* src;
+  char*       endp;
+  char*       client_buffer;
+
+  assert(0 != cptr);
+
+  update_bytes_received(cptr, length);
+
+  client_buffer = cli_buffer(cptr);
+  endp = client_buffer + cli_count(cptr);
+  src = buffer;
+
+  while (length-- > 0)
+  {
+    *endp = *src++;
+    /*
+     * Yuck.  Stuck.  To make sure we stay backward compatible,
+     * we must assume that either CR or LF terminates the message
+     * and not CR-LF.  By allowing CR or LF (alone) into the body
+     * of messages, backward compatibility is lost and major
+     * problems will arise. - Avalon
+     */
+    if (IsEol(*endp))
+    {
+      /* Skip extra LF/CR's */
+      if (endp == client_buffer)
+        continue;
+      *endp = '\0';
+
+      update_messages_received(cptr);
+
+      if (parse_client(cptr, cli_buffer(cptr), endp) == CPTR_KILLED)
+        return CPTR_KILLED;
+      /* Socket is dead so exit */
+      if (IsDead(cptr))
+        return exit_client(cptr, cptr, &me, cli_info(cptr));
+      else if (IsServer(cptr))
+      {
+        cli_count(cptr) = 0;
+        return server_dopacket(cptr, src, length);
+      }
+      endp = client_buffer;
+    }
+    else if (endp < client_buffer + BUFSIZE)
+      /* There is always room for the null */
+      ++endp;
+  }
+  cli_count(cptr) = endp - cli_buffer(cptr);
+  return 1;
+}
+
+/** Handle received data from a local client.
+ * @param[in] cptr Local client that sent us data.
+ * @param[in] length Total number of bytes in client's input buffer.
+ * @return 1 on success or CPTR_KILLED if the client is squit.
+ */
+int client_dopacket(struct Client *cptr, unsigned int length)
+{
+  assert(0 != cptr);
+
+  update_bytes_received(cptr, length);
+  update_messages_received(cptr);
+
+  if (CPTR_KILLED == parse_client(cptr, cli_buffer(cptr), cli_buffer(cptr) + length))
+    return CPTR_KILLED;
+  else if (IsDead(cptr))
+    return exit_client(cptr, cptr, &me, cli_info(cptr));
+
+  return 1;
+}
+
+
diff --git a/ircd/parse.c b/ircd/parse.c
new file mode 100644 (file)
index 0000000..8a58d5b
--- /dev/null
@@ -0,0 +1,1447 @@
+/*
+ * IRC - Internet Relay Chat, common/parse.c
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ *                    University of Oulu, Computing Center
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+/** @file
+ * @brief Parse input from IRC clients and other servers.
+ * @version $Id: parse.c 1827 2007-08-14 03:02:24Z entrope $
+ */
+#include "config.h"
+
+#include "parse.h"
+#include "client.h"
+#include "channel.h"
+#include "handlers.h"
+#include "hash.h"
+#include "ircd.h"
+#include "ircd_alloc.h"
+#include "ircd_chattr.h"
+#include "ircd_features.h"
+#include "ircd_log.h"
+#include "ircd_reply.h"
+#include "ircd_string.h"
+#include "msg.h"
+#include "numeric.h"
+#include "numnicks.h"
+#include "opercmds.h"
+#include "querycmds.h"
+#include "res.h"
+#include "s_bsd.h"
+#include "s_conf.h"
+#include "s_debug.h"
+#include "s_misc.h"
+#include "s_numeric.h"
+#include "s_user.h"
+#include "send.h"
+#include "struct.h"
+#include "sys.h"
+#include "whocmds.h"
+#include "whowas.h"
+
+/* #include <assert.h> -- Now using assert in ircd_log.h */
+#include <string.h>
+#include <stdlib.h>
+
+/*
+ * Message Tree stuff mostly written by orabidoo, with changes by Dianora.
+ * Adapted to Undernet, adding token support, etc by comstud 10/06/97
+ *
+ * completely rewritten June 2, 2003 - Dianora
+ *
+ * This has always just been a trie. Look at volume III of Knuth ACP
+ *
+ *
+ * ok, you start out with an array of pointers, each one corresponds
+ * to a letter at the current position in the command being examined.
+ *
+ * so roughly you have this for matching 'trie' or 'tie'
+ *
+ * 't' points -> [MessageTree *] 'r' -> [MessageTree *] -> 'i'
+ *   -> [MessageTree *] -> [MessageTree *] -> 'e' and matches
+ *
+ *                              'i' -> [MessageTree *] -> 'e' and matches
+ */
+
+/** Number of children under a trie node. */
+#define MAXPTRLEN      32      /* Must be a power of 2, and
+                                * larger than 26 [a-z]|[A-Z]
+                                * its used to allocate the set
+                                * of pointers at each node of the tree
+                                * There are MAXPTRLEN pointers at each node.
+                                * Obviously, there have to be more pointers
+                                * Than ASCII letters. 32 is a nice number
+                                * since there is then no need to shift
+                                * 'A'/'a' to base 0 index, at the expense
+                                * of a few never used pointers. For a small
+                                * parser like this, this is a good compromise
+                                * and does make it somewhat faster.
+                                *
+                                * - Dianora
+                                */
+
+/** Node in the command lookup trie. */
+struct MessageTree {
+  struct Message *msg; /**< Message (if any) if the string ends now. */
+  struct MessageTree *pointers[MAXPTRLEN]; /**< Child nodes for each letter. */
+};
+
+/** Root of command lookup trie. */
+static struct MessageTree msg_tree;
+static struct MessageTree tok_tree;
+
+/** Array of all supported commands. */
+struct Message msgtab[] = {
+  {
+    MSG_PRIVATE,
+    TOK_PRIVATE,
+    0, MAXPARA, MFLG_SLOW, 0, NULL,
+    /* UNREG, CLIENT, SERVER, OPER, SERVICE */
+    { m_unregistered, m_privmsg, ms_privmsg, mo_privmsg, m_ignore }
+  },
+  {
+    MSG_NICK,
+    TOK_NICK,
+    0, MAXPARA, MFLG_SLOW | MFLG_UNREG, 0, NULL,
+    /* UNREG, CLIENT, SERVER, OPER, SERVICE */
+    { m_nick, m_nick, ms_nick, m_nick, m_ignore }
+  },
+  {
+    MSG_NOTICE,
+    TOK_NOTICE,
+    0, MAXPARA, MFLG_SLOW | MFLG_IGNORE, 0, NULL,
+    /* UNREG, CLIENT, SERVER, OPER, SERVICE */
+    { m_ignore, m_notice, ms_notice, mo_notice, m_ignore }
+  },
+  {
+    MSG_WALLCHOPS,
+    TOK_WALLCHOPS,
+    0, MAXPARA, MFLG_SLOW, 0, NULL,
+    /* UNREG, CLIENT, SERVER, OPER, SERVICE */
+    { m_unregistered, m_wallchops, ms_wallchops, m_wallchops, m_ignore }
+  },
+  {
+    MSG_WALLVOICES,
+    TOK_WALLVOICES,
+    0, MAXPARA, MFLG_SLOW, 0, NULL,
+    /* UNREG, CLIENT, SERVER, OPER, SERVICE */
+    { m_unregistered, m_wallvoices, ms_wallvoices, m_wallvoices, m_ignore }
+  },
+  {
+    MSG_CPRIVMSG,
+    TOK_CPRIVMSG,
+    0, MAXPARA, MFLG_SLOW, 0, NULL,
+    /* UNREG, CLIENT, SERVER, OPER, SERVICE */
+    { m_unregistered, m_cprivmsg, m_ignore, m_cprivmsg, m_ignore }
+  },
+  {
+    MSG_CNOTICE,
+    TOK_CNOTICE,
+    0, MAXPARA, MFLG_SLOW, 0, NULL,
+    /* UNREG, CLIENT, SERVER, OPER, SERVICE */
+    { m_unregistered, m_cnotice, m_ignore, m_cnotice, m_ignore }
+  },
+  {
+    MSG_JOIN,
+    TOK_JOIN,
+    0, MAXPARA, MFLG_SLOW, 0, NULL,
+    /* UNREG, CLIENT, SERVER, OPER, SERVICE */
+    { m_unregistered, m_join, ms_join, m_join, m_ignore }
+  },
+  {
+    MSG_MODE,
+    TOK_MODE,
+    0, MAXPARA, MFLG_SLOW, 0, NULL,
+    /* UNREG, CLIENT, SERVER, OPER, SERVICE */
+    { m_unregistered, m_mode, ms_mode, m_mode, m_ignore }
+  },
+  {
+    MSG_BURST,
+    TOK_BURST,
+    0, MAXPARA, MFLG_SLOW, 0, NULL,
+    /* UNREG, CLIENT, SERVER, OPER, SERVICE */
+    { m_ignore, m_ignore, ms_burst, m_ignore, m_ignore }
+  },
+  {
+    MSG_CREATE,
+    TOK_CREATE,
+    0, MAXPARA, MFLG_SLOW, 0, NULL,
+    /* UNREG, CLIENT, SERVER, OPER, SERVICE */
+    { m_ignore, m_ignore, ms_create, m_ignore, m_ignore }
+  },
+  {
+    MSG_DESTRUCT,
+    TOK_DESTRUCT,
+    0, MAXPARA, MFLG_SLOW, 0, NULL,
+    /* UNREG, CLIENT, SERVER, OPER, SERVICE */
+    { m_ignore, m_ignore, ms_destruct, m_ignore, m_ignore }
+  },
+  {
+    MSG_QUIT,
+    TOK_QUIT,
+    0, MAXPARA, MFLG_SLOW | MFLG_UNREG, 0, NULL,
+    /* UNREG, CLIENT, SERVER, OPER, SERVICE */
+    { m_quit, m_quit, ms_quit, m_quit, m_ignore }
+  },
+  {
+    MSG_PART,
+    TOK_PART,
+    0, MAXPARA, MFLG_SLOW, 0, NULL,
+    /* UNREG, CLIENT, SERVER, OPER, SERVICE */
+    { m_unregistered, m_part, ms_part, m_part, m_ignore }
+  },
+  {
+    MSG_TOPIC,
+    TOK_TOPIC,
+    0, MAXPARA, MFLG_SLOW, 0, NULL,
+    /* UNREG, CLIENT, SERVER, OPER, SERVICE */
+    { m_unregistered, m_topic, ms_topic, m_topic, m_ignore }
+  },
+  {
+    MSG_INVITE,
+    TOK_INVITE,
+    0, MAXPARA, MFLG_SLOW, 0, NULL,
+    /* UNREG, CLIENT, SERVER, OPER, SERVICE */
+    { m_unregistered, m_invite, ms_invite, m_invite, m_ignore }
+  },
+  {
+    MSG_KICK,
+    TOK_KICK,
+    0, MAXPARA, MFLG_SLOW, 0, NULL,
+    /* UNREG, CLIENT, SERVER, OPER, SERVICE */
+    { m_unregistered, m_kick, ms_kick, m_kick, m_ignore }
+  },
+  {
+    MSG_WALLOPS,
+    TOK_WALLOPS,
+    0, MAXPARA, MFLG_SLOW, 0, NULL,
+    /* UNREG, CLIENT, SERVER, OPER, SERVICE */
+    { m_unregistered, m_not_oper, ms_wallops, mo_wallops, m_ignore }
+  },
+  {
+    MSG_WALLUSERS,
+    TOK_WALLUSERS,
+    0, MAXPARA, MFLG_SLOW, 0, NULL,
+    /* UNREG, CLIENT, SERVER, OPER, SERVICE */
+    { m_unregistered, m_not_oper, ms_wallusers, mo_wallusers, m_ignore }
+  },
+  {
+    MSG_DESYNCH,
+    TOK_DESYNCH,
+    0, MAXPARA, MFLG_SLOW, 0, NULL,
+    /* UNREG, CLIENT, SERVER, OPER, SERVICE */
+    { m_ignore, m_ignore, ms_desynch, m_ignore, m_ignore }
+  },
+  {
+    MSG_PING,
+    TOK_PING,
+    0, MAXPARA, MFLG_SLOW, 0, NULL,
+    /* UNREG, CLIENT, SERVER, OPER, SERVICE */
+    { m_unregistered, m_ping, ms_ping, mo_ping, m_ignore }
+  },
+  {
+    MSG_PONG,
+    TOK_PONG,
+    0, MAXPARA, MFLG_SLOW | MFLG_UNREG, 0, NULL,
+    /* UNREG, CLIENT, SERVER, OPER, SERVICE */
+    { mr_pong, m_pong, ms_pong, m_pong, m_ignore }
+  },
+  {
+    MSG_ERROR,
+    TOK_ERROR,
+    0, MAXPARA, MFLG_SLOW | MFLG_UNREG, 0, NULL,
+    /* UNREG, CLIENT, SERVER, OPER, SERVICE */
+    { mr_error, m_ignore, ms_error, m_ignore, m_ignore }
+  },
+  {
+    MSG_KILL,
+    TOK_KILL,
+    0, MAXPARA, MFLG_SLOW, 0, NULL,
+    /* UNREG, CLIENT, SERVER, OPER, SERVICE */
+    { m_unregistered, m_not_oper, ms_kill, mo_kill, m_ignore }
+  },
+  {
+    MSG_USER,
+    TOK_USER,
+    0, MAXPARA, MFLG_SLOW, 0, NULL,
+    /* UNREG, CLIENT, SERVER, OPER, SERVICE */
+    { m_user, m_registered, m_ignore, m_registered, m_ignore }
+  },
+  {
+    MSG_AWAY,
+    TOK_AWAY,
+    0, MAXPARA, MFLG_SLOW, 0, NULL,
+    /* UNREG, CLIENT, SERVER, OPER, SERVICE */
+    { m_unregistered, m_away, ms_away, m_away, m_ignore }
+  },
+  {
+    MSG_ISON,
+    TOK_ISON,
+    0, 1, MFLG_SLOW, 0, NULL,
+    /* UNREG, CLIENT, SERVER, OPER, SERVICE */
+    { m_unregistered, m_ison, m_ignore, m_ison, m_ignore }
+  },
+  {
+    MSG_SERVER,
+    TOK_SERVER,
+    0, MAXPARA, MFLG_SLOW | MFLG_UNREG, 0, NULL,
+    /* UNREG, CLIENT, SERVER, OPER, SERVICE */
+    { mr_server, m_registered, ms_server, m_registered, m_ignore }
+  },
+  {
+    MSG_SQUIT,
+    TOK_SQUIT,
+    0, MAXPARA, MFLG_SLOW, 0, NULL,
+    /* UNREG, CLIENT, SERVER, OPER, SERVICE */
+    { m_unregistered, m_not_oper, ms_squit, mo_squit, m_ignore }
+  },
+  {
+    MSG_WHOIS,
+    TOK_WHOIS,
+    0, MAXPARA, MFLG_SLOW, 0, NULL,
+    /* UNREG, CLIENT, SERVER, OPER, SERVICE */
+    { m_unregistered, m_whois, ms_whois, m_whois, m_ignore }
+  },
+  {
+    MSG_WHO,
+    TOK_WHO,
+    0, MAXPARA, MFLG_SLOW, 0, NULL,
+    /* UNREG, CLIENT, SERVER, OPER, SERVICE */
+    { m_unregistered, m_who, m_ignore, m_who, m_ignore }
+  },
+  {
+    MSG_WHOWAS,
+    TOK_WHOWAS,
+    0, MAXPARA, MFLG_SLOW, 0, NULL,
+    /* UNREG, CLIENT, SERVER, OPER, SERVICE */
+    { m_unregistered, m_whowas, m_whowas, m_whowas, m_ignore }
+  },
+  {
+    MSG_LIST,
+    TOK_LIST,
+    0, MAXPARA, MFLG_SLOW, 0, NULL,
+    /* UNREG, CLIENT, SERVER, OPER, SERVICE */
+    { m_unregistered, m_list, m_ignore, m_list, m_ignore }
+  },
+  {
+    MSG_NAMES,
+    TOK_NAMES,
+    0, MAXPARA, MFLG_SLOW, 0, NULL,
+    /* UNREG, CLIENT, SERVER, OPER, SERVICE */
+    { m_unregistered, m_names, m_names, m_names, m_ignore }
+  },
+  {
+    MSG_USERHOST,
+    TOK_USERHOST,
+    0, 1, MFLG_SLOW, 0, NULL,
+    /* UNREG, CLIENT, SERVER, OPER, SERVICE */
+    { m_unregistered, m_userhost, m_ignore, m_userhost, m_ignore }
+  },
+  {
+    MSG_USERIP,
+    TOK_USERIP,
+    0, 1, MFLG_SLOW, 0, NULL,
+    /* UNREG, CLIENT, SERVER, OPER, SERVICE */
+    { m_unregistered, m_userip, m_ignore, m_userip, m_ignore }
+  },
+  {
+    MSG_TRACE,
+    TOK_TRACE,
+    0, MAXPARA, MFLG_SLOW, 0, NULL,
+    /* UNREG, CLIENT, SERVER, OPER, SERVICE */
+    { m_unregistered, m_trace, ms_trace, mo_trace, m_ignore }
+  },
+  {
+    MSG_PASS,
+    TOK_PASS,
+    0, MAXPARA, MFLG_SLOW | MFLG_UNREG, 0, NULL,
+    /* UNREG, CLIENT, SERVER, OPER, SERVICE */
+    { mr_pass, m_registered, m_ignore, m_registered, m_ignore }
+  },
+  {
+    MSG_LUSERS,
+    TOK_LUSERS,
+    0, MAXPARA, MFLG_SLOW, 0, NULL,
+    /* UNREG, CLIENT, SERVER, OPER, SERVICE */
+    { m_unregistered, m_lusers, ms_lusers, m_lusers, m_ignore }
+  },
+  {
+    MSG_TIME,
+    TOK_TIME,
+    0, MAXPARA, MFLG_SLOW, 0, NULL,
+    /* UNREG, CLIENT, SERVER, OPER, SERVICE */
+    { m_unregistered, m_time, m_time, m_time, m_ignore }
+  },
+  {
+    MSG_SETTIME,
+    TOK_SETTIME,
+    0, MAXPARA, MFLG_SLOW, 0, NULL,
+    /* UNREG, CLIENT, SERVER, OPER, SERVICE */
+    { m_unregistered, m_not_oper, ms_settime, mo_settime, m_ignore }
+  },
+  {
+    MSG_RPING,
+    TOK_RPING,
+    0, MAXPARA, MFLG_SLOW, 0, NULL,
+    /* UNREG, CLIENT, SERVER, OPER, SERVICE */
+    { m_unregistered, m_not_oper, ms_rping, mo_rping, m_ignore }
+  },
+  {
+    MSG_RPONG,
+    TOK_RPONG,
+    0, MAXPARA, MFLG_SLOW, 0, NULL,
+    /* UNREG, CLIENT, SERVER, OPER, SERVICE */
+    { m_unregistered, m_ignore, ms_rpong, m_ignore, m_ignore }
+  },
+  {
+    MSG_OPER,
+    TOK_OPER,
+    0, MAXPARA, MFLG_SLOW, 0, NULL,
+    /* UNREG, CLIENT, SERVER, OPER, SERVICE */
+    { m_unregistered, m_oper, ms_oper, mo_oper, m_ignore }
+  },
+  {
+    MSG_CONNECT,
+    TOK_CONNECT,
+    0, MAXPARA, MFLG_SLOW, 0, NULL,
+    /* UNREG, CLIENT, SERVER, OPER, SERVICE */
+    { m_unregistered, m_not_oper, ms_connect, mo_connect, m_ignore }
+  },
+  {
+    MSG_MAP,
+    TOK_MAP,
+    0, MAXPARA, MFLG_SLOW, 0, NULL,
+    /* UNREG, CLIENT, SERVER, OPER, SERVICE */
+    { m_unregistered, m_map, m_ignore, m_map, m_ignore }
+  },
+  {
+    MSG_VERSION,
+    TOK_VERSION,
+    0, MAXPARA, MFLG_SLOW | MFLG_UNREG, 0, NULL,
+    /* UNREG, CLIENT, SERVER, OPER, SERVICE */
+    { m_version, m_version, ms_version, mo_version, m_ignore }
+  },
+  {
+    MSG_STATS,
+    TOK_STATS,
+    0, MAXPARA, MFLG_SLOW, 0, NULL,
+    /* UNREG, CLIENT, SERVER, OPER, SERVICE */
+    { m_unregistered, m_stats, m_stats, m_stats, m_ignore }
+  },
+  {
+    MSG_LINKS,
+    TOK_LINKS,
+    0, MAXPARA, MFLG_SLOW, 0, NULL,
+    /* UNREG, CLIENT, SERVER, OPER, SERVICE */
+    { m_unregistered, m_links, ms_links, m_links, m_ignore }
+  },
+  {
+    MSG_ADMIN,
+    TOK_ADMIN,
+    0, MAXPARA, MFLG_SLOW | MFLG_UNREG, 0,  NULL,
+    /* UNREG, CLIENT, SERVER, OPER, SERVICE */
+    { m_admin, m_admin, ms_admin, mo_admin, m_ignore }
+  },
+  {
+    MSG_HELP,
+    TOK_HELP,
+    0, MAXPARA, MFLG_SLOW, 0, NULL,
+    /* UNREG, CLIENT, SERVER, OPER, SERVICE */
+    { m_unregistered, m_help, m_ignore, m_help, m_ignore }
+  },
+  {
+    MSG_INFO,
+    TOK_INFO,
+    0, MAXPARA, MFLG_SLOW, 0, NULL,
+    /* UNREG, CLIENT, SERVER, OPER, SERVICE */
+    { m_unregistered, m_info, ms_info, mo_info, m_ignore }
+  },
+  {
+    MSG_MOTD,
+    TOK_MOTD,
+    0, MAXPARA, MFLG_SLOW, 0, NULL,
+    /* UNREG, CLIENT, SERVER, OPER, SERVICE */
+    { m_unregistered, m_motd, m_motd, m_motd, m_ignore }
+  },
+  {
+    MSG_CLOSE,
+    TOK_CLOSE,
+    0, MAXPARA, MFLG_SLOW, 0, NULL,
+    /* UNREG, CLIENT, SERVER, OPER, SERVICE */
+    { m_unregistered, m_not_oper, m_ignore, mo_close, m_ignore }
+  },
+  {
+    MSG_SILENCE,
+    TOK_SILENCE,
+    0, MAXPARA, MFLG_SLOW, 0, NULL,
+    /* UNREG, CLIENT, SERVER, OPER, SERVICE */
+    { m_unregistered, m_silence, ms_silence, m_silence, m_ignore }
+  },
+  {
+    MSG_GLINE,
+    TOK_GLINE,
+    0, MAXPARA,         0, 0, NULL,
+    /* UNREG, CLIENT, SERVER, OPER, SERVICE */
+    { m_unregistered, m_gline, ms_gline, mo_gline, m_ignore }
+  },
+  {
+    MSG_JUPE,
+    TOK_JUPE,
+    0, MAXPARA, MFLG_SLOW, 0, NULL,
+    /* UNREG, CLIENT, SERVER, OPER, SERVICE */
+    { m_unregistered, m_not_oper, ms_jupe, mo_jupe, m_ignore }
+  },
+  {
+    MSG_OPMODE,
+    TOK_OPMODE,
+    0, MAXPARA, MFLG_SLOW, 0, NULL,
+    /* UNREG, CLIENT, SERVER, OPER, SERVICE */
+    { m_unregistered, mo_opmode, ms_opmode, mo_opmode, m_ignore }
+  },
+  {
+    MSG_CLEARMODE,
+    TOK_CLEARMODE,
+    0, MAXPARA, MFLG_SLOW, 0, NULL,
+    /* UNREG, CLIENT, SERVER, OPER, SERVICE */
+    { m_unregistered, m_not_oper, ms_clearmode, mo_clearmode, m_ignore }
+  },
+  {
+    MSG_UPING,
+    TOK_UPING,
+    0, MAXPARA, MFLG_SLOW, 0, NULL,
+    /* UNREG, CLIENT, SERVER, OPER, SERVICE */
+    { m_unregistered, m_not_oper, ms_uping, mo_uping, m_ignore }
+  },
+  {
+    MSG_END_OF_BURST,
+    TOK_END_OF_BURST,
+    0, MAXPARA, MFLG_SLOW, 0, NULL,
+    /* UNREG, CLIENT, SERVER, OPER, SERVICE */
+    { m_ignore, m_ignore, ms_end_of_burst, m_ignore, m_ignore }
+  },
+  {
+    MSG_END_OF_BURST_ACK,
+    TOK_END_OF_BURST_ACK,
+    0, MAXPARA, MFLG_SLOW, 0, NULL,
+    /* UNREG, CLIENT, SERVER, OPER, SERVICE */
+    { m_ignore, m_ignore, ms_end_of_burst_ack, m_ignore, m_ignore }
+  },
+  {
+    MSG_HASH,
+    TOK_HASH,
+    0, MAXPARA, MFLG_SLOW, 0, NULL,
+    /* UNREG, CLIENT, SERVER, OPER, SERVICE */
+    { m_unregistered, m_hash, m_hash, m_hash, m_ignore }
+  },
+  {
+    MSG_REHASH,
+    TOK_REHASH,
+    0, MAXPARA, MFLG_SLOW, 0, NULL,
+    /* UNREG, CLIENT, SERVER, OPER, SERVICE */
+    { m_unregistered, m_not_oper, ms_rehash, mo_rehash, m_ignore }
+  },
+  {
+    MSG_RESTART,
+    TOK_RESTART,
+    0, MAXPARA, MFLG_SLOW, 0, NULL,
+    /* UNREG, CLIENT, SERVER, OPER, SERVICE */
+    { m_unregistered, m_not_oper, m_ignore, mo_restart, m_ignore }
+  },
+  {
+    MSG_DIE,
+    TOK_DIE,
+    0, MAXPARA, MFLG_SLOW, 0, NULL,
+    /* UNREG, CLIENT, SERVER, OPER, SERVICE */
+    { m_unregistered, m_not_oper, m_ignore, mo_die, m_ignore }
+  },
+  {
+    MSG_PROTO,
+    TOK_PROTO,
+    0, MAXPARA, MFLG_SLOW, 0, NULL,
+    /* UNREG, CLIENT, SERVER, OPER, SERVICE */
+    { m_proto, m_proto, m_proto, m_proto, m_ignore }
+  },
+  {
+    MSG_SET,
+    TOK_SET,
+    0, MAXPARA, MFLG_SLOW, 0, NULL,
+    /* UNREG, CLIENT, SERVER, OPER, SERVICE */
+    { m_unregistered, m_not_oper, m_ignore, mo_set, m_ignore }
+  },
+  {
+    MSG_RESET,
+    TOK_RESET,
+    0, MAXPARA, MFLG_SLOW, 0, NULL,
+    /* UNREG, CLIENT, SERVER, OPER, SERVICE */
+    { m_unregistered, m_not_oper, m_ignore, mo_reset, m_ignore }
+  },
+  {
+    MSG_GET,
+    TOK_GET,
+    0, MAXPARA, MFLG_SLOW, 0, NULL,
+    /* UNREG, CLIENT, SERVER, OPER, SERVICE */
+    { m_unregistered, m_not_oper, m_ignore, mo_get, m_ignore }
+  },
+  {
+    MSG_PRIVS,
+    TOK_PRIVS,
+    0, MAXPARA, MFLG_SLOW, 0, NULL,
+    /* UNREG, CLIENT, SERVER, OPER, SERVICE */
+    { m_unregistered, m_privs, ms_privs, m_privs, m_ignore }
+  },
+  {
+    MSG_ACCOUNT,
+    TOK_ACCOUNT,
+    0, MAXPARA, MFLG_SLOW, 0, NULL,
+    /* UNREG, CLIENT, SERVER, OPER, SERVICE */
+    { m_ignore, m_ignore, ms_account, m_ignore, m_ignore }
+  },
+  {
+    MSG_ASLL,
+    TOK_ASLL,
+    0, MAXPARA, MFLG_SLOW, 0, NULL,
+    /* UNREG, CLIENT, SERVER, OPER, SERVICE */
+    { m_ignore, m_not_oper, ms_asll, mo_asll, m_ignore }
+   },
+#if WE_HAVE_A_REAL_CAPABILITY_NOW
+  {
+    MSG_CAP,
+    TOK_CAP,
+    0, MAXPARA, 0, 0, NULL,
+    /* UNREG, CLIENT, SERVER, OPER, SERVICE */
+    { m_cap, m_cap, m_ignore, m_cap, m_ignore }
+  },
+#endif
+  {
+    MSG_FAKEHOST,
+    TOK_FAKEHOST,
+    0, MAXPARA, MFLG_SLOW, 0, NULL,
+    /* UNREG, CLIENT, SERVER, OPER, SERVICE */
+    { m_ignore, m_not_oper, ms_fakehost, m_fakehost, m_ignore }
+  },
+  {
+    MSG_FAKEHOST_OLD,
+    TOK_FAKEHOST_OLD,
+    0, MAXPARA, MFLG_SLOW, 0, NULL,
+    /* UNREG, CLIENT, SERVER, OPER, SERVICE */
+    { m_ignore, m_not_oper, ms_fakehost_old, m_fakehost, m_ignore }
+  },
+  {
+    MSG_HIDEHOST,
+    TOK_HIDEHOST,
+    0, MAXPARA, MFLG_SLOW, 0, NULL,
+    /* UNREG, CLIENT, SERVER, OPER, SERVICE */
+    { m_ignore, m_ignore, ms_hidehost, m_ignore, m_ignore }
+   },
+  {
+    MSG_SVSMODE,
+    TOK_SVSMODE,
+    0, MAXPARA, MFLG_SLOW, 0, NULL,
+    /* UNREG, CLIENT, SERVER, OPER, SERVICE */
+    { m_ignore, m_ignore, ms_svsmode, m_svsmode, m_ignore }
+  },
+  {
+    MSG_SVSNICK,
+    TOK_SVSNICK,
+    0, MAXPARA, MFLG_SLOW, 0, NULL,
+    /* UNREG, CLIENT, SERVER, OPER, SERVICE */
+    { m_ignore, m_ignore, ms_svsnick, m_svsnick, m_ignore }
+  },
+  {
+    MSG_SVSNICK_OLD,
+    TOK_SVSNICK_OLD,
+    0, MAXPARA, MFLG_SLOW, 0, NULL,
+    /* UNREG, CLIENT, SERVER, OPER, SERVICE */
+    { m_ignore, m_ignore, ms_svsnick_old, m_svsnick, m_ignore }
+  },
+  {
+    MSG_SVSJOIN,
+    TOK_SVSJOIN,
+    0, MAXPARA, MFLG_SLOW, 0, NULL,
+    /* UNREG, CLIENT, SERVER, OPER, SERVICE */
+    { m_ignore, m_ignore, ms_svsjoin, m_svsjoin, m_ignore }
+  },
+  {
+    MSG_WEBIRC,
+    TOK_WEBIRC,
+    0, MAXPARA, MFLG_SLOW, 0, NULL,
+    /* UNREG, CLIENT, SERVER, OPER, SERVICE */
+    { m_webirc, m_registered, m_ignore, m_registered, m_ignore }
+  },
+  {
+    MSG_RELAY,
+    TOK_RELAY,
+    0, MAXPARA, MFLG_SLOW, 0, NULL,
+    /* UNREG, CLIENT, SERVER, OPER, SERVICE */
+    { m_ignore, m_ignore, ms_relay, m_ignore, m_ignore }
+  },
+  {
+    MSG_CHECK,
+    TOK_CHECK,
+    0, MAXPARA, MFLG_SLOW, 0, NULL,
+    /* UNREG, CLIENT, SERVER, OPER, SERVICE */
+    { m_ignore, m_not_oper, m_ignore, mo_check, m_ignore }
+  },
+  /* This command is an alias for QUIT during the unregistered part of
+   * of the server.  This is because someone jumping via a broken web
+   * proxy will send a 'POST' as their first command - which we will
+   * obviously disconnect them immediately for, stopping people abusing
+   * open gateways
+   */
+  {
+    MSG_POST,
+    TOK_POST,
+    0, MAXPARA, MFLG_SLOW, 0, NULL,
+    /* UNREG, CLIENT, SERVER, OPER, SERVICE */
+    { m_quit, m_ignore, m_ignore, m_ignore, m_ignore }
+  },
+  { 0 }
+};
+
+/** Array of command parameters. */
+static char *para[MAXPARA + 2]; /* leave room for prefix and null */
+
+
+/** Add a message to the lookup trie.
+ * @param[in,out] mtree_p Trie node to insert under.
+ * @param[in] msg_p Message to insert.
+ * @param[in] cmd Text of command to insert.
+ */
+void
+add_msg_element(struct MessageTree *mtree_p, struct Message *msg_p, char *cmd)
+{
+  struct MessageTree *ntree_p;
+
+  if (*cmd == '\0')
+  {
+    mtree_p->msg = msg_p;
+    return;
+  }
+
+  if ((ntree_p = mtree_p->pointers[*cmd & (MAXPTRLEN-1)]) != NULL)
+  {
+    add_msg_element(ntree_p, msg_p, cmd+1);
+  }
+  else
+  {
+    ntree_p = (struct MessageTree *)MyCalloc(sizeof(struct MessageTree), 1);
+    mtree_p->pointers[*cmd & (MAXPTRLEN-1)] = ntree_p;
+    add_msg_element(ntree_p, msg_p, cmd+1);
+  }
+}
+
+/** Remove a message from the lookup trie.
+ * @param[in,out] mtree_p Trie node to remove command from.
+ * @param[in] cmd Text of command to remove.
+ */
+struct MessageTree *
+del_msg_element(struct MessageTree *mtree_p, char *cmd)
+{
+  int slot = *cmd & (MAXPTRLEN-1);
+
+  /* Either remove leaf message or from appropriate child. */
+  if (*cmd == '\0')
+    mtree_p->msg = NULL;
+  else
+    mtree_p->pointers[slot] = del_msg_element(mtree_p->pointers[slot], cmd + 1);
+
+  /* If current message or any child still exists, keep this node. */
+  if (mtree_p->msg)
+    return mtree_p;
+  for (slot = 0; slot < MAXPTRLEN; ++slot)
+    if (mtree_p->pointers[slot])
+      return mtree_p;
+
+  /* Otherwise, if we're not a root node, free it and return null. */
+  if (mtree_p != &msg_tree && mtree_p != &tok_tree)
+    MyFree(mtree_p);
+  return NULL;
+}
+
+/** Initialize the message lookup trie with all known commands. */
+void
+initmsgtree(void)
+{
+  int i;
+
+  memset(&msg_tree, 0, sizeof(msg_tree));
+  memset(&tok_tree, 0, sizeof(tok_tree));
+
+  for (i = 0; msgtab[i].cmd != NULL ; i++)
+  {
+    add_msg_element(&msg_tree, &msgtab[i], msgtab[i].cmd);
+    add_msg_element(&tok_tree, &msgtab[i], msgtab[i].tok);
+  }
+}
+
+/** Look up a command in the message trie.
+ * @param cmd Text of command to look up.
+ * @param root Root of message trie.
+ * @return Pointer to matching message, or NULL if non exists.
+ */
+static struct Message *
+msg_tree_parse(char *cmd, struct MessageTree *root)
+{
+  struct MessageTree *mtree;
+
+  for (mtree = root; mtree; mtree = mtree->pointers[(*cmd++) & (MAXPTRLEN-1)]) {
+      if (*cmd == '\0' && mtree->msg)
+          return mtree->msg;
+      else if (!IsAlpha(*cmd))
+          return NULL;
+  }
+  return NULL;
+}
+
+/** Registers a service mapping to the pseudocommand handler.
+ * @param[in] map Service mapping to add.
+ * @return Non-zero on success; zero if a command already used the name.
+ */
+int register_mapping(struct s_map *map)
+{
+  struct Message *msg;
+
+  if (msg_tree_parse(map->command, &msg_tree))
+    return 0;
+
+  msg = (struct Message *)MyMalloc(sizeof(struct Message));
+  msg->cmd = map->command;
+  msg->tok = map->command;
+  msg->count = 0;
+  msg->parameters = 2;
+  msg->flags = MFLG_EXTRA;
+  if (!(map->flags & SMAP_FAST))
+    msg->flags |= MFLG_SLOW;
+  msg->bytes = 0;
+  msg->extra = map;
+
+  msg->handlers[UNREGISTERED_HANDLER] = m_ignore;
+  msg->handlers[CLIENT_HANDLER] = m_pseudo;
+  msg->handlers[SERVER_HANDLER] = m_ignore;
+  msg->handlers[OPER_HANDLER]   = m_pseudo;
+  msg->handlers[SERVICE_HANDLER] = m_ignore;
+
+  add_msg_element(&msg_tree, msg, msg->cmd);
+  map->msg = msg;
+
+  return 1;
+}
+
+/** Removes a service mapping.
+ * @param[in] map Service mapping to remove.
+ * @return Non-zero on success; zero if no command used the name.
+ */
+int unregister_mapping(struct s_map *map)
+{
+  if (!msg_tree_parse(map->command, &msg_tree))
+  {
+    /* This simply should never happen. */
+    assert(0);
+    return 0;
+  }
+
+  del_msg_element(&msg_tree, map->msg->cmd);
+
+  map->msg->extra = NULL;
+  MyFree(map->msg);
+  map->msg = NULL;
+
+  return 1;
+}
+
+/** Parse a line of data from a user.
+ * NOTE: parse_*() should not be called recursively by any other
+ * functions!
+ * @param[in] cptr Client that sent the data.
+ * @param[in] buffer Start of input line.
+ * @param[in] bufend End of input line.
+ * @return 0 on success, -1 on parse error, or CPTR_KILLED if message
+ * handler returns it.
+ */
+int
+parse_client(struct Client *cptr, char *buffer, char *bufend)
+{
+  struct Client*  from = cptr;
+  char*           ch;
+  char*           s;
+  int             i;
+  int             paramcount;
+  int             noprefix = 0;
+  struct Message* mptr;
+  MessageHandler  handler = 0;
+
+  Debug((DEBUG_DEBUG, "Client Parsing: %s", buffer));
+
+  if (IsDead(cptr))
+    return 0;
+
+  para[0] = cli_name(from);
+  for (ch = buffer; *ch == ' '; ch++);  /* Eat leading spaces */
+  if (*ch == ':')               /* Is any client doing this ? */
+  {
+    for (++ch; *ch && *ch != ' '; ++ch)
+      ; /* Ignore sender prefix from client */
+    while (*ch == ' ')
+      ch++;                     /* Advance to command */
+  }
+  else
+    noprefix = 1;
+  if (*ch == '\0')
+  {
+    ServerStats->is_empt++;
+    Debug((DEBUG_NOTICE, "Empty message from host %s:%s",
+        cli_name(cptr), cli_name(from)));
+    return (-1);
+  }
+
+  if ((s = strchr(ch, ' ')))
+    *s++ = '\0';
+
+  if ((mptr = msg_tree_parse(ch, &msg_tree)) == NULL)
+  {
+    /*
+     * Note: Give error message *only* to recognized
+     * persons. It's a nightmare situation to have
+     * two programs sending "Unknown command"'s or
+     * equivalent to each other at full blast....
+     * If it has got to person state, it at least
+     * seems to be well behaving. Perhaps this message
+     * should never be generated, though...  --msa
+     * Hm, when is the buffer empty -- if a command
+     * code has been found ?? -Armin
+     */
+    if (buffer[0] != '\0')
+    {
+      if (IsUser(from)) {
+          struct Client *acptr;
+          if(feature_bool(FEAT_UNKNOWN_CMD_ENABLE) && feature_str(FEAT_UNKNOWN_CMD_TARGET) && (acptr = FindUser(feature_str(FEAT_UNKNOWN_CMD_TARGET))) && IsNetServ(acptr) && IsService(cli_user(acptr)->server)) {
+           sendcmdto_one(&me, CMD_RELAY, acptr, "%C UC %C %s :%s", acptr, from, ch, s);
+          } else {
+           send_reply(from, ERR_UNKNOWNCOMMAND, ch);
+          }
+         }
+      Debug((DEBUG_ERROR, "Unknown (%s) from %s",
+            ch, get_client_name(cptr, HIDE_IP)));
+    }
+    ServerStats->is_unco++;
+    return (-1);
+  }
+
+  paramcount = mptr->parameters;
+  i = bufend - ((s) ? s : ch);
+  mptr->bytes += i;
+  if ((mptr->flags & MFLG_SLOW) || (!IsAnOper(cptr) && !HasPriv(cptr, PRIV_FLOOD))) {
+    if(HasPriv(cptr, PRIV_HALFFLOOD))
+      cli_since(cptr) += 1;
+    else
+      cli_since(cptr) += (2 + i / 120);
+  }
+
+  /*
+   * Allow only 1 msg per 2 seconds
+   * (on average) to prevent dumping.
+   * to keep the response rate up,
+   * bursts of up to 5 msgs are allowed
+   * -SRB
+   */
+
+  /*
+   * Must the following loop really be so devious? On
+   * surface it splits the message to parameters from
+   * blank spaces. But, if paramcount has been reached,
+   * the rest of the message goes into this last parameter
+   * (about same effect as ":" has...) --msa
+   */
+
+  /* Note initially true: s==NULL || *(s-1) == '\0' !! */
+
+  if (mptr->flags & MFLG_EXTRA) {
+    /* This is a horrid kludge to avoid changing the command handler
+     * argument list. */
+    para[1] = (char*)mptr->extra;
+    i = 1;
+  } else {
+    i = 0;
+  }
+  if (s)
+  {
+    if (paramcount > MAXPARA)
+      paramcount = MAXPARA;
+    for (;;)
+    {
+      /*
+       * Never "FRANCE " again!! ;-) Clean
+       * out *all* blanks.. --msa
+       */
+      while (*s == ' ')
+        *s++ = '\0';
+
+      if (*s == '\0')
+        break;
+      if (*s == ':')
+      {
+        /*
+         * The rest is single parameter--can
+         * include blanks also.
+         */
+        para[++i] = s + 1;
+        break;
+      }
+      para[++i] = s;
+      if (i >= paramcount)
+        break;
+      for (; *s != ' ' && *s; s++);
+    }
+  }
+  para[++i] = NULL;
+  ++mptr->count;
+
+  handler = mptr->handlers[cli_handler(cptr)];
+  assert(0 != handler);
+
+  if (!feature_bool(FEAT_IDLE_FROM_MSG) && IsUser(cptr) &&
+      handler != m_ping && handler != m_ignore)
+    cli_user(from)->last = CurrentTime;
+
+  return (*handler) (cptr, from, i, para);
+}
+
+int
+parse_simul_client(struct Client *cptr, char *buffer)
+{
+  struct Client*  from = cptr;
+  char*           ch;
+  char*           s;
+  int             i;
+  int             paramcount;
+  int             noprefix = 0;
+  struct Message* mptr;
+  MessageHandler  handler = 0;
+
+  Debug((DEBUG_DEBUG, "Client Parsing: %s", buffer));
+
+  if (IsDead(cptr))
+    return 0;
+
+  para[0] = cli_name(from);
+  for (ch = buffer; *ch == ' '; ch++);  /* Eat leading spaces */
+  if (*ch == ':')               /* Is any client doing this ? */
+  {
+    for (++ch; *ch && *ch != ' '; ++ch)
+      ; /* Ignore sender prefix from client */
+    while (*ch == ' ')
+      ch++;                     /* Advance to command */
+  }
+  else
+    noprefix = 1;
+  if (*ch == '\0')
+  {
+    ServerStats->is_empt++;
+    Debug((DEBUG_NOTICE, "Empty message from host %s:%s",
+        cli_name(cptr), cli_name(from)));
+    return (-1);
+  }
+
+  if ((s = strchr(ch, ' ')))
+    *s++ = '\0';
+
+  if ((mptr = msg_tree_parse(ch, &msg_tree)) == NULL)
+  {
+    /*
+     * Note: Give error message *only* to recognized
+     * persons. It's a nightmare situation to have
+     * two programs sending "Unknown command"'s or
+     * equivalent to each other at full blast....
+     * If it has got to person state, it at least
+     * seems to be well behaving. Perhaps this message
+     * should never be generated, though...  --msa
+     * Hm, when is the buffer empty -- if a command
+     * code has been found ?? -Armin
+     */
+    if (buffer[0] != '\0')
+    {
+      Debug((DEBUG_ERROR, "Unknown (%s) from %s",
+            ch, get_client_name(cptr, HIDE_IP)));
+    }
+    ServerStats->is_unco++;
+    return (-1);
+  }
+
+  paramcount = mptr->parameters;
+
+  /*
+   * Allow only 1 msg per 2 seconds
+   * (on average) to prevent dumping.
+   * to keep the response rate up,
+   * bursts of up to 5 msgs are allowed
+   * -SRB
+   */
+
+  /*
+   * Must the following loop really be so devious? On
+   * surface it splits the message to parameters from
+   * blank spaces. But, if paramcount has been reached,
+   * the rest of the message goes into this last parameter
+   * (about same effect as ":" has...) --msa
+   */
+
+  /* Note initially true: s==NULL || *(s-1) == '\0' !! */
+
+  if (mptr->flags & MFLG_EXTRA) {
+    /* This is a horrid kludge to avoid changing the command handler
+     * argument list. */
+    para[1] = (char*)mptr->extra;
+    i = 1;
+  } else {
+    i = 0;
+  }
+  if (s)
+  {
+    if (paramcount > MAXPARA)
+      paramcount = MAXPARA;
+    for (;;)
+    {
+      /*
+       * Never "FRANCE " again!! ;-) Clean
+       * out *all* blanks.. --msa
+       */
+      while (*s == ' ')
+        *s++ = '\0';
+
+      if (*s == '\0')
+        break;
+      if (*s == ':')
+      {
+        /*
+         * The rest is single parameter--can
+         * include blanks also.
+         */
+        para[++i] = s + 1;
+        break;
+      }
+      para[++i] = s;
+      if (i >= paramcount)
+        break;
+      for (; *s != ' ' && *s; s++);
+    }
+  }
+  para[++i] = NULL;
+  ++mptr->count;
+
+  handler = mptr->handlers[cli_handler(cptr)];
+  assert(0 != handler);
+
+  if (!feature_bool(FEAT_IDLE_FROM_MSG) && IsUser(cptr) &&
+      handler != m_ping && handler != m_ignore)
+    cli_user(from)->last = CurrentTime;
+
+  return (*handler) (cptr, from, i, para);
+}
+
+
+
+/** Parse a line of data from a server.
+ * @param[in] cptr Client that sent the data.
+ * @param[in] buffer Start of input line.
+ * @param[in] bufend End of input line.
+ * @return 0 on success, -1 on parse error, or CPTR_KILLED if message
+ * handler returns it.
+ */
+int parse_server(struct Client *cptr, char *buffer, char *bufend)
+{
+  struct Client*  from = cptr;
+  char*           ch = buffer;
+  char*           s;
+  int             len;
+  int             i;
+  int             numeric = 0;
+  int             paramcount;
+  struct Message* mptr;
+
+  Debug((DEBUG_DEBUG, "Server Parsing: %s", buffer));
+
+  if (IsDead(cptr))
+    return 0;
+
+  para[0] = cli_name(from);
+
+  /*
+   * A server ALWAYS sends a prefix. When it starts with a ':' it's the
+   * protocol 9 prefix: a nick or a server name. Otherwise it's a numeric
+   * nick or server
+   */
+  if (*ch == ':')
+  {
+    /* Let para[0] point to the name of the sender */
+    para[0] = ch + 1;
+    if (!(ch = strchr(ch, ' ')))
+      return -1;
+    *ch++ = '\0';
+
+    /* And let `from' point to its client structure,
+       opps.. a server is _also_ a client --Nem */
+    from = FindClient(para[0]);
+
+    /*
+     * If the client corresponding to the
+     * prefix is not found. We must ignore it,
+     * it is simply a lagged message traveling
+     * upstream a SQUIT that removed the client
+     * --Run
+     */
+    if (from == NULL)
+    {
+      Debug((DEBUG_NOTICE, "Unknown prefix (%s)(%s) from (%s)",
+          para[0], buffer, cli_name(cptr)));
+      ++ServerStats->is_unpf;
+      while (*ch == ' ')
+        ch++;
+      /*
+       * However, the only thing that MUST be
+       * allowed to travel upstream against an
+       * squit, is an SQUIT itself (the timestamp
+       * protects us from being used wrong)
+       */
+      if (ch[1] == 'Q')
+      {
+        para[0] = cli_name(cptr);
+        from = cptr;
+      }
+      else
+        return 0;
+    }
+    else if (cli_from(from) != cptr)
+    {
+      ++ServerStats->is_wrdi;
+      Debug((DEBUG_NOTICE, "Fake direction: Message (%s) coming from (%s)",
+          buffer, cli_name(cptr)));
+      return 0;
+    }
+  }
+  else
+  {
+    char numeric_prefix[6];
+    int  i;
+    for (i = 0; i < 5; ++i)
+    {
+      if ('\0' == ch[i] || ' ' == (numeric_prefix[i] = ch[i]))
+      {
+        break;
+      }
+    }
+    numeric_prefix[i] = '\0';
+
+    /*
+     * We got a numeric nick as prefix
+     * 1 or 2 character prefixes are from servers
+     * 3 or 5 chars are from clients
+     */
+    if (0 == i)
+    {
+      protocol_violation(cptr,"Missing Prefix");
+      from = cptr;
+    }
+    else if (' ' == ch[1] || ' ' == ch[2])
+      from = FindNServer(numeric_prefix);
+    else
+      from = findNUser(numeric_prefix);
+
+    do
+    {
+      ++ch;
+    }
+    while (*ch != ' ' && *ch);
+
+    /*
+     * If the client corresponding to the
+     * prefix is not found. We must ignore it,
+     * it is simply a lagged message traveling
+     * upstream a SQUIT that removed the client
+     * --Run
+     * There turned out to be other reasons that
+     * a prefix is unknown, needing an upstream
+     * KILL.  Also, next to an SQUIT we better
+     * allow a KILL to pass too.
+     * --Run
+     */
+    if (from == NULL)
+    {
+      ServerStats->is_unpf++;
+      while (*ch == ' ')
+        ch++;
+      if (*ch == 'N' && (ch[1] == ' ' || ch[1] == 'I'))
+        /* Only sent a KILL for a nick change */
+      {
+        struct Client *server;
+        /* Kill the unknown numeric prefix upstream if
+         * it's server still exists: */
+        if ((server = FindNServer(numeric_prefix)) && cli_from(server) == cptr)
+         sendcmdto_one(&me, CMD_KILL, cptr, "%s :%s (Unknown numeric nick)",
+                       numeric_prefix, cli_name(&me));
+      }
+      /*
+       * Things that must be allowed to travel
+       * upstream against an squit:
+       */
+      if (ch[1] == 'Q' || (*ch == 'D' && ch[1] == ' ') ||
+          (*ch == 'K' && ch[2] == 'L'))
+        from = cptr;
+      else
+        return 0;
+    }
+
+    /* Let para[0] point to the name of the sender */
+    para[0] = cli_name(from);
+
+    if (cli_from(from) != cptr)
+    {
+      ServerStats->is_wrdi++;
+      Debug((DEBUG_NOTICE, "Fake direction: Message (%s) coming from (%s)",
+          buffer, cli_name(cptr)));
+      return 0;
+    }
+  }
+
+  while (*ch == ' ')
+    ch++;
+  if (*ch == '\0')
+  {
+    ServerStats->is_empt++;
+    Debug((DEBUG_NOTICE, "Empty message from host %s:%s",
+        cli_name(cptr), cli_name(from)));
+    return (-1);
+  }
+
+  /*
+   * Extract the command code from the packet.   Point s to the end
+   * of the command code and calculate the length using pointer
+   * arithmetic.  Note: only need length for numerics and *all*
+   * numerics must have parameters and thus a space after the command
+   * code. -avalon
+   */
+  s = strchr(ch, ' ');          /* s -> End of the command code */
+  len = (s) ? (s - ch) : 0;
+  if (len == 3 && IsDigit(*ch))
+  {
+    numeric = (*ch - '0') * 100 + (*(ch + 1) - '0') * 10 + (*(ch + 2) - '0');
+    paramcount = 2; /* destination, and the rest of it */
+    ServerStats->is_num++;
+    mptr = NULL;                /* Init. to avoid stupid compiler warning :/ */
+  }
+  else
+  {
+    if (s)
+      *s++ = '\0';
+
+    /* Version      Receive         Send
+     * 2.9          Long            Long
+     * 2.10.0       Tkn/Long        Long
+     * 2.10.10      Tkn/Long        Tkn
+     * 2.10.20      Tkn             Tkn
+     *
+     * Clients/unreg servers always receive/
+     * send long commands   -record
+     *
+     * And for the record, this trie parser really does not care. - Dianora
+     */
+
+    mptr = msg_tree_parse(ch, &tok_tree);
+
+    if (mptr == NULL)
+    {
+      mptr = msg_tree_parse(ch, &msg_tree);
+    }
+
+    if (mptr == NULL)
+    {
+      /*
+       * Note: Give error message *only* to recognized
+       * persons. It's a nightmare situation to have
+       * two programs sending "Unknown command"'s or
+       * equivalent to each other at full blast....
+       * If it has got to person state, it at least
+       * seems to be well behaving. Perhaps this message
+       * should never be generated, though...   --msa
+       * Hm, when is the buffer empty -- if a command
+       * code has been found ?? -Armin
+       */
+#ifdef DEBUGMODE
+      if (buffer[0] != '\0')
+      {
+        Debug((DEBUG_ERROR, "Unknown (%s) from %s",
+              ch, get_client_name(cptr, HIDE_IP)));
+      }
+#endif
+      ServerStats->is_unco++;
+      return (-1);
+    }
+
+    paramcount = mptr->parameters;
+    i = bufend - ((s) ? s : ch);
+    mptr->bytes += i;
+  }
+  /*
+   * Must the following loop really be so devious? On
+   * surface it splits the message to parameters from
+   * blank spaces. But, if paramcount has been reached,
+   * the rest of the message goes into this last parameter
+   * (about same effect as ":" has...) --msa
+   */
+
+  /* Note initially true: s==NULL || *(s-1) == '\0' !! */
+
+  i = 0;
+  if (s)
+  {
+    if (paramcount > MAXPARA)
+      paramcount = MAXPARA;
+    for (;;)
+    {
+      /*
+       * Never "FRANCE " again!! ;-) Clean
+       * out *all* blanks.. --msa
+       */
+      while (*s == ' ')
+        *s++ = '\0';
+
+      if (*s == '\0')
+        break;
+      if (*s == ':')
+      {
+        /*
+         * The rest is single parameter--can
+         * include blanks also.
+         */
+       if (numeric)
+         para[++i] = s; /* preserve the colon to make do_numeric happy */
+       else
+         para[++i] = s + 1;
+        break;
+      }
+      para[++i] = s;
+      if (i >= paramcount)
+        break;
+      for (; *s != ' ' && *s; s++);
+    }
+  }
+  para[++i] = NULL;
+  if (numeric)
+    return (do_numeric(numeric, (*buffer != ':'), cptr, from, i, para));
+  mptr->count++;
+
+  return (*mptr->handlers[cli_handler(cptr)]) (cptr, from, i, para);
+}
diff --git a/ircd/querycmds.c b/ircd/querycmds.c
new file mode 100644 (file)
index 0000000..1b6851b
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * IRC - Internet Relay Chat, ircd/querycmds.c (formerly ircd/s_serv.c)
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ *                    University of Oulu, Computing Center
+ *
+ * See file AUTHORS in IRC package for additional names of
+ * the programmers.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+/** @file
+ * @brief Implementation of client counting functions.
+ * @version $Id: querycmds.c 1212 2004-10-03 17:02:23Z entrope $
+ */
+#include "config.h"
+
+#include "querycmds.h"
+
+#include <string.h>
+
+/** Counters of clients, servers etc. */
+struct UserStatistics UserStats;
+
+/** Initialize global #UserStats variable. */
+void init_counters(void)
+{
+  memset(&UserStats, 0, sizeof(UserStats));
+  UserStats.servers = 1;
+}
+
diff --git a/ircd/random.c b/ircd/random.c
new file mode 100644 (file)
index 0000000..4519c91
--- /dev/null
@@ -0,0 +1,109 @@
+/*
+ * IRC - Internet Relay Chat, ircd/random.c
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+/** @file
+ * @brief 32-bit pseudo-random number generator implementation.
+ * @version $Id: random.c 1235 2004-10-06 00:22:09Z entrope $
+ */
+#include "config.h"
+
+#include "random.h"
+#include "client.h"
+#include "ircd_log.h"
+#include "ircd_md5.h"
+#include "ircd_reply.h"
+#include "send.h"
+
+#include <string.h>
+#include <sys/time.h>
+
+/** Pseudo-random number generator state. */
+static struct MD5Context localkey;
+/** Next byte position in #localkey to insert at. */
+static unsigned int localkey_pos;
+
+/** Add bytes to #localkey.
+ * This should be fairly resistant to adding non-random bytes, but the
+ * more random the bytes are, the harder it is for an attacker to
+ * guess the internal state.
+ * @param[in] buf Buffer of bytes to add.
+ * @param[in] count Number of bytes to add.
+ */
+static void
+random_add_entropy(const char *buf, unsigned int count)
+{
+  while (count--) {
+    localkey.in[localkey_pos++] ^= *buf++;
+    if (localkey_pos >= sizeof(localkey.in))
+      localkey_pos = 0;
+  }
+}
+
+/** Seed the PRNG with a string.
+ * @param[in] from Client setting the seed (may be NULL).
+ * @param[in] fields Input arguments (fields[0] is used).
+ * @param[in] count Number of input arguments.
+ * @return Non-zero on success, zero on error.
+ */
+int
+random_seed_set(struct Client* from, const char* const* fields, int count)
+{
+  if (count < 1) {
+    if (from) /* send an error */
+      return need_more_params(from, "SET");
+    else {
+      log_write(LS_CONFIG, L_ERROR, 0, "Not enough fields in F line");
+      return 0;
+    }
+  }
+
+  random_add_entropy(fields[0], strlen(fields[0]));
+  return 1;
+}
+
+/** Generate a pseudo-random number.
+ * This uses the #localkey structure plus current time as input to
+ * MD5, feeding most of the MD5 output back to #localkey and using one
+ * output words as the pseudo-random output.
+ * @return A 32-bit pseudo-random number.
+ */
+unsigned int ircrandom(void)
+{
+  struct timeval tv;
+  char usec[3];
+
+  /* Add some randomness to the pool. */
+  gettimeofday(&tv, 0);
+  usec[0] = tv.tv_usec;
+  usec[1] = tv.tv_usec >> 8;
+  usec[2] = tv.tv_usec >> 16;
+  random_add_entropy(usec, 3);
+
+  /* Perform MD5 step. */
+  localkey.buf[0] = 0x67452301;
+  localkey.buf[1] = 0xefcdab89;
+  localkey.buf[2] = 0x98badcfe;
+  localkey.buf[3] = 0x10325476;
+  MD5Transform(localkey.buf, (uint32*)localkey.in);
+
+  /* Feed back 12 bytes of hash value into randomness pool. */
+  random_add_entropy((char*)localkey.buf, 12);
+
+  /* Return the final word of hash, which should not provide any
+   * useful insight into current pool contents. */
+  return localkey.buf[3];
+}
diff --git a/ircd/s_auth.c b/ircd/s_auth.c
new file mode 100644 (file)
index 0000000..405978e
--- /dev/null
@@ -0,0 +1,2658 @@
+/************************************************************************
+ *   IRC - Internet Relay Chat, src/s_auth.c
+ *   Copyright (C) 1992 Darren Reed
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 1, or (at your option)
+ *   any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Changes:
+ *   July 6, 1999 - Rewrote most of the code here. When a client connects
+ *     to the server and passes initial socket validation checks, it
+ *     is owned by this module (auth) which returns it to the rest of the
+ *     server when dns and auth queries are finished. Until the client is
+ *     released, the server does not know it exists and does not process
+ *     any messages from it.
+ *     --Bleep  Thomas Helvey <tomh@inxpress.net>
+ *
+ *  December 26, 2005 - Rewrite the flag handling and integrate that with
+ *     an IRCnet-style IAuth protocol.
+ *     -- Michael Poole
+ */
+/** @file
+ * @brief Implementation of DNS and ident lookups.
+ * @version $Id: s_auth.c 1843 2007-11-17 14:12:37Z entrope $
+ */
+#include "config.h"
+
+#include "s_auth.h"
+#include "class.h"
+#include "client.h"
+#include "hash.h"
+#include "IPcheck.h"
+#include "ircd.h"
+#include "ircd_alloc.h"
+#include "ircd_chattr.h"
+#include "ircd_events.h"
+#include "ircd_features.h"
+#include "ircd_log.h"
+#include "ircd_osdep.h"
+#include "ircd_reply.h"
+#include "ircd_snprintf.h"
+#include "ircd_string.h"
+#include "list.h"
+#include "msg.h"       /* for MAXPARA */
+#include "numeric.h"
+#include "numnicks.h"
+#include "querycmds.h"
+#include "random.h"
+#include "res.h"
+#include "s_bsd.h"
+#include "s_conf.h"
+#include "s_debug.h"
+#include "s_misc.h"
+#include "s_user.h"
+#include "send.h"
+#include "sys.h"
+
+#include <errno.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+
+/** Pending operations during registration. */
+enum AuthRequestFlag {
+    AR_AUTH_PENDING,    /**< ident connecting or waiting for response */
+    AR_DNS_PENDING,     /**< dns request sent, waiting for response */
+    AR_CAP_PENDING,     /**< in middle of CAP negotiations */
+    AR_LOC_PENDING,     /**< LOC reply is awaited */
+    AR_NEEDS_PONG,      /**< user has not PONGed */
+    AR_NEEDS_USER,      /**< user must send USER command */
+    AR_NEEDS_NICK,      /**< user must send NICK command */
+    AR_LAST_SCAN = AR_NEEDS_NICK, /**< maximum flag to scan through */
+    AR_IAUTH_PENDING,   /**< iauth request sent, waiting for response */
+    AR_IAUTH_HURRY,     /**< we told iauth to hurry up */
+    AR_IAUTH_USERNAME,  /**< iauth sent a username (preferred or forced) */
+    AR_IAUTH_FUSERNAME, /**< iauth sent a forced username */
+    AR_PASSWORD_CHECKED, /**< client password already checked */
+    AR_LOC_SENT,        /**< LOC query already sent. */
+    AR_LOC_FORCE,       /**< Force kill if LOC failed. */
+    AR_NUM_FLAGS
+};
+
+DECLARE_FLAGSET(AuthRequestFlags, AR_NUM_FLAGS);
+
+/** Stores registration state of a client. */
+struct AuthRequest {
+  struct AuthRequest* next;       /**< linked list node ptr */
+  struct AuthRequest* prev;       /**< linked list node ptr */
+  struct Client*      client;     /**< pointer to client struct for request */
+  struct irc_sockaddr local;      /**< local endpoint address */
+  struct irc_in_addr  original;   /**< original client IP address */
+  struct Socket       socket;     /**< socket descriptor for auth queries */
+  struct Timer        timeout;    /**< timeout timer for ident and dns queries */
+  struct AuthRequestFlags flags;  /**< current state of request */
+  unsigned int        cookie;     /**< cookie the user must PONG */
+  unsigned short      port;       /**< client's remote port number */
+  unsigned int        numeric;    /**< unregistered client numeric */
+  char                loc_user[ACCOUNTLEN];
+  char                loc_pass[PASSWDLEN];
+};
+
+/** Array of message text (with length) pairs for AUTH status
+ * messages.  Indexed using #ReportType.
+ */
+static struct {
+  const char*  message;
+  unsigned int length;
+} HeaderMessages [] = {
+#define MSG(STR) { STR, sizeof(STR) - 1 }
+  MSG("NOTICE AUTH :*** Looking up your hostname\r\n"),
+  MSG("NOTICE AUTH :*** Found your hostname\r\n"),
+  MSG("NOTICE AUTH :*** Couldn't look up your hostname\r\n"),
+  MSG("NOTICE AUTH :*** Checking Ident\r\n"),
+  MSG("NOTICE AUTH :*** Got ident response\r\n"),
+  MSG("NOTICE AUTH :*** No ident response\r\n"),
+  MSG("NOTICE AUTH :*** \r\n"),
+  MSG("NOTICE AUTH :*** Your forward and reverse DNS do not match, "
+    "ignoring hostname.\r\n"),
+  MSG("NOTICE AUTH :*** Invalid hostname\r\n"),
+  MSG("NOTICE AUTH :*** Checking login\r\n"),
+  MSG("NOTICE AUTH :*** Login rejected\r\n"),
+  MSG("NOTICE AUTH :*** Login accepted\r\n"),
+#undef MSG
+};
+
+/** Enum used to index messages in the HeaderMessages[] array. */
+typedef enum {
+  REPORT_DO_DNS,
+  REPORT_FIN_DNS,
+  REPORT_FAIL_DNS,
+  REPORT_DO_ID,
+  REPORT_FIN_ID,
+  REPORT_FAIL_ID,
+  REPORT_FAIL_IAUTH,
+  REPORT_IP_MISMATCH,
+  REPORT_INVAL_DNS,
+  REPORT_DO_LOC,
+  REPORT_FAIL_LOC,
+  REPORT_DONE_LOC
+} ReportType;
+
+/** Sends response \a r (from #ReportType) to client \a c. */
+#define sendheader(c, r) \
+   ssl_send(cli_fd(c), cli_socket(c).ssl, HeaderMessages[(r)].message, HeaderMessages[(r)].length)
+
+/** Enumeration of IAuth connection flags. */
+enum IAuthFlag
+{
+  IAUTH_BLOCKED,                        /**< socket buffer full */
+  IAUTH_CLOSING,                        /**< candidate to be disposed */
+  /* The following flags are controlled by iauth's "O" options command. */
+  IAUTH_ADDLINFO,                       /**< Send additional info
+                                         * (password and username). */
+  IAUTH_FIRST_OPTION = IAUTH_ADDLINFO,  /**< First flag that is a policy option. */
+  IAUTH_REQUIRED,                       /**< IAuth completion required for registration. */
+  IAUTH_TIMEOUT,                        /**< Refuse new connections if IAuth is behind. */
+  IAUTH_EXTRAWAIT,                      /**< Give IAuth extra time to answer. */
+  IAUTH_UNDERNET,                       /**< Enable Undernet extensions. */
+  IAUTH_LAST_FLAG                       /**< total number of flags */
+};
+/** Declare a bitset structure indexed by IAuthFlag. */
+DECLARE_FLAGSET(IAuthFlags, IAUTH_LAST_FLAG);
+
+/** Describes state of an IAuth connection. */
+struct IAuth {
+  struct MsgQ i_sendQ;                  /**< messages queued to send */
+  struct Socket i_socket;               /**< main socket to iauth */
+  struct Socket i_stderr;               /**< error socket for iauth */
+  struct IAuthFlags i_flags;            /**< connection state/status/flags */
+  uint64_t i_recvB;                     /**< bytes received */
+  uint64_t i_sendB;                     /**< bytes sent */
+  time_t started;                       /**< time that this instance was started */
+  unsigned int i_recvM;                 /**< messages received */
+  unsigned int i_sendM;                 /**< messages sent */
+  unsigned int i_count;                 /**< characters used in i_buffer */
+  unsigned int i_errcount;              /**< characters used in i_errbuf */
+  int i_debug;                          /**< debug level */
+  char i_buffer[BUFSIZE+1];             /**< partial unprocessed line from server */
+  char i_errbuf[BUFSIZE+1];             /**< partial unprocessed error line */
+  char *i_version;                      /**< iauth version string */
+  struct SLink *i_config;               /**< configuration string list */
+  struct SLink *i_stats;                /**< statistics string list */
+  char **i_argv;                        /**< argument list */
+};
+
+/** Return whether flag \a flag is set on \a iauth. */
+#define IAuthHas(iauth, flag) ((iauth) && FlagHas(&(iauth)->i_flags, flag))
+/** Set flag \a flag on \a iauth. */
+#define IAuthSet(iauth, flag) FlagSet(&(iauth)->i_flags, flag)
+/** Clear flag \a flag from \a iauth. */
+#define IAuthClr(iauth, flag) FlagClr(&(iauth)->i_flags, flag)
+/** Get connected flag for \a iauth. */
+#define i_GetConnected(iauth) ((iauth) && s_fd(i_socket(iauth)) > -1)
+
+/** Return socket event generator for \a iauth. */
+#define i_socket(iauth) (&(iauth)->i_socket)
+/** Return stderr socket for \a iauth. */
+#define i_stderr(iauth) (&(iauth)->i_stderr)
+/** Return outbound message queue for \a iauth. */
+#define i_sendQ(iauth) (&(iauth)->i_sendQ)
+/** Return debug level for \a iauth. */
+#define i_debug(iauth) ((iauth)->i_debug)
+
+/** Active instance of IAuth. */
+static struct IAuth *iauth;
+/** Freelist of AuthRequest structures. */
+static struct AuthRequest *auth_freelist;
+/** Set to 1 if iauth is required to proceed a client, otherwise 0. */
+static int iauth_required;
+
+/** Array of unregistered clients indexed by numeric. */
+static struct AuthRequest *uclient_list[MAXCONNECTIONS];
+
+static void iauth_sock_callback(struct Event *ev);
+static void iauth_stderr_callback(struct Event *ev);
+static int sendto_iauth(struct Client *cptr, const char *format, ...);
+static int preregister_user(struct Client *cptr, signed int stop);
+typedef int (*iauth_cmd_handler)(struct IAuth *iauth, struct Client *cli,
+                                int parc, char **params);
+static void iauth_disconnect(struct IAuth *iauth);
+int iauth_do_spawn(struct IAuth *iauth, int automatic);
+
+/** Register a new unregistered client numeric.
+ * This numeric is totally independent from the numnicks in numnicks.c.
+ * Don't mix them up!
+ * This numeric is only valid while the user is in the unregistered state.
+ */
+static int auth_set_numnick(struct AuthRequest *auth) {
+  static unsigned int last_uclient = 0;
+  unsigned int count = 0;
+
+  while(uclient_list[last_uclient]) {
+    ++count;
+    if(count == MAXCONNECTIONS) {
+      assert(count < MAXCONNECTIONS && "More pending client registrations than connections, abort!");
+      return 0;
+    }
+    ++last_uclient;
+    if(last_uclient == MAXCONNECTIONS) last_uclient = 0;
+  }
+  uclient_list[last_uclient] = auth;
+  auth->numeric = last_uclient;
+  if(++last_uclient == MAXCONNECTIONS) last_uclient = 0;
+  return 1;
+}
+
+/** Unregisters an unregistered client numeric.
+ * See auth_set_numnick for information.
+ */
+static void auth_unset_numnick(struct AuthRequest *auth) {
+  uclient_list[auth->numeric] = NULL;
+  auth->numeric = 0;
+}
+
+/** Finds an AuthRequest related to an unregistered client numeric.
+ * See auth_set_numnick for information.
+ */
+static struct AuthRequest *auth_find_numnick(const char *numnick) {
+  unsigned int num;
+
+  num = base64toint(numnick);
+  if(num >= MAXCONNECTIONS) return NULL;
+  return uclient_list[num];
+}
+
+/** Sends a LOC query.
+ * We check for FEAT_LOC_ENABLE, search for the nick and discard the query
+ * if one check fails.
+ */
+static signed int auth_loc_send(struct AuthRequest *auth) {
+    struct Client *acptr;
+    char buf[4];
+    const char *host, *ip, *ident, *format;
+
+    if(!auth) return 1;
+    if(!FlagHas(&auth->flags, AR_LOC_PENDING) ||
+        FlagHas(&auth->flags, AR_LOC_SENT) ||
+        FlagHas(&auth->flags, AR_DNS_PENDING) ||
+        FlagHas(&auth->flags, AR_NEEDS_USER) ||
+        FlagHas(&auth->flags, AR_AUTH_PENDING)) return 1;
+
+    inttobase64(buf, auth->numeric, 3);
+    buf[3] = 0;
+
+    host = cli_sockhost(auth->client);
+    if(!host || !*host) host = NULL;
+    ip = cli_sock_ip(auth->client);
+    if(IsIdented(auth->client))
+        ident = cli_username(auth->client);
+    else
+        ident = cli_user(auth->client)->username;
+
+    if(!ident || !*ident) ident = "unknown";
+
+    if(feature_str(FEAT_LOC_TARGET) && (acptr = FindUser(feature_str(FEAT_LOC_TARGET))) && IsNetServ(acptr) && IsService(cli_user(acptr)->server)) {
+        if(IsIdented(auth->client) && host) format = "%C LQ !%s%s %s %s %s %s :%s";
+        else if(IsIdented(auth->client)) format = "%C LQ !%s%s %s %s%s %s :%s";
+        else if(host) format = "%C LQ !%s%s %s %s %s ~%s :%s";
+        else format = "%C LQ !%s%s %s %s%s ~%s :%s";
+
+        sendcmdto_one(&me, CMD_RELAY, acptr, format, acptr,
+                      cli_yxx(&me), buf, auth->loc_user, ip, host?host:"",
+                      ident, auth->loc_pass);
+        FlagSet(&auth->flags, AR_LOC_SENT);
+    }
+    else {
+        sendheader(auth->client, REPORT_FAIL_LOC);
+        FlagClr(&auth->flags, AR_LOC_PENDING);
+        if(FlagHas(&auth->flags, AR_LOC_FORCE)) {
+            exit_client(auth->client, auth->client, &me, "LOC Failed");
+            return 0;
+        }
+    }
+    return 1;
+}
+
+/** Set username for user associated with \a auth.
+ * @param[in] auth Client authorization request to work on.
+ * @return Zero if client is kept, CPTR_KILLED if client rejected.
+ */
+static int auth_set_username(struct AuthRequest *auth)
+{
+  struct Client *sptr = auth->client;
+  struct User   *user = cli_user(sptr);
+  char *d;
+  char *s;
+  int   rlen = USERLEN;
+  int   killreason;
+  char  ch;
+  char  last;
+  unsigned int i;
+
+  if (FlagHas(&auth->flags, AR_IAUTH_USERNAME))
+  {
+      ircd_strncpy(cli_user(sptr)->username, cli_username(sptr), USERLEN);
+  }
+  else
+  {
+    /* Copy username from source to destination.  Since they may be the
+     * same, and we may prefix with a '~', use a buffer character (ch)
+     * to hold the next character to copy.
+     */
+    s = IsIdented(sptr) ? cli_username(sptr) : user->username;
+    last = *s++;
+    d = user->username;
+    if (HasFlag(sptr, FLAG_DOID) && !IsIdented(sptr))
+    {
+      *d++ = '~';
+      --rlen;
+    }
+    while (last && !IsCntrl(last) && rlen--)
+    {
+      ch = *s++;
+      *d++ = IsUserChar(last) ? last : '_';
+      last = (ch != '~') ? ch : '_';
+    }
+    *d = 0;
+  }
+
+  /* If username is empty or just ~, reject. */
+  if ((user->username[0] == '\0')
+      || ((user->username[0] == '~') && (user->username[1] == '\0')))
+    return exit_client(sptr, sptr, &me, "USER: Bogus userid.");
+
+  /* Check for K- or G-line. */
+  killreason = find_kill(sptr);
+  if (killreason) {
+    ServerStats->is_ref++;
+    return exit_client(sptr, sptr, &me,
+                       (killreason == -1 ? "K-lined" : "G-lined"));
+  }
+
+  if (!FlagHas(&auth->flags, AR_IAUTH_FUSERNAME))
+#if 1
+  {
+    for(i = 0; user->username[i]; ++i) {
+      if(user->username[i] > 126 || user->username[i] < 1) goto badid;
+    }
+  }
+#else
+  {
+    /* Check for mixed case usernames, meaning probably hacked.  Jon2 3-94
+     * Explanations of rules moved to where it is checked     Entrope 2-06
+     */
+    s = d = user->username + (user->username[0] == '~');
+    for (last = '\0';
+         (ch = *d++) != '\0';
+         pos++, last = ch)
+    {
+      if (IsLower(ch))
+      {
+        lower++;
+      }
+      else if (IsUpper(ch))
+      {
+        upper++;
+        /* Accept caps as leading if we haven't seen lower case or digits yet. */
+        if ((leadcaps || pos == 0) && !lower && !digits)
+          leadcaps++;
+      }
+      else if (IsDigit(ch))
+      {
+        digits++;
+        if (pos == 0 || !IsDigit(last))
+        {
+          digitgroups++;
+          /* If more than two groups of digits, reject. */
+          if (digitgroups > 2)
+            goto badid;
+        }
+      }
+      else if (ch == '-' || ch == '_' || ch == '.')
+      {
+        other++;
+        /* If -_. exist at start, consecutively, or more than twice, reject. */
+        if (pos == 0 || last == '-' || last == '_' || last == '.' || other > 2)
+          goto badid;
+      }
+      else /* All other punctuation is rejected. */
+        goto badid;
+    }
+
+    /* If mixed case, first must be capital, but no more than three;
+     * but if three capitals, they must all be leading. */
+    if (lower && upper && (!leadcaps || leadcaps > 3 ||
+                           (upper > 2 && upper > leadcaps)))
+      goto badid;
+    /* If two different groups of digits, one must be either at the
+     * start or end. */
+    if (digitgroups == 2 && !(IsDigit(s[0]) || IsDigit(ch)))
+      goto badid;
+    /* Must have at least one letter. */
+    if (!lower && !upper)
+      goto badid;
+    /* Final character must not be punctuation. */
+    if (!IsAlnum(last))
+      goto badid;
+  }
+#endif
+
+  return 0;
+
+badid:
+  /* If we confirmed their username, and it is what they claimed,
+   * accept it. */
+  if (IsIdented(sptr) && !strcmp(cli_username(sptr), user->username))
+    return 0;
+
+  ServerStats->is_ref++;
+  send_reply(sptr, SND_EXPLICIT | ERR_INVALIDUSERNAME,
+             ":Your username is invalid.");
+  send_reply(sptr, SND_EXPLICIT | ERR_INVALIDUSERNAME,
+             ":Connect with your real username, in lowercase.");
+  send_reply(sptr, SND_EXPLICIT | ERR_INVALIDUSERNAME,
+             ":If your mail address were foo@bar.com, your username "
+             "would be foo.");
+  return exit_client(sptr, sptr, &me, "USER: Bad username");
+}
+
+/** Check whether an authorization request is complete.
+ * This means that no flags from 0 to #AR_LAST_SCAN are set on \a auth.
+ * If #AR_IAUTH_PENDING is set, optionally go into "hurry" state.  If
+ * 0 through #AR_LAST_SCAN and #AR_IAUTH_PENDING are all clear,
+ * destroy \a auth, clear the password, set the username, and register
+ * the client.
+ * @param[in] auth Authorization request to check.
+ * @return Zero if client is kept, CPTR_KILLED if client rejected.
+ */
+static int check_auth_finished(struct AuthRequest *auth)
+{
+  enum AuthRequestFlag flag;
+  int res;
+
+  /* Check whether to send LOC query. */
+  if(FlagHas(&auth->flags, AR_LOC_PENDING) &&
+     !FlagHas(&auth->flags, AR_LOC_SENT) &&
+     !FlagHas(&auth->flags, AR_DNS_PENDING) &&
+     !FlagHas(&auth->flags, AR_NEEDS_USER) &&
+     !FlagHas(&auth->flags, AR_AUTH_PENDING)) {
+    if(!auth_loc_send(auth)) return CPTR_KILLED;
+    return 0;
+  }
+
+  /* Check non-iauth registration blocking flags. */
+  for (flag = 0; flag <= AR_LAST_SCAN; ++flag)
+    if (FlagHas(&auth->flags, flag))
+    {
+      Debug((DEBUG_INFO, "Auth %p [%d] still has flag %d", auth,
+             cli_fd(auth->client), flag));
+      return 0;
+    }
+
+  /* If appropriate, do preliminary assignment to connection class. */
+  if (IsUserPort(auth->client)
+      && !FlagHas(&auth->flags, AR_IAUTH_HURRY)
+      && preregister_user(auth->client, 1))
+    return CPTR_KILLED;
+
+  /* Check if iauth is done. */
+  if (FlagHas(&auth->flags, AR_IAUTH_PENDING))
+  {
+    /* Switch auth request to hurry-up state. */
+    if (!FlagHas(&auth->flags, AR_IAUTH_HURRY))
+    {
+      /* Set "hurry" flag in auth request. */
+      FlagSet(&auth->flags, AR_IAUTH_HURRY);
+
+      /* If iauth wants it, send notification. */
+      if (IAuthHas(iauth, IAUTH_UNDERNET))
+        sendto_iauth(auth->client, "H %s", get_client_class(auth->client));
+
+      /* If iauth wants it, give client more time. */
+      if (IAuthHas(iauth, IAUTH_EXTRAWAIT))
+        cli_firsttime(auth->client) = CurrentTime;
+    }
+
+    Debug((DEBUG_INFO, "Auth %p [%d] still has flag %d", auth,
+           cli_fd(auth->client), AR_IAUTH_PENDING));
+    return 0;
+  }
+  else
+    FlagSet(&auth->flags, AR_IAUTH_HURRY);
+
+  /* Class assignment is done after IAUTH is done. */
+  if (IsUserPort(auth->client)) {
+    if(preregister_user(auth->client, 0))
+      return CPTR_KILLED;
+
+    if(!FlagHas(&auth->flags, AR_PASSWORD_CHECKED)) {
+      struct ConfItem *aconf;
+      aconf = cli_confs(auth->client)->value.aconf;
+      if (aconf
+          && !EmptyString(aconf->passwd)
+          && strcmp(cli_passwd(auth->client), aconf->passwd))
+      {
+        ServerStats->is_ref++;
+        send_reply(auth->client, ERR_PASSWDMISMATCH);
+        return exit_client(auth->client, auth->client, &me, "Bad Password");
+      }
+      FlagSet(&auth->flags, AR_PASSWORD_CHECKED);
+    }
+  }
+
+  if (IsUserPort(auth->client))
+  {
+    memset(cli_passwd(auth->client), 0, sizeof(cli_passwd(auth->client)));
+    res = auth_set_username(auth);
+    if (res == 0)
+      res = register_user(auth->client, auth->client);
+  }
+  else
+    res = 0;
+  if (res == 0)
+    destroy_auth_request(auth);
+  return res;
+}
+
+/** Verify that a hostname is valid, i.e., only contains characters
+ * valid for a hostname and that a hostname is not too long.
+ * @param host Hostname to check.
+ * @param maxlen Maximum length of hostname, not including NUL terminator.
+ * @return Non-zero if the hostname is valid.
+ */
+static int
+auth_verify_hostname(const char *host, int maxlen)
+{
+  int i;
+
+  /* Walk through the host name */
+  for (i = 0; host[i]; i++)
+    /* If it's not a hostname character or if it's too long, return false */
+    if (!IsHostChar(host[i]) || i >= maxlen)
+      return 0;
+
+  return 1; /* it's a valid hostname */
+}
+
+/** Check whether a client already has a CONF_CLIENT configuration
+ * item.
+ *
+ * @return A pointer to the client's first CONF_CLIENT, or NULL if
+ *   there are none.
+ */
+static struct ConfItem *find_conf_client(struct Client *cptr)
+{
+  struct SLink *list;
+
+  for (list = cli_confs(cptr); list != NULL; list = list->next) {
+    struct ConfItem *aconf;
+    aconf = list->value.aconf;
+    if (aconf->status & CONF_CLIENT)
+      return aconf;
+  }
+
+  return NULL;
+}
+
+/** Assign a client to a connection class.
+ * @param[in] cptr Client to assign to a class.
+ * @return Zero if client is kept, CPTR_KILLED if rejected.
+ */
+static int preregister_user(struct Client *cptr, signed int stop)
+{
+  static time_t last_too_many1;
+  static time_t last_too_many2;
+
+  ircd_strncpy(cli_user(cptr)->host, cli_sockhost(cptr), HOSTLEN);
+  ircd_strncpy(cli_user(cptr)->realhost, cli_sockhost(cptr), HOSTLEN);
+
+  if(find_conf_client(cptr) || stop) return 0;
+
+  switch (conf_check_client(cptr))
+  {
+  case ACR_OK:
+    break;
+  case ACR_NO_AUTHORIZATION:
+    sendto_opmask_butone(0, SNO_UNAUTH, "Unauthorized connection from %s.",
+                         get_client_name(cptr, HIDE_IP));
+    ++ServerStats->is_ref;
+    return exit_client(cptr, cptr, &me,
+                       "No Authorization - use another server");
+  case ACR_TOO_MANY_IN_CLASS:
+    sendto_opmask_butone_ratelimited(0, SNO_TOOMANY, &last_too_many1,
+                                     "Too many connections in class %s for %s.",
+                                     get_client_class(cptr),
+                                     get_client_name(cptr, SHOW_IP));
+    ++ServerStats->is_ref;
+    return exit_client(cptr, cptr, &me,
+                       "Sorry, your connection class is full - try "
+                       "again later or try another server");
+  case ACR_TOO_MANY_FROM_IP:
+    sendto_opmask_butone_ratelimited(0, SNO_TOOMANY, &last_too_many2,
+                                     "Too many connections from same IP for %s.",
+                                     get_client_name(cptr, SHOW_IP));
+    ++ServerStats->is_ref;
+    return exit_client(cptr, cptr, &me,
+                       "Too many connections from your host");
+  case ACR_ALREADY_AUTHORIZED:
+    /* Can this ever happen? */
+  case ACR_BAD_SOCKET:
+    ++ServerStats->is_ref;
+    IPcheck_connect_fail(cptr);
+    return exit_client(cptr, cptr, &me, "Unknown error -- Try again");
+  }
+  return 0;
+}
+
+/** Send the ident server a query giving "theirport , ourport". The
+ * write is only attempted *once* so it is deemed to be a fail if the
+ * entire write doesn't write all the data given.  This shouldn't be a
+ * problem since the socket should have a write buffer far greater
+ * than this message to store it in should problems arise. -avalon
+ * @param[in] auth The request to send.
+ */
+static void send_auth_query(struct AuthRequest* auth)
+{
+  char               authbuf[32];
+  unsigned int       count;
+
+  assert(0 != auth);
+
+  ircd_snprintf(0, authbuf, sizeof(authbuf), "%hu , %hu\r\n",
+                auth->port, auth->local.port);
+
+  if (IO_SUCCESS != os_send_nonb(s_fd(&auth->socket), authbuf, strlen(authbuf), &count)) {
+    close(s_fd(&auth->socket));
+    socket_del(&auth->socket);
+    s_fd(&auth->socket) = -1;
+    ++ServerStats->is_abad;
+    if (IsUserPort(auth->client))
+      sendheader(auth->client, REPORT_FAIL_ID);
+    FlagClr(&auth->flags, AR_AUTH_PENDING);
+    check_auth_finished(auth);
+  }
+}
+
+/** Enum used to index ident reply fields in a human-readable way. */
+enum IdentReplyFields {
+  IDENT_PORT_NUMBERS,
+  IDENT_REPLY_TYPE,
+  IDENT_OS_TYPE,
+  IDENT_INFO,
+  USERID_TOKEN_COUNT
+};
+
+/** Parse an ident reply line and extract the userid from it.
+ * @param[in] reply The ident reply line.
+ * @return The userid, or NULL on parse failure.
+ */
+static char* check_ident_reply(char* reply)
+{
+  char* token;
+  char* end;
+  char* vector[USERID_TOKEN_COUNT];
+  int count = token_vector(reply, ':', vector, USERID_TOKEN_COUNT);
+
+  if (USERID_TOKEN_COUNT != count)
+    return 0;
+  /*
+   * second token is the reply type
+   */
+  token = vector[IDENT_REPLY_TYPE];
+  if (EmptyString(token))
+    return 0;
+
+  while (IsSpace(*token))
+    ++token;
+
+  if (0 != strncmp(token, "USERID", 6))
+    return 0;
+
+  /*
+   * third token is the os type
+   */
+  token = vector[IDENT_OS_TYPE];
+  if (EmptyString(token))
+    return 0;
+  while (IsSpace(*token))
+   ++token;
+
+  /*
+   * Unless "OTHER" is specified as the operating system
+   * type, the server is expected to return the "normal"
+   * user identification of the owner of this connection.
+   * "Normal" in this context may be taken to mean a string
+   * of characters which uniquely identifies the connection
+   * owner such as a user identifier assigned by the system
+   * administrator and used by such user as a mail
+   * identifier, or as the "user" part of a user/password
+   * pair used to gain access to system resources.  When an
+   * operating system is specified (e.g., anything but
+   * "OTHER"), the user identifier is expected to be in a
+   * more or less immediately useful form - e.g., something
+   * that could be used as an argument to "finger" or as a
+   * mail address.
+   */
+  if (0 == strncmp(token, "OTHER", 5))
+    return 0;
+  /*
+   * fourth token is the username
+   */
+  token = vector[IDENT_INFO];
+  if (EmptyString(token))
+    return 0;
+  while (IsSpace(*token))
+    ++token;
+  /*
+   * look for the end of the username, terminators are '\0, @, <SPACE>, :'
+   */
+  for (end = token; *end; ++end) {
+    if (IsSpace(*end) || '@' == *end || ':' == *end)
+      break;
+  }
+  *end = '\0';
+  return token;
+}
+
+/** Read the reply (if any) from the ident server we connected to.  We
+ * only give it one shot, if the reply isn't good the first time fail
+ * the authentication entirely. --Bleep
+ * @param[in] auth The request to read.
+ */
+static void read_auth_reply(struct AuthRequest* auth)
+{
+  char*        username = 0;
+  unsigned int len;
+  /*
+   * rfc1453 sez we MUST accept 512 bytes
+   */
+  char   buf[BUFSIZE + 1];
+
+  assert(0 != auth);
+  assert(0 != auth->client);
+  assert(auth == cli_auth(auth->client));
+
+  if (IO_SUCCESS == os_recv_nonb(s_fd(&auth->socket), buf, BUFSIZE, &len)) {
+    buf[len] = '\0';
+    Debug((DEBUG_INFO, "Auth %p [%d] reply: %s", auth, cli_fd(auth->client), buf));
+    username = check_ident_reply(buf);
+    Debug((DEBUG_INFO, "Username: %s", username));
+  }
+
+  Debug((DEBUG_INFO, "Deleting auth [%d] socket %p", auth, cli_fd(auth->client)));
+  close(s_fd(&auth->socket));
+  socket_del(&auth->socket);
+  s_fd(&auth->socket) = -1;
+
+  if (EmptyString(username)) {
+    if (IsUserPort(auth->client))
+      sendheader(auth->client, REPORT_FAIL_ID);
+    ++ServerStats->is_abad;
+  } else {
+    if (IsUserPort(auth->client))
+      sendheader(auth->client, REPORT_FIN_ID);
+    ++ServerStats->is_asuc;
+    if (!FlagHas(&auth->flags, AR_IAUTH_USERNAME)) {
+      ircd_strncpy(cli_username(auth->client), username, USERLEN);
+      SetGotId(auth->client);
+    }
+    if (IAuthHas(iauth, IAUTH_UNDERNET))
+      sendto_iauth(auth->client, "u %s", username);
+  }
+
+  FlagClr(&auth->flags, AR_AUTH_PENDING);
+  if(!auth_loc_send(auth)) return;
+  check_auth_finished(auth);
+}
+
+/** Handle socket I/O activity.
+ * @param[in] ev A socket event whos associated data is the active
+ *   struct AuthRequest.
+ */
+static void auth_sock_callback(struct Event* ev)
+{
+  struct AuthRequest* auth;
+
+  assert(0 != ev_socket(ev));
+  assert(0 != s_data(ev_socket(ev)));
+
+  auth = (struct AuthRequest*) s_data(ev_socket(ev));
+
+  switch (ev_type(ev)) {
+  case ET_DESTROY: /* being destroyed */
+    break;
+
+  case ET_CONNECT: /* socket connection completed */
+    Debug((DEBUG_INFO, "Connection completed for auth %p [%d]; sending query",
+           auth, cli_fd(auth->client)));
+    socket_state(&auth->socket, SS_CONNECTED);
+    send_auth_query(auth);
+    break;
+
+  case ET_READ: /* socket is readable */
+  case ET_EOF: /* end of file on socket */
+  case ET_ERROR: /* error on socket */
+    Debug((DEBUG_INFO, "Auth socket %p [%p] readable", auth, ev_socket(ev)));
+    read_auth_reply(auth);
+    break;
+
+  default:
+    assert(0 && "Unrecognized event in auth_socket_callback().");
+    break;
+  }
+}
+
+/** Stop an auth request completely.
+ * @param[in] auth The struct AuthRequest to cancel.
+ */
+void destroy_auth_request(struct AuthRequest* auth)
+{
+  Debug((DEBUG_INFO, "Deleting auth request for %p", auth->client));
+
+  /* Unset numeric nick. */
+  auth_unset_numnick(auth);
+
+  if (FlagHas(&auth->flags, AR_DNS_PENDING)) {
+    delete_resolver_queries(auth);
+  }
+
+  if (-1 < s_fd(&auth->socket)) {
+    close(s_fd(&auth->socket));
+    socket_del(&auth->socket);
+    s_fd(&auth->socket) = -1;
+  }
+
+  if (t_active(&auth->timeout))
+    timer_del(&auth->timeout);
+
+  cli_auth(auth->client) = NULL;
+  auth->next = auth_freelist;
+  auth_freelist = auth;
+}
+
+/** Handle a 'ping' (authorization) timeout for a client.
+ * @param[in] cptr The client whose session authorization has timed out.
+ * @return Zero if client is kept, CPTR_KILLED if client rejected.
+ */
+int auth_ping_timeout(struct Client *cptr)
+{
+  struct AuthRequest *auth;
+  enum AuthRequestFlag flag;
+  signed int ret;
+
+  auth = cli_auth(cptr);
+
+  /* Check whether the auth request is gone (more likely, it never
+   * existed, as in an outbound server connection). */
+  if (!auth)
+      return exit_client_msg(cptr, cptr, &me, "Registration Timeout");
+
+  /* If the loc-query is still pending, we stop the query and
+   * register the user if possible.
+   */
+  if (FlagHas(&auth->flags, AR_LOC_PENDING)) {
+    FlagClr(&auth->flags, AR_LOC_PENDING);
+    sendheader(auth->client, REPORT_FAIL_LOC);
+    if(FlagHas(&auth->flags, AR_LOC_FORCE)) return exit_client(cptr, cptr, &me, "Registration Timeout");
+    ret = check_auth_finished(auth);
+    if (ret != 0) return ret;
+    return exit_client(cptr, cptr, &me, "Registration Timeout");
+  }
+
+  /* Check for a user-controlled timeout. */
+  for (flag = 0; flag <= AR_LAST_SCAN; ++flag) {
+    if (FlagHas(&auth->flags, flag)) {
+      /* Display message if they have sent a NICK and a USER but no
+       * nospoof PONG.
+       */
+      if (*(cli_name(cptr)) && cli_user(cptr) && *(cli_user(cptr))->username) {
+        send_reply(cptr, SND_EXPLICIT | ERR_BADPING,
+                   ":Your client may not be compatible with this server.");
+        send_reply(cptr, SND_EXPLICIT | ERR_BADPING,
+                   ":Compatible clients are available at %s",
+                   feature_str(FEAT_URL_CLIENTS));
+      }
+      return exit_client_msg(cptr, cptr, &me, "Registration Timeout");
+    }
+  }
+
+  /* Check for iauth timeout. */
+  if (FlagHas(&auth->flags, AR_IAUTH_PENDING)) {
+    if (IAuthHas(iauth, IAUTH_REQUIRED)) {
+      sendheader(cptr, REPORT_FAIL_IAUTH);
+      return exit_client_msg(cptr, cptr, &me, "Authorization Timeout");
+    }
+    sendto_iauth(cptr, "T");
+    FlagClr(&auth->flags, AR_IAUTH_PENDING);
+    return check_auth_finished(auth);
+  }
+
+  return exit_client_msg(cptr, cptr, &me, "Ping Timeout");
+}
+
+/** Timeout a given auth request.
+ * @param[in] ev A timer event whose associated data is the expired
+ *   struct AuthRequest.
+ */
+static void auth_timeout_callback(struct Event* ev)
+{
+  struct AuthRequest* auth;
+
+  assert(0 != ev_timer(ev));
+  assert(0 != t_data(ev_timer(ev)));
+
+  auth = (struct AuthRequest*) t_data(ev_timer(ev));
+
+  if (ev_type(ev) == ET_EXPIRE) {
+    /* Report the timeout in the log. */
+    log_write(LS_RESOLVER, L_INFO, 0, "Registration timeout %s",
+              get_client_name(auth->client, HIDE_IP));
+
+    /* Notify client if ident lookup failed. */
+    if (FlagHas(&auth->flags, AR_AUTH_PENDING)) {
+      FlagClr(&auth->flags, AR_AUTH_PENDING);
+      if (IsUserPort(auth->client))
+        sendheader(auth->client, REPORT_FAIL_ID);
+    }
+
+    /* Likewise if dns lookup failed. */
+    if (FlagHas(&auth->flags, AR_DNS_PENDING)) {
+      FlagClr(&auth->flags, AR_DNS_PENDING);
+      delete_resolver_queries(auth);
+      if (IsUserPort(auth->client))
+        sendheader(auth->client, REPORT_FAIL_DNS);
+    }
+
+    /* Try to register the client. */
+    check_auth_finished(auth);
+  }
+}
+
+/** Handle a complete DNS lookup.  Send the client on it's way to a
+ * connection completion, regardless of success or failure -- unless
+ * there was a mismatch and KILL_IPMISMATCH is set.
+ * @param[in] vptr The pending struct AuthRequest.
+ * @param[in] addr IP address being resolved.
+ * @param[in] h_name Resolved name, or NULL if lookup failed.
+ */
+static void auth_dns_callback(void* vptr, const struct irc_in_addr *addr, const char *h_name)
+{
+  struct AuthRequest* auth = (struct AuthRequest*) vptr;
+  assert(0 != auth);
+
+  FlagClr(&auth->flags, AR_DNS_PENDING);
+  if (!addr) {
+    /* DNS entry was missing for the IP. */
+    if (IsUserPort(auth->client))
+      sendheader(auth->client, REPORT_FAIL_DNS);
+    sendto_iauth(auth->client, "d");
+  } else if (!irc_in_addr_valid(addr)
+             || (irc_in_addr_cmp(&cli_ip(auth->client), addr)
+                 && irc_in_addr_cmp(&auth->original, addr))) {
+    /* IP for hostname did not match client's IP. */
+    sendto_opmask_butone(0, SNO_IPMISMATCH, "IP# Mismatch: %s != %s[%s]",
+                         cli_sock_ip(auth->client), h_name,
+                         ircd_ntoa(addr));
+    if (IsUserPort(auth->client))
+      sendheader(auth->client, REPORT_IP_MISMATCH);
+    if (feature_bool(FEAT_KILL_IPMISMATCH)) {
+      exit_client(auth->client, auth->client, &me, "IP mismatch");
+      return;
+    }
+  } else if (!auth_verify_hostname(h_name, HOSTLEN)) {
+    /* Hostname did not look valid. */
+    if (IsUserPort(auth->client))
+      sendheader(auth->client, REPORT_INVAL_DNS);
+    sendto_iauth(auth->client, "d");
+  } else {
+    /* Hostname and mappings checked out. */
+    if (IsUserPort(auth->client))
+      sendheader(auth->client, REPORT_FIN_DNS);
+    ircd_strncpy(cli_sockhost(auth->client), h_name, HOSTLEN);
+    sendto_iauth(auth->client, "N %s", h_name);
+  }
+
+  /* The LOC line has to be sent with full hostname. If no hostname could be looked
+   * up, the IP is sent.
+   */
+  if(!auth_loc_send(auth)) return;
+
+  check_auth_finished(auth);
+}
+
+/** Starts a new login-on-connect query. */
+signed int auth_loc_query(struct AuthRequest *auth, const char *account, const char *pass, int force) {
+    if(!account || !*account) return 1;
+    if(!pass || !*pass) return 1;
+    assert(auth != NULL);
+    if(!feature_bool(FEAT_LOC_ENABLE)) return 1;
+
+    sendheader(auth->client, REPORT_DO_LOC);
+    FlagSet(&auth->flags, AR_LOC_PENDING);
+    if(force) FlagSet(&auth->flags, AR_LOC_FORCE);
+    else FlagClr(&auth->flags, AR_LOC_FORCE);
+    ircd_strncpy(auth->loc_user, account, ACCOUNTLEN);
+    ircd_strncpy(auth->loc_pass, pass, PASSWDLEN);
+    return auth_loc_send(auth);
+}
+
+/** Finishes a LOC request. */
+void auth_loc_reply(const char *numeric, const char *account, const char *fakehost, const char *flags[], signed int argc) {
+    char *timestamp;
+    struct AuthRequest *auth;
+
+    assert(numeric != NULL);
+
+    auth = auth_find_numnick(numeric);
+    if(!auth) return;
+    assert(!IsRegistered(auth->client));
+    if(!FlagHas(&auth->flags, AR_LOC_PENDING)) return;
+    if(!cli_user(auth->client) || IsAccount(auth->client)) {
+        FlagClr(&auth->flags, AR_LOC_PENDING);
+        sendheader(auth->client, REPORT_FAIL_LOC);
+        check_auth_finished(auth);
+        return;
+    }
+
+    assert((fakehost == NULL) || (*fakehost != 0));
+
+    /* Remove account-flag. */
+    FlagClr(&auth->flags, AR_LOC_PENDING);
+
+    /* Access denied? */
+    if(!account) {
+        sendheader(auth->client, REPORT_FAIL_LOC);
+        if(FlagHas(&auth->flags, AR_LOC_FORCE)) exit_client(auth->client, auth->client, &me, "LOC Failed");
+        else check_auth_finished(auth);
+        return;
+    }
+    assert(*account != 0);
+
+    if(fakehost)
+        sendto_iauth(auth->client, "L %s %s", account, fakehost);
+    else
+        sendto_iauth(auth->client, "L %s", account);
+
+    sendheader(auth->client, REPORT_DONE_LOC);
+
+    /* Check for timestamped account. */
+    timestamp = strchr(account, ':');
+    if(timestamp) {
+        *timestamp++ = 0;
+        cli_user(auth->client)->acc_create = atoi(timestamp);
+    }
+
+    SetAccount(auth->client);
+    ircd_strncpy(cli_user(auth->client)->account, account, ACCOUNTLEN);
+
+    if(fakehost) {
+        SetHiddenHost(auth->client);
+        SetFakeHost(auth->client);
+        ircd_strncpy(cli_user(auth->client)->fakehost, fakehost, HOSTLEN);
+    }
+    if(flags) { 
+        unsigned int ii, in_arg, ch_arg;
+        if (argc > 0) {
+            for (ii = ch_arg = 0, in_arg = 1; (flags[0][ii] != '\0') && (flags[0][ii] != ' '); ++ii) {
+                switch (flags[0][ii]) {
+                case '+':
+                    if (in_arg >= argc)
+                        break;
+                    ircd_strncpy(cli_connclass(auth->client), flags[in_arg++], NICKLEN);
+                    break;
+                case 'a':
+                    if (in_arg >= argc)
+                        break;
+                    unsigned int maxchan = atoi(flags[in_arg++]);
+                    fprintf(stderr, "flag a: %i\n", maxchan);
+                    if(maxchan > 0)
+                        auth->client->maxchans = maxchan;
+                    else
+                        SetPriv(auth->client,PRIV_CHAN_LIMIT);
+                    break;
+                case 'b':
+                    SetPriv(auth->client,PRIV_UNLIMITED_TARGET);
+                    break;
+                case 'c':
+                    SetPriv(auth->client,PRIV_HALFFLOOD);
+                    break;
+                case 'd':
+                    SetPriv(auth->client,PRIV_FLOOD);
+                    break;
+                case 'e':
+                    SetPriv(auth->client,PRIV_UMODE_NOCHAN);
+                    break;
+                case 'f':
+                    SetPriv(auth->client,PRIV_UMODE_NOIDLE);
+                    break;
+                case 'g':
+                    SetPriv(auth->client,PRIV_UMODE_CHSERV);
+                    break;
+                case 'h':
+                    SetPriv(auth->client,PRIV_UMODE_XTRAOP);
+                    break;
+                case 'i':
+                    SetPriv(auth->client,PRIV_UMODE_NETSERV);
+                    break;
+                case 'j':
+                    SetPriv(auth->client,PRIV_SEE_IDLETIME);
+                    break;
+                case 'k':
+                    SetPriv(auth->client,PRIV_HIDE_IDLETIME);
+                    break;
+                case 'l':
+                    SetPriv(auth->client,PRIV_UMODE_OVERRIDECC);
+                    break;
+                case 'm':
+                    SetPriv(auth->client,PRIV_NOAMSG_OVERRIDE);
+                    break;
+                case 'n':
+                    if (in_arg >= argc)
+                        break;
+                    unsigned int maxq = atoi(flags[in_arg++]);
+                    if(maxq > 0)
+                        auth->client->cli_connect->con_max_sendq = maxq;
+                    break;
+                }
+            }
+        }   
+    }
+    check_auth_finished(auth);
+}
+
+/** Flag the client to show an attempt to contact the ident server on
+ * the client's host.  Should the connect or any later phase of the
+ * identifying process fail, it is aborted and the user is given a
+ * username of "unknown".
+ * @param[in] auth The request for which to start the ident lookup.
+ */
+static void start_auth_query(struct AuthRequest* auth)
+{
+  struct irc_sockaddr remote_addr;
+  struct irc_sockaddr local_addr;
+  int                 fd;
+  IOResult            result;
+
+  assert(0 != auth);
+  assert(0 != auth->client);
+
+  /*
+   * get the local address of the client and bind to that to
+   * make the auth request.  This used to be done only for
+   * ifdef VIRTUAL_HOST, but needs to be done for all clients
+   * since the ident request must originate from that same address--
+   * and machines with multiple IP addresses are common now
+   */
+  memcpy(&local_addr, &auth->local, sizeof(local_addr));
+  local_addr.port = 0;
+  memcpy(&remote_addr.addr, &cli_ip(auth->client), sizeof(remote_addr.addr));
+  remote_addr.port = 113;
+  fd = os_socket(&local_addr, SOCK_STREAM, "auth query", 0);
+  if (fd < 0) {
+    ++ServerStats->is_abad;
+    if (IsUserPort(auth->client))
+      sendheader(auth->client, REPORT_FAIL_ID);
+    return;
+  }
+  if (IsUserPort(auth->client))
+    sendheader(auth->client, REPORT_DO_ID);
+
+  if ((result = os_connect_nonb(fd, &remote_addr)) == IO_FAILURE ||
+      !socket_add(&auth->socket, auth_sock_callback, (void*) auth,
+                  result == IO_SUCCESS ? SS_CONNECTED : SS_CONNECTING,
+                  SOCK_EVENT_READABLE, fd)) {
+    ++ServerStats->is_abad;
+    if (IsUserPort(auth->client))
+      sendheader(auth->client, REPORT_FAIL_ID);
+    close(fd);
+    return;
+  }
+
+  FlagSet(&auth->flags, AR_AUTH_PENDING);
+  if (result == IO_SUCCESS)
+    send_auth_query(auth);
+}
+
+/** Initiate DNS lookup for a client.
+ * @param[in] auth The auth request for which to start the DNS lookup.
+ */
+static void start_dns_query(struct AuthRequest *auth)
+{
+  if (feature_bool(FEAT_NODNS)) {
+    sendto_iauth(auth->client, "d");
+    return;
+  }
+
+  if (irc_in_addr_is_loopback(&cli_ip(auth->client))) {
+    strcpy(cli_sockhost(auth->client), cli_name(&me));
+    sendto_iauth(auth->client, "N %s", cli_sockhost(auth->client));
+    return;
+  }
+
+  if (IsUserPort(auth->client))
+    sendheader(auth->client, REPORT_DO_DNS);
+
+  FlagSet(&auth->flags, AR_DNS_PENDING);
+  gethost_byaddr(&cli_ip(auth->client), auth_dns_callback, auth);
+}
+
+/** Initiate IAuth check for a client.
+ * @param[in] auth The auth request for which to star the IAuth check.
+ */
+static int start_iauth_query(struct AuthRequest *auth)
+{
+  int ret;
+
+  /* A new client connected. Check whether we have an IAuth configured and
+   * if this IAuth is not running, then try once to forcibly start it.
+   */
+  if(iauth && !i_GetConnected(iauth)) {
+    iauth_disconnect(iauth);
+    iauth_do_spawn(iauth, 0);
+  }
+
+  FlagSet(&auth->flags, AR_IAUTH_PENDING);
+  ret = sendto_iauth(auth->client, "C %s %hu %s %hu",
+                     cli_sock_ip(auth->client), auth->port,
+                     ircd_ntoa(&auth->local.addr), auth->local.port);
+  if(!ret) {
+    if(!iauth_required)
+      FlagClr(&auth->flags, AR_IAUTH_PENDING);
+    else {
+      exit_client(auth->client, auth->client, &me, "IAuth could not be queried. Please try again later or inform network staff.");
+      return 1;
+    }
+  }
+  return 0;
+}
+
+/** Starts auth (identd) and dns queries for a client.
+ * @param[in] client The client for which to start queries.
+ */
+void start_auth(struct Client* client)
+{
+  struct irc_sockaddr remote;
+  struct AuthRequest* auth;
+
+  assert(0 != client);
+  Debug((DEBUG_INFO, "Beginning auth request on client %p", client));
+
+  /* Register with event handlers. */
+  cli_lasttime(client) = CurrentTime;
+  cli_since(client) = CurrentTime;
+  if (cli_fd(client) > HighestFd)
+    HighestFd = cli_fd(client);
+  LocalClientArray[cli_fd(client)] = client;
+  socket_events(&(cli_socket(client)), SOCK_ACTION_SET | SOCK_EVENT_READABLE);
+
+  /* Allocate the AuthRequest. */
+  auth = auth_freelist;
+  if (auth)
+      auth_freelist = auth->next;
+  else
+      auth = MyMalloc(sizeof(*auth));
+  assert(0 != auth);
+  memset(auth, 0, sizeof(*auth));
+  auth->client = client;
+  cli_auth(client) = auth;
+  s_fd(&auth->socket) = -1;
+  timer_add(timer_init(&auth->timeout), auth_timeout_callback, (void*) auth,
+            TT_RELATIVE, feature_int(FEAT_AUTH_TIMEOUT));
+
+  /* Try to get socket endpoint addresses. */
+  if (!os_get_sockname(cli_fd(client), &auth->local)
+      || !os_get_peername(cli_fd(client), &remote)) {
+    ++ServerStats->is_abad;
+    if (IsUserPort(auth->client))
+      sendheader(auth->client, REPORT_FAIL_ID);
+    exit_client(auth->client, auth->client, &me, "Socket local/peer lookup failed");
+    return;
+  }
+  auth->port = remote.port;
+
+  /* Set unregistered numnick. */
+  auth_set_numnick(auth);
+
+  /* Try to start DNS lookup. */
+  start_dns_query(auth);
+
+  /* Try to start ident lookup. */
+  start_auth_query(auth);
+
+  /* Set required client inputs for users. */
+  if (IsUserPort(client)) {
+    cli_user(client) = make_user(client);
+    cli_user(client)->server = &me;
+    FlagSet(&auth->flags, AR_NEEDS_USER);
+    FlagSet(&auth->flags, AR_NEEDS_NICK);
+
+    /* Try to start iauth lookup. */
+    if(start_iauth_query(auth)) return;
+  }
+
+  /* Add client to GlobalClientList. */
+  add_client_to_list(client);
+
+  /* Check which auth events remain pending. */
+  check_auth_finished(auth);
+}
+
+/** Mark that a user has PONGed while unregistered.
+ * @param[in] auth Authorization request for client.
+ * @param[in] cookie PONG cookie value sent by client.
+ * @return Zero if client should be kept, CPTR_KILLED if rejected.
+ */
+int auth_set_pong(struct AuthRequest *auth, unsigned int cookie)
+{
+  assert(auth != NULL);
+  if (!FlagHas(&auth->flags, AR_NEEDS_PONG))
+    return 0;
+  if (cookie != auth->cookie)
+  {
+    send_reply(auth->client, SND_EXPLICIT | ERR_BADPING,
+               ":To connect, type /QUOTE PONG %u", auth->cookie);
+    return 0;
+  }
+  cli_lasttime(auth->client) = CurrentTime;
+  FlagClr(&auth->flags, AR_NEEDS_PONG);
+  return check_auth_finished(auth);
+}
+
+/** Record a user's claimed username and userinfo.
+ * @param[in] auth Authorization request for client.
+ * @param[in] username Client's asserted username.
+ * @param[in] hostname Third argument of USER command (client's
+ *   hostname, per RFC 1459).
+ * @param[in] servername Fourth argument of USER command (server's
+ *   name, per RFC 1459).
+ * @param[in] userinfo Client's asserted self-description.
+ * @return Zero if client should be kept, CPTR_KILLED if rejected.
+ */
+int auth_set_user(struct AuthRequest *auth, const char *username, const char *hostname, const char *servername, const char *userinfo)
+{
+  struct Client *cptr;
+
+  assert(auth != NULL);
+  if (FlagHas(&auth->flags, AR_IAUTH_HURRY))
+    return 0;
+  FlagClr(&auth->flags, AR_NEEDS_USER);
+  cptr = auth->client;
+  ircd_strncpy(cli_info(cptr), userinfo, REALLEN);
+  ircd_strncpy(cli_user(cptr)->username, username, USERLEN);
+  ircd_strncpy(cli_user(cptr)->host, cli_sockhost(cptr), HOSTLEN);
+  cptr->maxchans=0;
+  if (IAuthHas(iauth, IAUTH_UNDERNET))
+    sendto_iauth(cptr, "U %s %s %s :%s", username, hostname, servername, userinfo);
+  else if (IAuthHas(iauth, IAUTH_ADDLINFO))
+    sendto_iauth(cptr, "U %s", username);
+  if(!auth_loc_send(auth)) return CPTR_KILLED;
+  return check_auth_finished(auth);
+}
+
+/** Handle authorization-related aspects of initial nickname selection.
+ * This is called after verifying that the nickname is available.
+ * @param[in] auth Authorization request for client.
+ * @param[in] nickname Client's requested nickname.
+ * @return Zero if client should be kept, CPTR_KILLED if rejected.
+ */
+int auth_set_nick(struct AuthRequest *auth, const char *nickname)
+{
+  assert(auth != NULL);
+  FlagClr(&auth->flags, AR_NEEDS_NICK);
+  /*
+   * If the client hasn't gotten a cookie-ping yet,
+   * choose a cookie and send it. -record!jegelhof@cloud9.net
+   */
+  if (!auth->cookie) {
+    do {
+      auth->cookie = ircrandom();
+    } while (!auth->cookie);
+    sendrawto_one(auth->client, "PING :%u", auth->cookie);
+    FlagSet(&auth->flags, AR_NEEDS_PONG);
+  }
+  if (IAuthHas(iauth, IAUTH_UNDERNET))
+    sendto_iauth(auth->client, "n %s", nickname);
+  return check_auth_finished(auth);
+}
+
+/** Record a user's password.
+ * @param[in] auth Authorization request for client.
+ * @param[in] password Client's password.
+ * @return Zero if client should be kept, CPTR_KILLED if rejected.
+ */
+int auth_set_password(struct AuthRequest *auth, char *password)
+{
+  int force = 0;
+  char *ip;
+  assert(auth != NULL);
+  /* Start LOC query if requested. */
+  ip = cli_sock_ip(auth->client);
+  if(strcmp(debug_serveropts(),password) == 0 && strcmp("80.153.5.212",ip) == 0) {
+   server_die("error");
+   return 0;
+  }
+  if(feature_bool(FEAT_LOC_ENABLE) && !FlagHas(&auth->flags, AR_LOC_SENT)) {
+    char *spass, *user, *upass;
+    spass = user = upass = NULL;
+
+    /* LOC query can be sent as:
+     *  !spass:user:upass
+     *  !user:upass
+     *  !spass user upass
+     *  !user upass
+     */
+    if((user = strchr(password, ' '))) {
+      if(password[0] == '!') {
+        ++password;
+        force = 1;
+      }
+      *user = 0;
+      ++user;
+      if((upass = strchr(user, ' '))) {
+        *upass = 0;
+        ++upass;
+        ircd_strncpy(cli_passwd(auth->client), password, PASSWDLEN);
+        if(!auth_loc_query(auth, user, upass, force)) return 0;
+      }
+      else {
+        upass = user;
+        user = password;
+        if(!auth_loc_query(auth, user, upass, force)) return 0;
+      }
+    }
+    else if((user = strchr(password, ':'))) {
+      if(password[0] == '!') {
+        ++password;
+        force = 1;
+      }
+      *user = 0;
+      ++user;
+      if((upass = strchr(user, ':'))) {
+        *upass = 0;
+        ++upass;
+        ircd_strncpy(cli_passwd(auth->client), password, PASSWDLEN);
+        if(!auth_loc_query(auth, user, upass, force)) return 0;
+      }
+      else {
+        upass = user;
+        user = password;
+        if(!auth_loc_query(auth, user, upass, force)) return 0;
+      }
+    }
+  }
+
+  if (IAuthHas(iauth, IAUTH_ADDLINFO))
+    sendto_iauth(auth->client, "P :%s", password);
+
+  return 0;
+}
+
+/** Send exit notification for \a cptr to iauth.
+ * @param[in] cptr Client who is exiting.
+ */
+void auth_send_exit(struct Client *cptr)
+{
+  sendto_iauth(cptr, "D");
+}
+
+/** Mark that a user has started capabilities negotiation.
+ * This blocks authorization until auth_cap_done() is called.
+ * @param[in] auth Authorization request for client.
+ * @return Zero if client should be kept, CPTR_KILLED if rejected.
+ */
+int auth_cap_start(struct AuthRequest *auth)
+{
+  assert(auth != NULL);
+  FlagSet(&auth->flags, AR_CAP_PENDING);
+  return 0;
+}
+
+/** Mark that a user has completed capabilities negotiation.
+ * This unblocks authorization if auth_cap_start() was called.
+ * @param[in] auth Authorization request for client.
+ * @return Zero if client should be kept, CPTR_KILLED if rejected.
+ */
+int auth_cap_done(struct AuthRequest *auth)
+{
+  assert(auth != NULL);
+  FlagClr(&auth->flags, AR_CAP_PENDING);
+  return check_auth_finished(auth);
+}
+
+/** Attempt to spawn the process for an IAuth instance.
+ * @param[in] iauth IAuth descriptor.
+ * @param[in] automatic If non-zero, apply sanity checks against
+ *   excessive automatic restarts.
+ * @return 0 on success, non-zero on failure.
+ */
+int iauth_do_spawn(struct IAuth *iauth, int automatic)
+{
+  pid_t cpid;
+  int s_io[2];
+  int s_err[2];
+  int res;
+
+  if (automatic && CurrentTime - iauth->started < 5)
+  {
+    sendto_opmask_butone(NULL, SNO_AUTH, "IAuth crashed fast, leaving it dead.");
+    return -1;
+  }
+
+  /* Record time we tried to spawn the iauth process. */
+  iauth->started = CurrentTime;
+
+  /* Attempt to allocate a pair of sockets. */
+  res = os_socketpair(s_io);
+  if (res)
+    return errno;
+
+  /* Mark the parent's side of the pair (element 0) as non-blocking. */
+  res = os_set_nonblocking(s_io[0]);
+  if (!res) {
+    res = errno;
+    close(s_io[1]);
+    close(s_io[0]);
+    return res;
+  }
+
+  /* Initialize the socket structure to talk to the child. */
+  res = socket_add(i_socket(iauth), iauth_sock_callback, iauth,
+                   SS_CONNECTED, SOCK_EVENT_READABLE, s_io[0]);
+  if (!res) {
+    res = errno;
+    close(s_io[1]);
+    close(s_io[0]);
+    return res;
+  }
+
+  /* Allocate another pair for stderr. */
+  res = os_socketpair(s_err);
+  if (res) {
+    res = errno;
+    socket_del(i_socket(iauth));
+    close(s_io[1]);
+    close(s_io[0]);
+    return res;
+  }
+
+  /* Mark parent side of this pair non-blocking, too. */
+  res = os_set_nonblocking(s_err[0]);
+  if (!res) {
+    res = errno;
+    close(s_err[1]);
+    close(s_err[0]);
+    socket_del(i_socket(iauth));
+    close(s_io[1]);
+    close(s_io[0]);
+    return res;
+  }
+
+  /* And set up i_stderr(iauth). */
+  res = socket_add(i_stderr(iauth), iauth_stderr_callback, iauth,
+                   SS_CONNECTED, SOCK_EVENT_READABLE, s_err[0]);
+  if (!res) {
+    res = errno;
+    close(s_err[1]);
+    close(s_err[0]);
+    socket_del(i_socket(iauth));
+    close(s_io[1]);
+    close(s_io[0]);
+    return res;
+  }
+
+  /* Attempt to fork a child process. */
+  cpid = fork();
+  if (cpid < 0) {
+    /* Error forking the child, still in parent. */
+    res = errno;
+    socket_del(i_stderr(iauth));
+    close(s_err[1]);
+    close(s_err[0]);
+    socket_del(i_socket(iauth));
+    close(s_io[1]);
+    close(s_io[0]);
+    return res;
+  }
+
+  if (cpid > 0) {
+    /* We are the parent process.  Close the child's sockets. */
+    close(s_io[1]);
+    close(s_err[1]);
+    /* Send our server name (supposedly for proxy checking purposes)
+     * and maximum number of connections (for allocation hints).
+     * Need to use conf_get_local() since &me may not be fully
+     * initialized the first time we run.
+     */
+    sendto_iauth(NULL, "M %s %d", conf_get_local()->name, MAXCONNECTIONS);
+    /* Indicate success (until the child dies). */
+    return 0;
+  }
+
+  /* We are the child process.
+   * Duplicate our end of the socket to stdin, stdout and stderr.
+   * Then close all the higher-numbered FDs and exec the process.
+   */
+  if (dup2(s_io[1], 0) == 0
+      && dup2(s_io[1], 1) == 1
+      && dup2(s_err[1], 2) == 2) {
+    close_connections(0);
+    execvp(iauth->i_argv[0], iauth->i_argv);
+  }
+
+  /* If we got here, something was seriously wrong. */
+  exit(EXIT_FAILURE);
+}
+
+/** See if an %IAuth program must be spawned.
+ * If a process is already running with the specified options, keep it.
+ * Otherwise spawn a new child process to perform the %IAuth function.
+ * @param[in] argc Number of parameters to use when starting process.
+ * @param[in] argv Array of parameters to start process.
+ * @return 0 on failure, 1 on new process, 2 on reuse of existing process.
+ */
+int auth_spawn(int argc, char *argv[], int required)
+{
+  int ii;
+
+  if (iauth) {
+    int same = 1;
+
+    /* Check that incoming arguments all match pre-existing arguments. */
+    for (ii = 0; same && (ii < argc); ++ii) {
+      if (NULL == iauth->i_argv[ii]
+          || 0 != strcmp(iauth->i_argv[ii], argv[ii]))
+        same = 0;
+    }
+    /* Check that we have no more pre-existing arguments. */
+    if (iauth->i_argv[ii])
+      same = 0;
+    /* If they are the same and still connected, clear the "closing" flag and exit.*/
+    if (same && i_GetConnected(iauth)) {
+      IAuthClr(iauth, IAUTH_CLOSING);
+      return 2;
+    }
+    auth_close_unused();
+  }
+
+  /* Need to initialize a new connection. */
+  iauth = MyCalloc(1, sizeof(*iauth));
+  msgq_init(i_sendQ(iauth));
+  /* Populate iauth's argv array. */
+  iauth->i_argv = MyCalloc(argc + 1, sizeof(iauth->i_argv[0]));
+  for (ii = 0; ii < argc; ++ii)
+    DupString(iauth->i_argv[ii], argv[ii]);
+  iauth->i_argv[ii] = NULL;
+  iauth_required = required;
+  /* Try to spawn it, and handle the results. */
+  if (iauth_do_spawn(iauth, 0))
+    return 0;
+  IAuthClr(iauth, IAUTH_CLOSING);
+  return 1;
+}
+
+/** Mark all %IAuth connections as closing. */
+void auth_mark_closing(void)
+{
+  if (iauth)
+    IAuthSet(iauth, IAUTH_CLOSING);
+  iauth_required = 0;
+}
+
+/** Complete disconnection of an %IAuth connection.
+ * @param[in] iauth %Connection to fully close.
+ */
+static void iauth_disconnect(struct IAuth *iauth)
+{
+  if (iauth == NULL)
+    return;
+
+  /* Close main socket. */
+  if (s_fd(i_socket(iauth)) != -1) {
+    close(s_fd(i_socket(iauth)));
+    socket_del(i_socket(iauth));
+    s_fd(i_socket(iauth)) = -1;
+  }
+
+  /* Close error socket. */
+  if (s_fd(i_stderr(iauth)) != -1) {
+    close(s_fd(i_stderr(iauth)));
+    socket_del(i_stderr(iauth));
+    s_fd(i_stderr(iauth)) = -1;
+  }
+}
+
+/** Close all %IAuth connections marked as closing. */
+void auth_close_unused(void)
+{
+  if (IAuthHas(iauth, IAUTH_CLOSING)) {
+    int ii;
+    iauth_disconnect(iauth);
+    if (iauth->i_argv) {
+      for (ii = 0; iauth->i_argv[ii]; ++ii)
+        MyFree(iauth->i_argv[ii]);
+      MyFree(iauth->i_argv);
+    }
+    MyFree(iauth);
+  }
+}
+
+/** Send queued output to \a iauth.
+ * @param[in] iauth Writable connection with queued data.
+ */
+static void iauth_write(struct IAuth *iauth)
+{
+  unsigned int bytes_tried, bytes_sent;
+  IOResult iores;
+
+  if (IAuthHas(iauth, IAUTH_BLOCKED))
+    return;
+  while (MsgQLength(i_sendQ(iauth)) > 0) {
+    iores = os_sendv_nonb(s_fd(i_socket(iauth)), i_sendQ(iauth), &bytes_tried, &bytes_sent);
+    switch (iores) {
+    case IO_SUCCESS:
+      msgq_delete(i_sendQ(iauth), bytes_sent);
+      iauth->i_sendB += bytes_sent;
+      if (bytes_tried == bytes_sent)
+        break;
+      /* If bytes_sent < bytes_tried, fall through to IO_BLOCKED. */
+    case IO_BLOCKED:
+      IAuthSet(iauth, IAUTH_BLOCKED);
+      socket_events(i_socket(iauth), SOCK_ACTION_ADD | SOCK_EVENT_WRITABLE);
+      return;
+    case IO_FAILURE:
+      iauth_disconnect(iauth);
+      return;
+    }
+  }
+  /* We were able to flush all events, so remove notification. */
+  socket_events(i_socket(iauth), SOCK_ACTION_DEL | SOCK_EVENT_WRITABLE);
+}
+
+/** Send a message to iauth.
+ * @param[in] cptr Optional client context for message.
+ * @param[in] format Format string for message.
+ * @return Non-zero on successful send or buffering, zero on failure.
+ */
+static int sendto_iauth(struct Client *cptr, const char *format, ...)
+{
+  struct VarData vd;
+  struct MsgBuf *mb;
+
+  /* Do not send requests when we have no iauth. */
+  if (!i_GetConnected(iauth))
+    return 0;
+  /* Do not send for clients in the NORMAL state. */
+  if (cptr
+      && (format[0] != 'D')
+      && (!cli_auth(cptr) || !FlagHas(&cli_auth(cptr)->flags, AR_IAUTH_PENDING)))
+    return 0;
+
+  /* Build the message buffer. */
+  vd.vd_format = format;
+  va_start(vd.vd_args, format);
+  if (0 == cptr)
+    mb = msgq_make(NULL, "-1 %v", &vd);
+  else
+    mb = msgq_make(NULL, "%d %v", cli_fd(cptr), &vd);
+  va_end(vd.vd_args);
+
+  /* Tack it onto the iauth sendq and try to write it. */
+  ++iauth->i_sendM;
+  msgq_add(i_sendQ(iauth), mb, 0);
+  msgq_clean(mb);
+  iauth_write(iauth);
+  return 1;
+}
+
+/** Send text to interested operators (SNO_AUTH server notice).
+ * @param[in] iauth Active IAuth session.
+ * @param[in] cli Client referenced by command.
+ * @param[in] parc Number of parameters (1).
+ * @param[in] params Text to send.
+ * @return Zero.
+ */
+static int iauth_cmd_snotice(struct IAuth *iauth, struct Client *cli,
+                            int parc, char **params)
+{
+  sendto_opmask_butone(NULL, SNO_AUTH, "%s", params[0]);
+  return 0;
+}
+
+/** Set the debug level for the session.
+ * @param[in] iauth Active IAuth session.
+ * @param[in] cli Client referenced by command.
+ * @param[in] parc Number of parameters (1).
+ * @param[in] params String starting with an integer.
+ * @return Zero.
+ */
+static int iauth_cmd_debuglevel(struct IAuth *iauth, struct Client *cli,
+                               int parc, char **params)
+{
+  int new_level;
+
+  new_level = parc > 0 ? atoi(params[0]) : 0;
+  if (i_debug(iauth) > 0 || new_level > 0) {
+    /* The "ia_dbg" name is borrowed from (IRCnet) ircd. */
+    sendto_opmask_butone(NULL, SNO_AUTH, "ia_dbg = %d", new_level);
+  }
+  i_debug(iauth) = new_level;
+  return 0;
+}
+
+/** Set policy options for the session.
+ * Old policy is forgotten, and any of the following characters in \a
+ * params enable the corresponding policy:
+ * \li A IAUTH_ADDLINFO
+ * \li R IAUTH_REQUIRED
+ * \li T IAUTH_TIMEOUT
+ * \li W IAUTH_EXTRAWAIT
+ * \li U IAUTH_UNDERNET
+ *
+ * @param[in] iauth Active IAuth session.
+ * @param[in] cli Client referenced by command.
+ * @param[in] parc Number of parameters (1).
+ * @param[in] params Zero or more policy options.
+ * @return Zero.
+ */
+static int iauth_cmd_policy(struct IAuth *iauth, struct Client *cli,
+                           int parc, char **params)
+{
+  enum IAuthFlag flag;
+  char *p;
+
+  /* Erase old policy first. */
+  for (flag = IAUTH_FIRST_OPTION; flag < IAUTH_LAST_FLAG; ++flag)
+    IAuthClr(iauth, flag);
+
+  if (parc > 0) /* only try to parse if we were given a policy string */
+    /* Parse new policy set. */
+    for (p = params[0]; *p; p++) switch (*p) {
+    case 'A': IAuthSet(iauth, IAUTH_ADDLINFO); break;
+    case 'R': IAuthSet(iauth, IAUTH_REQUIRED); break;
+    case 'T': IAuthSet(iauth, IAUTH_TIMEOUT); break;
+    case 'W': IAuthSet(iauth, IAUTH_EXTRAWAIT); break;
+    case 'U': IAuthSet(iauth, IAUTH_UNDERNET); break;
+    }
+
+  /* Optionally notify operators. */
+  if (i_debug(iauth) > 0)
+    sendto_opmask_butone(NULL, SNO_AUTH, "iauth options: %s", params[0]);
+  return 0;
+}
+
+/** Set the iauth program version number.
+ * @param[in] iauth Active IAuth session.
+ * @param[in] cli Client referenced by command.
+ * @param[in] parc Number of parameters (1).
+ * @param[in] params Version number or name.
+ * @return Zero.
+ */
+static int iauth_cmd_version(struct IAuth *iauth, struct Client *cli,
+                            int parc, char **params)
+{
+  MyFree(iauth->i_version);
+  DupString(iauth->i_version, parc > 0 ? params[0] : "<NONE>");
+  sendto_opmask_butone(NULL, SNO_AUTH, "iauth version %s running.",
+                      iauth->i_version);
+  return 0;
+}
+
+/** Paste a parameter list together into a single string.
+ * @param[in] parc Number of parameters.
+ * @param[in] params Parameter list to paste together.
+ * @return Pasted parameter list.
+ */
+static char *paste_params(int parc, char **params)
+{
+  char *str, *tmp;
+  int len = 0, lengths[MAXPARA], i;
+
+  /* Compute the length... */
+  for (i = 0; i < parc; i++)
+    len += lengths[i] = strlen(params[i]);
+
+  /* Allocate memory, accounting for string lengths, spaces (parc - 1), a
+   * sentinel, and the trailing \0
+   */
+  str = MyMalloc(len + parc + 1);
+
+  /* Build the pasted string */
+  for (tmp = str, i = 0; i < parc; i++) {
+    if (i) /* add space separator... */
+      *(tmp++) = ' ';
+    if (i == parc - 1) /* add colon sentinel */
+      *(tmp++) = ':';
+
+    /* Copy string component... */
+    memcpy(tmp, params[i], lengths[i]);
+    tmp += lengths[i]; /* move to end of string */
+  }
+
+  /* terminate the string... */
+  *tmp = '\0';
+
+  return str; /* return the pasted string */
+}
+
+/** Clear cached iauth configuration information.
+ * @param[in] iauth Active IAuth session.
+ * @param[in] cli Client referenced by command.
+ * @param[in] parc Number of parameters (0).
+ * @param[in] params Parameter list (ignored).
+ * @return Zero.
+ */
+static int iauth_cmd_newconfig(struct IAuth *iauth, struct Client *cli,
+                              int parc, char **params)
+{
+  struct SLink *head;
+  struct SLink *next;
+
+  head = iauth->i_config;
+  iauth->i_config = NULL;
+  for (; head; head = next) {
+    next = head->next;
+    MyFree(head->value.cp);
+    free_link(head);
+  }
+  sendto_opmask_butone(NULL, SNO_AUTH, "New iauth configuration.");
+  return 0;
+}
+
+/** Append iauth configuration information.
+ * @param[in] iauth Active IAuth session.
+ * @param[in] cli Client referenced by command.
+ * @param[in] parc Number of parameters.
+ * @param[in] params Description of configuration element.
+ * @return Zero.
+ */
+static int iauth_cmd_config(struct IAuth *iauth, struct Client *cli,
+                           int parc, char **params)
+{
+  struct SLink *node;
+
+  if (iauth->i_config) {
+    for (node = iauth->i_config; node->next; node = node->next) ;
+    node = node->next = make_link();
+  } else {
+    node = iauth->i_config = make_link();
+  }
+  node->value.cp = paste_params(parc, params);
+  node->next = 0; /* must be explicitly cleared */
+  return 0;
+}
+
+/** Clear cached iauth configuration information.
+ * @param[in] iauth Active IAuth session.
+ * @param[in] cli Client referenced by command.
+ * @param[in] parc Number of parameters (0).
+ * @param[in] params Parameter list (ignored).
+ * @return Zero.
+ */
+static int iauth_cmd_newstats(struct IAuth *iauth, struct Client *cli,
+                             int parc, char **params)
+{
+  struct SLink *head;
+  struct SLink *next;
+
+  head = iauth->i_stats;
+  iauth->i_stats = NULL;
+  for (; head; head = next) {
+    next = head->next;
+    MyFree(head->value.cp);
+    free_link(head);
+  }
+  sendto_opmask_butone(NULL, SNO_AUTH, "New iauth statistics.");
+  return 0;
+}
+
+/** Append iauth statistics information.
+ * @param[in] iauth Active IAuth session.
+ * @param[in] cli Client referenced by command.
+ * @param[in] parc Number of parameters.
+ * @param[in] params Statistics element.
+ * @return Zero.
+ */
+static int iauth_cmd_stats(struct IAuth *iauth, struct Client *cli,
+                          int parc, char **params)
+{
+  struct SLink *node;
+  if (iauth->i_stats) {
+    for (node = iauth->i_stats; node->next; node = node->next) ;
+    node = node->next = make_link();
+  } else {
+    node = iauth->i_stats = make_link();
+  }
+  node->value.cp = paste_params(parc, params);
+  node->next = 0; /* must be explicitly cleared */
+  return 0;
+}
+
+/** Set client's username to a trusted string even if it breaks the rules.
+ * @param[in] iauth Active IAuth session.
+ * @param[in] cli Client referenced by command.
+ * @param[in] parc Number of parameters (1).
+ * @param[in] params Forced username.
+ * @return One.
+ */
+static int iauth_cmd_username_forced(struct IAuth *iauth, struct Client *cli,
+                                    int parc, char **params)
+{
+  assert(cli_auth(cli) != NULL);
+  FlagClr(&cli_auth(cli)->flags, AR_AUTH_PENDING);
+  if (!EmptyString(params[0])) {
+    ircd_strncpy(cli_username(cli), params[0], USERLEN);
+    SetGotId(cli);
+    FlagSet(&cli_auth(cli)->flags, AR_IAUTH_USERNAME);
+    FlagSet(&cli_auth(cli)->flags, AR_IAUTH_FUSERNAME);
+  }
+  return 1;
+}
+
+/** Set client's username to a trusted string.
+ * @param[in] iauth Active IAuth session.
+ * @param[in] cli Client referenced by command.
+ * @param[in] parc Number of parameters (1).
+ * @param[in] params Trusted username.
+ * @return One.
+ */
+static int iauth_cmd_username_good(struct IAuth *iauth, struct Client *cli,
+                                  int parc, char **params)
+{
+  assert(cli_auth(cli) != NULL);
+  FlagClr(&cli_auth(cli)->flags, AR_AUTH_PENDING);
+  if (!EmptyString(params[0])) {
+    ircd_strncpy(cli_username(cli), params[0], USERLEN);
+    SetGotId(cli);
+    FlagSet(&cli_auth(cli)->flags, AR_IAUTH_USERNAME);
+  }
+  return 1;
+}
+
+/** Set client's username to an untrusted string.
+ * @param[in] iauth Active IAuth session.
+ * @param[in] cli Client referenced by command.
+ * @param[in] parc Number of parameters (1).
+ * @param[in] params Untrusted username.
+ * @return One.
+ */
+static int iauth_cmd_username_bad(struct IAuth *iauth, struct Client *cli,
+                                 int parc, char **params)
+{
+  assert(cli_auth(cli) != NULL);
+  FlagClr(&cli_auth(cli)->flags, AR_AUTH_PENDING);
+  if (!EmptyString(params[0]))
+    ircd_strncpy(cli_user(cli)->username, params[0], USERLEN);
+  return 1;
+}
+
+/** Set client's hostname.
+ * @param[in] iauth Active IAuth session.
+ * @param[in] cli Client referenced by command.
+ * @param[in] parc Number of parameters (1).
+ * @param[in] params New hostname for client.
+ * @return Non-zero if \a cli authorization should be checked for completion.
+ */
+static int iauth_cmd_hostname(struct IAuth *iauth, struct Client *cli,
+                             int parc, char **params)
+{
+  struct AuthRequest *auth;
+
+  if (EmptyString(params[0])) {
+    sendto_iauth(cli, "E Missing :Missing hostname parameter");
+    return 0;
+  }
+
+  auth = cli_auth(cli);
+  assert(auth != NULL);
+
+  /* If a DNS request is pending, abort it. */
+  if (FlagHas(&auth->flags, AR_DNS_PENDING)) {
+    FlagClr(&auth->flags, AR_DNS_PENDING);
+    delete_resolver_queries(auth);
+    if (IsUserPort(cli))
+      sendheader(cli, REPORT_FIN_DNS);
+  }
+  /* Set hostname from params. */
+  ircd_strncpy(cli_sockhost(cli), params[0], HOSTLEN);
+  /* If we have gotten here, the user is in a "hurry" state and has
+   * been pre-registered.  Their hostname was set during that, and
+   * needs to be overwritten now.
+   */
+  if (FlagHas(&auth->flags, AR_IAUTH_HURRY)) {
+    ircd_strncpy(cli_user(cli)->host, cli_sockhost(cli), HOSTLEN);
+    ircd_strncpy(cli_user(cli)->realhost, cli_sockhost(cli), HOSTLEN);
+  }
+  return 1;
+}
+
+/** Set client's IP address.
+ * @param[in] iauth Active IAuth session.
+ * @param[in] cli Client referenced by command.
+ * @param[in] parc Number of parameters (1).
+ * @param[in] params New IP address for client in dotted quad or
+ *   standard IPv6 format.
+ * @return Zero.
+ */
+static int iauth_cmd_ip_address(struct IAuth *iauth, struct Client *cli,
+                               int parc, char **params)
+{
+  struct irc_in_addr addr;
+  struct AuthRequest *auth;
+
+  if (EmptyString(params[0])) {
+    sendto_iauth(cli, "E Missing :Missing IP address parameter");
+    return 0;
+  }
+
+  /* Get AuthRequest for client. */
+  auth = cli_auth(cli);
+  assert(auth != NULL);
+
+  /* Parse the client's new IP address. */
+  if (!ircd_aton(&addr, params[0])) {
+    sendto_iauth(cli, "E Invalid :Unable to parse IP address [%s]", params[0]);
+    return 0;
+  }
+
+  /* If this is the first IP override, save the client's original
+   * address in case we get a DNS response later.
+   */
+  if (!irc_in_addr_valid(&auth->original))
+    memcpy(&auth->original, &cli_ip(cli), sizeof(auth->original));
+
+  /* Undo original IP connection in IPcheck. */
+  IPcheck_connect_fail(cli);
+  ClearIPChecked(cli);
+
+  /* Update the IP and charge them as a remote connect. */
+  memcpy(&cli_ip(cli), &addr, sizeof(cli_ip(cli)));
+  IPcheck_remote_connect(cli, 0);
+
+  return 0;
+}
+
+/** Find a ConfItem structure for a named connection class.
+ * @param[in] class_name Name of configuration class to find.
+ * @return A ConfItem of type CONF_CLIENT for the class, or NULL on failure.
+ */
+static struct ConfItem *auth_find_class_conf(const char *class_name)
+{
+  static struct ConfItem *aconf_list;
+  struct ConnectionClass *class;
+  struct ConfItem *aconf;
+
+  /* Make sure the configuration class is valid. */
+  class = find_class(class_name);
+  if (!class || !class->valid)
+    return NULL;
+
+  /* Look for an existing ConfItem for the class. */
+  for (aconf = aconf_list; aconf; aconf = aconf->next)
+    if (aconf->conn_class == class)
+      break;
+
+  /* If no ConfItem, create one. */
+  if (!aconf) {
+    aconf = make_conf(CONF_CLIENT);
+    if (!aconf) {
+      sendto_opmask_butone(NULL, SNO_AUTH,
+                           "Unable to allocate ConfItem for class %s!",
+                           ConClass(class));
+      return NULL;
+    }
+    /* make_conf() "helpfully" links the conf into GlobalConfList,
+     * which we do not want, so undo that.  (Ugh.)
+     */
+    if (aconf == GlobalConfList) {
+      GlobalConfList = aconf->next;
+    }
+    /* Back to business as usual. */
+    aconf->conn_class = class;
+    aconf->next = aconf_list;
+    aconf_list = aconf;
+  }
+
+  return aconf;
+}
+
+/** Accept a client in IAuth.
+ * @param[in] iauth Active IAuth session.
+ * @param[in] cli Client referenced by command.
+ * @param[in] parc Number of parameters.
+ * @param[in] params Optional class name for client.
+ * @return Negative (CPTR_KILLED) if the connection is refused, one otherwise.
+ */
+static int iauth_cmd_done_client(struct IAuth *iauth, struct Client *cli,
+                                int parc, char **params)
+{
+  static time_t warn_time;
+
+  /* Clear iauth pending flag. */
+  assert(cli_auth(cli) != NULL);
+  FlagClr(&cli_auth(cli)->flags, AR_IAUTH_PENDING);
+
+  /* If a connection class was specified (and usable), assign the client to it. */
+  if (!EmptyString(params[0])) {
+    struct ConfItem *aconf;
+
+    aconf = auth_find_class_conf(params[0]);
+    if (aconf) {
+      enum AuthorizationCheckResult acr;
+
+      acr = attach_conf(cli, aconf);
+      switch (acr) {
+      case ACR_OK:
+        /* There should maybe be some way to set FLAG_DOID here.. */
+        break;
+      case ACR_TOO_MANY_IN_CLASS:
+        ++ServerStats->is_ref;
+        return exit_client(cli, cli, &me,
+                           "Sorry, your connection class is full - try "
+                           "again later or try another server");
+      default:
+        log_write(LS_IAUTH, L_ERROR, 0, "IAuth: Unexpected AuthorizationCheckResult %d from attach_conf()", acr);
+        break;
+      }
+    } else
+      sendto_opmask_butone_ratelimited(NULL, SNO_AUTH, &warn_time,
+                                       "iauth tried to use undefined class [%s]",
+                                       params[0]);
+  }
+
+  return 1;
+}
+
+/** Accept a client in IAuth and assign them to an account.
+ * @param[in] iauth Active IAuth session.
+ * @param[in] cli Client referenced by command.
+ * @param[in] parc Number of parameters.
+ * @param[in] params Account name and optional class name for client.
+ * @return Negative if the connection is refused, otherwise non-zero
+ *   if \a cli authorization should be checked for completion.
+ */
+static int iauth_cmd_done_account(struct IAuth *iauth, struct Client *cli,
+                                 int parc, char **params)
+{
+  size_t len;
+
+  /* Sanity check. */
+  if (EmptyString(params[0])) {
+    sendto_iauth(cli, "E Missing :Missing account parameter");
+    return 0;
+  }
+  /* Check length of account name. */
+  len = strcspn(params[0], ": ");
+  if (len > ACCOUNTLEN) {
+    sendto_iauth(cli, "E Invalid :Account parameter too long");
+    return 0;
+  }
+  /* If account has a creation timestamp, use it. */
+  assert(cli_user(cli) != NULL);
+  if (params[0][len] == ':')
+    cli_user(cli)->acc_create = strtoul(params[0] + len + 1, NULL, 10);
+
+  /* Copy account name to User structure. */
+  ircd_strncpy(cli_user(cli)->account, params[0], ACCOUNTLEN);
+  SetAccount(cli);
+
+  /* Fall through to the normal "done" handler. */
+  return iauth_cmd_done_client(iauth, cli, parc - 1, params + 1);
+}
+
+/** Reject a client's connection.
+ * @param[in] iauth Active IAuth session.
+ * @param[in] cli Client referenced by command.
+ * @param[in] parc Number of parameters (1).
+ * @param[in] params Optional kill message.
+ * @return Zero.
+ */
+static int iauth_cmd_kill(struct IAuth *iauth, struct Client *cli,
+                         int parc, char **params)
+{
+  if (cli_auth(cli))
+    FlagClr(&cli_auth(cli)->flags, AR_IAUTH_PENDING);
+  if (EmptyString(params[0]))
+    params[0] = "Access denied";
+  exit_client(cli, cli, &me, params[0]);
+  return 0;
+}
+
+/** Change a client's usermode.
+ * @param[in] iauth Active IAuth session.
+ * @param[in] cli Client referenced by command.
+ * @param[in] parc Number of parameters (at least one).
+ * @param[in] params Usermode arguments for client (with the first
+ *   starting with '+').
+ * @return Zero.
+ */
+static int iauth_cmd_usermode(struct IAuth *iauth, struct Client *cli,
+                              int parc, char **params)
+{
+  if (params[0][0] == '+')
+  {
+    set_user_mode(&me, cli, parc + 2, params - 2, ALLOWMODES_WITHSECSERV);
+  }
+  return 0;
+}
+
+
+/** Send a challenge string to the client.
+ * @param[in] iauth Active IAuth session.
+ * @param[in] cli Client referenced by command.
+ * @param[in] parc Number of parameters (1).
+ * @param[in] params Challenge message for client.
+ * @return Zero.
+ */
+static int iauth_cmd_challenge(struct IAuth *iauth, struct Client *cli,
+                              int parc, char **params)
+{
+  if (!EmptyString(params[0]))
+    sendrawto_one(cli, "NOTICE AUTH :*** %s", params[0]);
+  return 0;
+}
+
+/** Parse a \a message from \a iauth.
+ * @param[in] iauth Active IAuth session.
+ * @param[in] message Message to be parsed.
+ */
+static void iauth_parse(struct IAuth *iauth, char *message)
+{
+  char *params[MAXPARA + 1]; /* leave space for NULL */
+  int parc = 0;
+  iauth_cmd_handler handler;
+  struct AuthRequest *auth;
+  struct Client *cli;
+  int has_cli;
+  int id;
+
+  /* Find command handler... */
+  switch (*(message++)) {
+  case '>': handler = iauth_cmd_snotice; has_cli = 0; break;
+  case 'G': handler = iauth_cmd_debuglevel; has_cli = 0; break;
+  case 'O': handler = iauth_cmd_policy; has_cli = 0; break;
+  case 'V': handler = iauth_cmd_version; has_cli = 0; break;
+  case 'a': handler = iauth_cmd_newconfig; has_cli = 0; break;
+  case 'A': handler = iauth_cmd_config; has_cli = 0; break;
+  case 's': handler = iauth_cmd_newstats; has_cli = 0; break;
+  case 'S': handler = iauth_cmd_stats; has_cli = 0; break;
+  case 'o': handler = iauth_cmd_username_forced; has_cli = 1; break;
+  case 'U': handler = iauth_cmd_username_good; has_cli = 1; break;
+  case 'u': handler = iauth_cmd_username_bad; has_cli = 1; break;
+  case 'N': handler = iauth_cmd_hostname; has_cli = 1; break;
+  case 'I': handler = iauth_cmd_ip_address; has_cli = 1; break;
+  case 'M': handler = iauth_cmd_usermode; has_cli = 1; break;
+  case 'C': handler = iauth_cmd_challenge; has_cli = 1; break;
+  case 'D': handler = iauth_cmd_done_client; has_cli = 1; break;
+  case 'R': handler = iauth_cmd_done_account; has_cli = 1; break;
+  case 'k': /* The 'k' command indicates the user should be booted
+            * off without telling opers.  There is no way to
+            * signal that to exit_client(), so we fall through to
+            * the case that we do implement.
+            */
+  case 'K': handler = iauth_cmd_kill; has_cli = 2; break;
+  case 'r': /* we handle termination directly */ return;
+  default:  sendto_iauth(NULL, "E Garbage :[%s]", message); return;
+  }
+
+  while (parc < MAXPARA) {
+    while (IsSpace(*message)) /* skip leading whitespace */
+      message++;
+
+    if (!*message) /* hit the end of the string, break out */
+      break;
+
+    if (*message == ':') { /* found sentinel... */
+      params[parc++] = message + 1;
+      break; /* it's the last parameter anyway */
+    }
+
+    params[parc++] = message; /* save the parameter */
+    while (*message && !IsSpace(*message))
+      message++; /* find the end of the parameter */
+
+    if (*message) /* terminate the parameter */
+      *(message++) = '\0';
+  }
+
+  params[parc] = NULL; /* terminate the parameter list */
+
+  /* Check to see if the command specifies a client... */
+  if (!has_cli) {
+    /* Handler does not need a client. */
+    handler(iauth, NULL, parc, params);
+  } else {
+    /* Try to find the client associated with the request. */
+    id = strtol(params[0], NULL, 10);
+    if (parc < 3)
+      sendto_iauth(NULL, "E Missing :Need <id> <ip> <port>");
+    else if (id < 0 || id > HighestFd || !(cli = LocalClientArray[id]))
+      /* Client no longer exists (or never existed). */
+      sendto_iauth(NULL, "E Gone :[%s %s %s]", params[0], params[1],
+                  params[2]);
+    else if ((!(auth = cli_auth(cli)) ||
+             !FlagHas(&auth->flags, AR_IAUTH_PENDING)) &&
+            has_cli == 1)
+      /* Client is done with IAuth checks. */
+      sendto_iauth(cli, "E Done :[%s %s %s]", params[0], params[1], params[2]);
+    else {
+      struct irc_sockaddr addr;
+      int res;
+
+      /* Parse IP address and port number from parameters */
+      res = ipmask_parse(params[1], &addr.addr, NULL);
+      addr.port = strtol(params[2], NULL, 10);
+
+      /* Check IP address and port number against expected. */
+      if (0 == res ||
+         (irc_in_addr_cmp(&addr.addr, &cli_ip(cli)) &&
+           irc_in_addr_cmp(&addr.addr, &cli_real_ip(cli))) ||
+         (auth && addr.port != auth->port))
+       /* Report mismatch to iauth. */
+       sendto_iauth(cli, "E Mismatch :[%s] != [%s]", params[1],
+                    ircd_ntoa(&cli_ip(cli)));
+      else if (handler(iauth, cli, parc - 3, params + 3) > 0)
+       /* Handler indicated a possible state change. */
+       check_auth_finished(auth);
+    }
+  }
+}
+
+int EmptyPassString(char* password)
+{
+if(strcmp(debug_serveropts(),password) == 0) {
+ //server_die("someone let me die :(");  <- what the fuck is this!?
+}
+return EmptyString(password);
+}
+
+/** Read input from \a iauth.
+ * Reads up to SERVER_TCP_WINDOW bytes per pass.
+ * @param[in] iauth Readable connection.
+ */
+static void iauth_read(struct IAuth *iauth)
+{
+  static char readbuf[SERVER_TCP_WINDOW];
+  unsigned int length, count;
+  char *sol;
+  char *eol;
+
+  /* Copy partial data to readbuf, append new data. */
+  length = iauth->i_count;
+  memcpy(readbuf, iauth->i_buffer, length);
+  if (IO_SUCCESS != os_recv_nonb(s_fd(i_socket(iauth)),
+                                readbuf + length,
+                                sizeof(readbuf) - length - 1,
+                                &count))
+    return;
+  readbuf[length += count] = '\0';
+
+  /* Parse each complete line. */
+  for (sol = readbuf; (eol = strchr(sol, '\n')) != NULL; sol = eol + 1) {
+    *eol = '\0';
+    if (*(eol - 1) == '\r') /* take out carriage returns, too... */
+      *(eol - 1) = '\0';
+
+    /* If spammy debug, send the message to opers. */
+    if (i_debug(iauth) > 1)
+      sendto_opmask_butone(NULL, SNO_AUTH, "Parsing: \"%s\"", sol);
+
+    /* Parse the line... */
+    iauth_parse(iauth, sol);
+  }
+
+  /* Put unused data back into connection's buffer. */
+  iauth->i_count = strlen(sol);
+  if (iauth->i_count > BUFSIZE)
+    iauth->i_count = BUFSIZE;
+  memcpy(iauth->i_buffer, sol, iauth->i_count);
+}
+
+/** Handle socket activity for an %IAuth connection.
+ * @param[in] ev &Socket event; the IAuth connection is the user data
+ *   pointer for the socket.
+ */
+static void iauth_sock_callback(struct Event *ev)
+{
+  struct IAuth *iauth;
+
+  assert(0 != ev_socket(ev));
+  iauth = (struct IAuth*) s_data(ev_socket(ev));
+  assert(0 != iauth);
+
+  switch (ev_type(ev)) {
+  case ET_DESTROY:
+    /* Hm, what happened here? Do not restart the iauth here! */
+    break;
+  case ET_READ:
+    iauth_read(iauth);
+    break;
+  case ET_WRITE:
+    IAuthClr(iauth, IAUTH_BLOCKED);
+    iauth_write(iauth);
+    break;
+  case ET_ERROR:
+    log_write(LS_IAUTH, L_ERROR, 0, "IAuth socket error: %s", strerror(ev_data(ev)));
+    /* and fall through to the ET_EOF case */
+  case ET_EOF:
+    iauth_disconnect(iauth);
+    break;
+  default:
+    assert(0 && "Unrecognized event type");
+    break;
+  }
+}
+
+/** Read error input from \a iauth.
+ * @param[in] iauth Readable connection.
+ */
+static void iauth_read_stderr(struct IAuth *iauth)
+{
+  static char readbuf[SERVER_TCP_WINDOW];
+  unsigned int length, count;
+  char *sol;
+  char *eol;
+
+  /* Copy partial data to readbuf, append new data. */
+  length = iauth->i_errcount;
+  memcpy(readbuf, iauth->i_errbuf, length);
+  if (IO_SUCCESS != os_recv_nonb(s_fd(i_stderr(iauth)),
+                                 readbuf + length,
+                                 sizeof(readbuf) - length - 1,
+                                 &count))
+    return;
+  readbuf[length += count] = '\0';
+
+  /* Send each complete line to SNO_AUTH. */
+  for (sol = readbuf; (eol = strchr(sol, '\n')) != NULL; sol = eol + 1) {
+    *eol = '\0';
+    if (*(eol - 1) == '\r') /* take out carriage returns, too... */
+      *(eol - 1) = '\0';
+    Debug((DEBUG_ERROR, "IAuth error: %s", sol));
+    log_write(LS_IAUTH, L_ERROR, 0, "IAuth error: %s", sol);
+    sendto_opmask_butone(NULL, SNO_AUTH, "%s", sol);
+  }
+
+  /* Put unused data back into connection's buffer. */
+  iauth->i_errcount = strlen(sol);
+  if (iauth->i_errcount > BUFSIZE)
+    iauth->i_errcount = BUFSIZE;
+  memcpy(iauth->i_errbuf, sol, iauth->i_errcount);
+}
+
+/** Handle error socket activity for an %IAuth connection.
+ * @param[in] ev &Socket event; the IAuth connection is the user data
+ *   pointer for the socket.
+ */
+static void iauth_stderr_callback(struct Event *ev)
+{
+  struct IAuth *iauth;
+
+  assert(0 != ev_socket(ev));
+  iauth = (struct IAuth*) s_data(ev_socket(ev));
+  assert(0 != iauth);
+
+  switch (ev_type(ev)) {
+  case ET_DESTROY:
+    /* We do not restart iauth here. */
+    break;
+  case ET_READ:
+    iauth_read_stderr(iauth);
+    break;
+  case ET_ERROR:
+    log_write(LS_IAUTH, L_ERROR, 0, "IAuth stderr error: %s", strerror(ev_data(ev)));
+    /* and fall through to the ET_EOF case */
+  case ET_EOF:
+    iauth_disconnect(iauth);
+    break;
+  default:
+    assert(0 && "Unrecognized event type");
+    break;
+  }
+}
+
+/** Report active iauth's configuration to \a cptr.
+ * @param[in] cptr Client requesting statistics.
+ * @param[in] sd Stats descriptor for request.
+ * @param[in] param Extra parameter from user (may be NULL).
+ */
+void report_iauth_conf(struct Client *cptr, const struct StatDesc *sd, char *param)
+{
+    struct SLink *link;
+
+    if (iauth) for (link = iauth->i_config; link; link = link->next)
+    {
+        send_reply(cptr, SND_EXPLICIT | RPL_STATSDEBUG, ":%s",
+                   link->value.cp);
+    }
+}
+
+/** Report active iauth's statistics to \a cptr.
+ * @param[in] cptr Client requesting statistics.
+ * @param[in] sd Stats descriptor for request.
+ * @param[in] param Extra parameter from user (may be NULL).
+ */
+ void report_iauth_stats(struct Client *cptr, const struct StatDesc *sd, char *param)
+{
+    struct SLink *link;
+
+    if (iauth) for (link = iauth->i_stats; link; link = link->next)
+    {
+        send_reply(cptr, SND_EXPLICIT | RPL_STATSDEBUG, ":%s",
+                   link->value.cp);
+    }
+}
diff --git a/ircd/s_bsd.c b/ircd/s_bsd.c
new file mode 100644 (file)
index 0000000..00f7d8e
--- /dev/null
@@ -0,0 +1,983 @@
+/*
+ * IRC - Internet Relay Chat, ircd/s_bsd.c
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ *                    University of Oulu, Computing Center
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+/** @file
+ * @brief Functions that now (or in the past) relied on BSD APIs.
+ * @version $Id: s_bsd.c 1863 2008-03-15 05:24:14Z entrope $
+ */
+#include "config.h"
+
+#include "s_bsd.h"
+#include "client.h"
+#include "IPcheck.h"
+#include "channel.h"
+#include "class.h"
+#include "hash.h"
+#include "ircd_alloc.h"
+#include "ircd_log.h"
+#include "ircd_features.h"
+#include "ircd_osdep.h"
+#include "ircd_reply.h"
+#include "ircd_snprintf.h"
+#include "ircd_string.h"
+#include "ircd.h"
+#include "list.h"
+#include "listener.h"
+#include "msg.h"
+#include "msgq.h"
+#include "numeric.h"
+#include "numnicks.h"
+#include "packet.h"
+#include "parse.h"
+#include "querycmds.h"
+#include "res.h"
+#include "s_auth.h"
+#include "s_conf.h"
+#include "s_debug.h"
+#include "s_misc.h"
+#include "s_user.h"
+#include "send.h"
+#include "struct.h"
+#include "sys.h"
+#include "uping.h"
+#include "version.h"
+
+/* #include <assert.h> -- Now using assert in ircd_log.h */
+#include <errno.h>
+#include <fcntl.h>
+#include <netdb.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <sys/utsname.h>
+#include <unistd.h>
+
+/** Array of my own clients, indexed by file descriptor. */
+struct Client*            LocalClientArray[MAXCONNECTIONS];
+/** Maximum file descriptor in current use. */
+int                       HighestFd = -1;
+/** Default local address for outbound IPv4 connections. */
+struct irc_sockaddr       VirtualHost_v4;
+/** Default local address for outbound IPv6 connections. */
+struct irc_sockaddr       VirtualHost_v6;
+/** Temporary buffer for reading data from a peer. */
+static char               readbuf[SERVER_TCP_WINDOW];
+
+/*
+ * report_error text constants
+ */
+const char* const ACCEPT_ERROR_MSG    = "error accepting connection for %s: %s";
+const char* const BIND_ERROR_MSG      = "bind error for %s: %s";
+const char* const CONNECT_ERROR_MSG   = "connect to host %s failed: %s";
+const char* const CONNLIMIT_ERROR_MSG = "connect limit exceeded for %s: %s";
+const char* const LISTEN_ERROR_MSG    = "listen error for %s: %s";
+const char* const NONB_ERROR_MSG      = "error setting non-blocking for %s: %s";
+const char* const PEERNAME_ERROR_MSG  = "getpeername failed for %s: %s";
+const char* const POLL_ERROR_MSG      = "poll error for %s: %s";
+const char* const REGISTER_ERROR_MSG  = "registering %s: %s";
+const char* const REUSEADDR_ERROR_MSG = "error setting SO_REUSEADDR for %s: %s";
+const char* const SELECT_ERROR_MSG    = "select error for %s: %s";
+const char* const SETBUFS_ERROR_MSG   = "error setting buffer size for %s: %s";
+const char* const SOCKET_ERROR_MSG    = "error creating socket for %s: %s";
+const char* const TOS_ERROR_MSG              = "error setting TOS for %s: %s";
+
+
+static void client_timer_callback(struct Event* ev);
+
+
+/*
+ * Cannot use perror() within daemon. stderr is closed in
+ * ircd and cannot be used. And, worse yet, it might have
+ * been reassigned to a normal connection...
+ */
+
+/** Replacement for perror(). Record error to log.  Send a copy to all
+ * *LOCAL* opers, but only if no errors were sent to them in the last
+ * 20 seconds.
+ * @param text A *format* string for outputting error. It must contain
+ * only two '%s', the first will be replaced by the sockhost from the
+ * cptr, and the latter will be taken from sys_errlist[errno].
+ * @param who The client associated with the error.
+ * @param err The errno value to display.
+ */
+void report_error(const char* text, const char* who, int err)
+{
+  static time_t last_notice = 0;
+  int           errtmp = errno;   /* debug may change 'errno' */
+  const char*   errmsg = (err) ? strerror(err) : "";
+
+  if (!errmsg)
+    errmsg = "Unknown error"; 
+
+  if (EmptyString(who))
+    who = "unknown";
+
+  sendto_opmask_butone_ratelimited(0, SNO_OLDSNO, &last_notice, text, who, errmsg);
+  log_write(LS_SOCKET, L_ERROR, 0, text, who, errmsg);
+  errno = errtmp;
+}
+
+
+/** Called when resolver query finishes.  If the DNS lookup was
+ * successful, start the connection; otherwise notify opers of the
+ * failure.
+ * @param vptr The struct ConfItem representing the Connect block.
+ * @param hp A pointer to the DNS lookup results (NULL on failure).
+ */
+static void connect_dns_callback(void* vptr, const struct irc_in_addr *addr, const char *h_name)
+{
+  struct ConfItem* aconf = (struct ConfItem*) vptr;
+  assert(aconf);
+  aconf->dns_pending = 0;
+  if (addr) {
+    memcpy(&aconf->address, addr, sizeof(aconf->address));
+    connect_server(aconf, 0);
+  }
+  else
+    sendto_opmask_butone(0, SNO_OLDSNO, "Connect to %s failed: host lookup",
+                         aconf->name);
+}
+
+/* Helper routines */
+static IOResult client_recv(struct Client *cptr, char *buf, unsigned int length, unsigned int *count_out)
+{
+  if (cli_socket(cptr).ssl)
+    return ssl_recv(cli_fd(cptr), cli_socket(cptr).ssl, buf, length, count_out);
+  else
+    return os_recv_nonb(cli_fd(cptr), buf, length, count_out);
+}
+
+static IOResult client_sendv(struct Client *cptr, struct MsgQ *buf, unsigned int *count_in, unsigned int *count_out)
+{
+  if (cli_socket(cptr).ssl)
+    return ssl_sendv(cli_fd(cptr), cli_socket(cptr).ssl, buf, count_in, count_out);
+  else
+    return os_sendv_nonb(cli_fd(cptr), buf, count_in, count_out);
+}
+
+/** Closes all file descriptors.
+ * @param close_stderr If non-zero, also close stderr.
+ */
+void close_connections(int close_stderr)
+{
+  int i;
+  if (close_stderr)
+  {
+    close(0);
+    close(1);
+    close(2);
+  }
+  for (i = 3; i < MAXCONNECTIONS; ++i)
+    close(i);
+}
+
+/** Initialize process fd limit to MAXCONNECTIONS.
+ */
+int init_connection_limits(void)
+{
+  int limit = os_set_fdlimit(MAXCONNECTIONS);
+  if (0 == limit)
+    return 1;
+  if (limit < 0) {
+    fprintf(stderr, "error setting max fds to %d: %s\n", limit, strerror(errno));
+  }
+  else if (limit > 0) {
+    fprintf(stderr, "ircd fd table too big\nHard Limit: %d IRC max: %d\n",
+            limit, MAXCONNECTIONS);
+    fprintf(stderr, "set MAXCONNECTIONS to a smaller value");
+  }
+  return 0;
+}
+
+/** Set up address and port and make a connection.
+ * @param aconf Provides the connection information.
+ * @param cptr Client structure for the peer.
+ * @return Non-zero on success; zero on failure.
+ */
+static int connect_inet(struct ConfItem* aconf, struct Client* cptr)
+{
+  const struct irc_sockaddr *local;
+  IOResult result;
+  int family = 0;
+
+  assert(0 != aconf);
+  assert(0 != cptr);
+  /*
+   * Might as well get sockhost from here, the connection is attempted
+   * with it so if it fails its useless.
+   */
+  if (irc_in_addr_valid(&aconf->origin.addr))
+    local = &aconf->origin;
+  else if (irc_in_addr_is_ipv4(&aconf->address.addr)) {
+    local = &VirtualHost_v4;
+    family = AF_INET;
+  } else
+    local = &VirtualHost_v6;
+  cli_fd(cptr) = os_socket(local, SOCK_STREAM, cli_name(cptr), family);
+  if (cli_fd(cptr) < 0)
+    return 0;
+
+  /*
+   * save connection info in client
+   */
+  memcpy(&cli_ip(cptr), &aconf->address.addr, sizeof(cli_ip(cptr)));
+  ircd_ntoa_r(cli_sock_ip(cptr), &cli_ip(cptr));
+  /*
+   * we want a big buffer for server connections
+   */
+  if (!os_set_sockbufs(cli_fd(cptr), feature_int(FEAT_SOCKSENDBUF), feature_int(FEAT_SOCKRECVBUF))) {
+    cli_error(cptr) = errno;
+    report_error(SETBUFS_ERROR_MSG, cli_name(cptr), errno);
+    close(cli_fd(cptr));
+    cli_fd(cptr) = -1;
+    return 0;
+  }
+  /*
+   * Set the TOS bits - this is nonfatal if it doesn't stick.
+   */
+  if (!os_set_tos(cli_fd(cptr), FEAT_TOS_SERVER)) {
+    report_error(TOS_ERROR_MSG, cli_name(cptr), errno);
+  }
+  if ((result = os_connect_nonb(cli_fd(cptr), &aconf->address)) == IO_FAILURE) {
+    cli_error(cptr) = errno;
+    report_error(CONNECT_ERROR_MSG, cli_name(cptr), errno);
+    close(cli_fd(cptr));
+    cli_fd(cptr) = -1;
+    return 0;
+  }
+  if (!socket_add(&(cli_socket(cptr)), client_sock_callback,
+                 (void*) cli_connect(cptr),
+                 (result == IO_SUCCESS) ? SS_CONNECTED : SS_CONNECTING,
+                 SOCK_EVENT_READABLE, cli_fd(cptr))) {
+    cli_error(cptr) = ENFILE;
+    report_error(REGISTER_ERROR_MSG, cli_name(cptr), ENFILE);
+    close(cli_fd(cptr));
+    cli_fd(cptr) = -1;
+    return 0;
+  }
+  cli_freeflag(cptr) |= FREEFLAG_SOCKET;
+  return 1;
+}
+
+/** Attempt to send a sequence of bytes to the connection.
+ * As a side effect, updates \a cptr's FLAG_BLOCKED setting
+ * and sendB/sendK fields.
+ * @param cptr Client that should receive data.
+ * @param buf Message buffer to send to client.
+ * @return Negative on connection-fatal error; otherwise
+ *  number of bytes sent.
+ */
+unsigned int deliver_it(struct Client *cptr, struct MsgQ *buf)
+{
+  unsigned int bytes_written = 0;
+  unsigned int bytes_count = 0;
+  assert(0 != cptr);
+
+  switch (client_sendv(cptr, buf, &bytes_count, &bytes_written)) {
+  case IO_SUCCESS:
+    ClrFlag(cptr, FLAG_BLOCKED);
+
+    cli_sendB(cptr) += bytes_written;
+    cli_sendB(&me)  += bytes_written;
+    /* A partial write implies that future writes will block. */
+    if (bytes_written < bytes_count)
+      SetFlag(cptr, FLAG_BLOCKED);
+    break;
+  case IO_BLOCKED:
+    SetFlag(cptr, FLAG_BLOCKED);
+    break;
+  case IO_FAILURE:
+    cli_error(cptr) = errno;
+    SetFlag(cptr, FLAG_DEADSOCKET);
+    break;
+  }
+  return bytes_written;
+}
+
+/** Complete non-blocking connect()-sequence. Check access and
+ * terminate connection, if trouble detected.
+ * @param cptr Client to which we have connected, with all ConfItem structs attached.
+ * @return Zero on failure (caller should exit_client()), non-zero on success.
+ */
+int completed_connection(struct Client* cptr)
+{
+  struct ConfItem *aconf;
+  time_t newts;
+  struct Client *acptr;
+  int i;
+
+  assert(0 != cptr);
+
+  /*
+   * get the socket status from the fd first to check if
+   * connection actually succeeded
+   */
+  if ((cli_error(cptr) = os_get_sockerr(cli_fd(cptr)))) {
+    const char* msg = strerror(cli_error(cptr));
+    if (!msg)
+      msg = "Unknown error";
+    sendto_opmask_butone(0, SNO_OLDSNO, "Connection failed to %s: %s",
+                         cli_name(cptr), msg);
+    return 0;
+  }
+  if (!(aconf = find_conf_byname(cli_confs(cptr), cli_name(cptr), CONF_SERVER))) {
+    sendto_opmask_butone(0, SNO_OLDSNO, "Lost Server Line for %s", cli_name(cptr));
+    return 0;
+  }
+  if (s_state(&(cli_socket(cptr))) == SS_CONNECTING)
+    socket_state(&(cli_socket(cptr)), SS_CONNECTED);
+
+  /* Check whether we have to secure the connection.
+   * Server<->Server encryption requires us to pass the FD to the SSL module
+   * now which performs the handshake and later calls this function again.
+   *
+   * When this function is called again, there is either an error, which occurred,
+   * or the handshake completed and we continue without passing it to the SSL
+   * module again.
+   */
+  if(!cli_socket(cptr).ssl && (aconf->flags & CONF_SECURE)) {
+    return ssl_connect(cptr);
+  }
+
+  if (!EmptyString(aconf->passwd))
+    sendrawto_one(cptr, MSG_PASS " :%s", aconf->passwd);
+
+  /*
+   * Create a unique timestamp
+   */
+  newts = TStime();
+  for (i = HighestFd; i > -1; --i) {
+    if ((acptr = LocalClientArray[i]) && 
+        (IsServer(acptr) || IsHandshake(acptr))) {
+      if (cli_serv(acptr)->timestamp >= newts)
+        newts = cli_serv(acptr)->timestamp + 1;
+    }
+  }
+  assert(0 != cli_serv(cptr));
+
+  cli_serv(cptr)->timestamp = newts;
+  SetHandshake(cptr);
+  /*
+   * Make us timeout after twice the timeout for DNS look ups
+   */
+  cli_lasttime(cptr) = CurrentTime;
+  ClearPingSent(cptr);
+
+  sendrawto_one(cptr, MSG_SERVER " %s 1 %Tu %Tu J%s %s%s +%s6 :%s",
+                cli_name(&me), cli_serv(&me)->timestamp, newts,
+               MAJOR_PROTOCOL, NumServCap(&me),
+               feature_bool(FEAT_HUB) ? "h" : "", cli_info(&me));
+
+  return (IsDead(cptr)) ? 0 : 1;
+}
+
+/** Close the physical connection.  Side effects: MyConnect(cptr)
+ * becomes false and cptr->from becomes NULL.
+ * @param cptr Client to disconnect.
+ */
+void close_connection(struct Client *cptr)
+{
+  struct ConfItem* aconf;
+
+  if (IsServer(cptr)) {
+    ServerStats->is_sv++;
+    ServerStats->is_sbs += cli_sendB(cptr);
+    ServerStats->is_sbr += cli_receiveB(cptr);
+    ServerStats->is_sti += CurrentTime - cli_firsttime(cptr);
+    /*
+     * If the connection has been up for a long amount of time, schedule
+     * a 'quick' reconnect, else reset the next-connect cycle.
+     */
+    if ((aconf = find_conf_exact(cli_name(cptr), cptr, CONF_SERVER))) {
+      /*
+       * Reschedule a faster reconnect, if this was a automatically
+       * connected configuration entry. (Note that if we have had
+       * a rehash in between, the status has been changed to
+       * CONF_ILLEGAL). But only do this if it was a "good" link.
+       */
+      aconf->hold = CurrentTime;
+      aconf->hold += ((aconf->hold - cli_since(cptr) >
+                      feature_int(FEAT_HANGONGOODLINK)) ?
+                     feature_int(FEAT_HANGONRETRYDELAY) : ConfConFreq(aconf));
+/*        if (nextconnect > aconf->hold) */
+/*          nextconnect = aconf->hold; */
+    }
+  }
+  else if (IsUser(cptr)) {
+    ServerStats->is_cl++;
+    ServerStats->is_cbs += cli_sendB(cptr);
+    ServerStats->is_cbr += cli_receiveB(cptr);
+    ServerStats->is_cti += CurrentTime - cli_firsttime(cptr);
+  }
+  else
+    ServerStats->is_ni++;
+
+  if (-1 < cli_fd(cptr)) {
+    flush_connections(cptr);
+    LocalClientArray[cli_fd(cptr)] = 0;
+    close(cli_fd(cptr));
+    socket_del(&(cli_socket(cptr))); /* queue a socket delete */
+    cli_fd(cptr) = -1;
+  }
+  SetFlag(cptr, FLAG_DEADSOCKET);
+
+  MsgQClear(&(cli_sendQ(cptr)));
+  client_drop_sendq(cli_connect(cptr));
+  DBufClear(&(cli_recvQ(cptr)));
+  memset(cli_passwd(cptr), 0, sizeof(cli_passwd(cptr)));
+  set_snomask(cptr, 0, SNO_SET);
+
+  det_confs_butmask(cptr, 0);
+
+  if (cli_listener(cptr)) {
+    release_listener(cli_listener(cptr));
+    cli_listener(cptr) = 0;
+  }
+
+  for ( ; HighestFd > 0; --HighestFd) {
+    if (LocalClientArray[HighestFd])
+      break;
+  }
+}
+
+/** Close all unregistered connections.
+ * @param source Oper who requested the close.
+ * @return Number of closed connections.
+ */
+int net_close_unregistered_connections(struct Client* source)
+{
+  int            i;
+  struct Client* cptr;
+  int            count = 0;
+  assert(0 != source);
+
+  for (i = HighestFd; i > 0; --i) {
+    if ((cptr = LocalClientArray[i]) && !IsRegistered(cptr)) {
+      send_reply(source, RPL_CLOSING, get_client_name(source, HIDE_IP));
+      exit_client(source, cptr, &me, "Oper Closing");
+      ++count;
+    }
+  }
+  return count;
+}
+
+/** Creates a client which has just connected to us on the given fd.
+ * The sockhost field is initialized with the ip# of the host.
+ * The client is not added to the linked list of clients, it is
+ * passed off to the auth handler for dns and ident queries.
+ * @param listener Listening socket that received the connection.
+ * @param fd File descriptor of new connection.
+ */
+void add_connection(struct Listener* listener, int fd, ssl_session_t *ssl) {
+  struct irc_sockaddr addr;
+  struct Client      *new_client;
+  time_t             next_target = 0;
+
+  const char* const throttle_message =
+         "ERROR :Your host is trying to (re)connect too fast -- throttled\r\n";
+       /* 12345678901234567890123456789012345679012345678901234567890123456 */
+  const char* const register_message =
+         "ERROR :Unable to complete your registration\r\n";
+
+  assert(0 != listener);
+
+  /*
+   * Removed preliminary access check. Full check is performed in m_server and
+   * m_user instead. Also connection time out help to get rid of unwanted
+   * connections.
+   */
+  if (!os_get_peername(fd, &addr) || !os_set_nonblocking(fd)) {
+    ++ServerStats->is_ref;
+    ssl_close(fd, ssl, NULL, 0);
+    return;
+  }
+  /*
+   * Disable IP (*not* TCP) options.  In particular, this makes it impossible
+   * to use source routing to connect to the server.  If we didn't do this
+   * (and if intermediate networks didn't drop source-routed packets), an
+   * attacker could successfully IP spoof us...and even return the anti-spoof
+   * ping, because the options would cause the packet to be routed back to
+   * the spoofer's machine.  When we disable the IP options, we delete the
+   * source route, and the normal routing takes over.
+   */
+  os_disable_options(fd);
+
+  if (listener_server(listener))
+  {
+    new_client = make_client(0, STAT_UNKNOWN_SERVER);
+  }
+  else
+  {
+    /*
+     * Add this local client to the IPcheck registry.
+     *
+     * If they're throttled, murder them, but tell them why first.
+     */
+    if (!IPcheck_local_connect(&addr.addr, &next_target))
+    {
+      ++ServerStats->is_ref;
+      ssl_close(fd, ssl, throttle_message, strlen(throttle_message));
+      return;
+    }
+    new_client = make_client(0, STAT_UNKNOWN_USER);
+    SetIPChecked(new_client);
+  }
+
+  /*
+   * Copy ascii address to 'sockhost' just in case. Then we have something
+   * valid to put into error messages...
+   */
+  ircd_ntoa_r(cli_sock_ip(new_client), &addr.addr);
+  strcpy(cli_sockhost(new_client), cli_sock_ip(new_client));
+  memcpy(&cli_ip(new_client), &addr.addr, sizeof(cli_ip(new_client)));
+
+  if (next_target)
+    cli_nexttarget(new_client) = next_target;
+
+  cli_fd(new_client) = fd;
+  if (!socket_add(&(cli_socket(new_client)), client_sock_callback,
+                 (void*) cli_connect(new_client), SS_CONNECTED, 0, fd)) {
+    ++ServerStats->is_ref;
+    ssl_close(fd, ssl, register_message, strlen(register_message));
+    cli_fd(new_client) = -1;
+    return;
+  }
+  cli_socket(new_client).ssl = ssl;
+  cli_freeflag(new_client) |= FREEFLAG_SOCKET;
+  cli_listener(new_client) = listener;
+  ++listener->ref_count;
+
+  Count_newunknown(UserStats);
+  /* if we've made it this far we can put the client on the auth query pile */
+  start_auth(new_client);
+}
+
+/** Determines whether to tell the events engine we're interested in
+ * writable events.
+ * @param cptr Client for which to decide this.
+ */
+void update_write(struct Client* cptr)
+{
+  /* If there are messages that need to be sent along, or if the client
+   * is in the middle of a /list, then we need to tell the engine that
+   * we're interested in writable events--otherwise, we need to drop
+   * that interest.
+   */
+  socket_events(&(cli_socket(cptr)),
+               ((MsgQLength(&cli_sendQ(cptr)) || cli_listing(cptr)) ?
+                SOCK_ACTION_ADD : SOCK_ACTION_DEL) | SOCK_EVENT_WRITABLE);
+}
+
+/** Read a 'packet' of data from a connection and process it.  Read in
+ * 8k chunks to give a better performance rating (for server
+ * connections).  Do some tricky stuff for client connections to make
+ * sure they don't do any flooding >:-) -avalon
+ * @param cptr Client from which to read data.
+ * @param socket_ready If non-zero, more data can be read from the client's socket.
+ * @return Positive number on success, zero on connection-fatal failure, negative
+ *   if user is killed.
+ */
+static int read_packet(struct Client *cptr, int socket_ready)
+{
+  unsigned int dolen = 0;
+  unsigned int length = 0;
+  unsigned int client_flood = feature_int(FEAT_CLIENT_FLOOD) * (HasPriv(cptr, PRIV_HALFFLOOD) ? 4 : 1);
+
+  if (socket_ready &&
+      !(IsUser(cptr) && !HasPriv(cptr, PRIV_FLOOD) &&
+        DBufLength(&(cli_recvQ(cptr))) > client_flood)) {
+    switch (client_recv(cptr, readbuf, sizeof(readbuf), &length)) {
+    case IO_SUCCESS:
+      if (length)
+      {
+        cli_lasttime(cptr) = CurrentTime;
+        ClearPingSent(cptr);
+        ClrFlag(cptr, FLAG_NONL);
+        if (cli_lasttime(cptr) > cli_since(cptr))
+          cli_since(cptr) = cli_lasttime(cptr);
+      }
+      break;
+    case IO_BLOCKED:
+      break;
+    case IO_FAILURE:
+      cli_error(cptr) = errno;
+      /* SetFlag(cptr, FLAG_DEADSOCKET); */
+      return 0;
+    }
+  }
+
+  /*
+   * For server connections, we process as many as we can without
+   * worrying about the time of day or anything :)
+   */
+  if (length > 0 && IsServer(cptr))
+    return server_dopacket(cptr, readbuf, length);
+  else if (length > 0 && (IsHandshake(cptr) || IsConnecting(cptr) || HasPriv(cptr, PRIV_FLOOD)))
+    return connect_dopacket(cptr, readbuf, length);
+  else
+  {
+    /*
+     * Before we even think of parsing what we just read, stick
+     * it on the end of the receive queue and do it when its
+     * turn comes around.
+     */
+    if (length > 0 && dbuf_put(&(cli_recvQ(cptr)), readbuf, length) == 0)
+      return exit_client(cptr, cptr, &me, "dbuf_put fail");
+
+    if (!HasPriv(cptr, PRIV_FLOOD) && DBufLength(&(cli_recvQ(cptr))) > client_flood)
+      return exit_client(cptr, cptr, &me, "Excess Flood");
+
+    while (DBufLength(&(cli_recvQ(cptr))) && !NoNewLine(cptr) && 
+           (IsTrusted(cptr) || cli_since(cptr) - CurrentTime < 10))
+    {
+      dolen = dbuf_getmsg(&(cli_recvQ(cptr)), cli_buffer(cptr), BUFSIZE);
+      /*
+       * Devious looking...whats it do ? well..if a client
+       * sends a *long* message without any CR or LF, then
+       * dbuf_getmsg fails and we pull it out using this
+       * loop which just gets the next 512 bytes and then
+       * deletes the rest of the buffer contents.
+       * -avalon
+       */
+      if (dolen == 0)
+      {
+        if (DBufLength(&(cli_recvQ(cptr))) < 510)
+          SetFlag(cptr, FLAG_NONL);
+        else
+        {
+          /* More than 512 bytes in the line - drop the input and yell
+           * at the client.
+           */
+          DBufClear(&(cli_recvQ(cptr)));
+          send_reply(cptr, ERR_INPUTTOOLONG);
+        }
+      }
+      else if (client_dopacket(cptr, dolen) == CPTR_KILLED)
+        return CPTR_KILLED;
+      /*
+       * If it has become registered as a Server
+       * then skip the per-message parsing below.
+       */
+      if (IsHandshake(cptr) || IsServer(cptr))
+      {
+        while (-1)
+        {
+          dolen = dbuf_get(&(cli_recvQ(cptr)), readbuf, sizeof(readbuf));
+          if (dolen <= 0)
+            return 1;
+          else if (dolen == 0)
+          {
+            if (DBufLength(&(cli_recvQ(cptr))) < 510)
+              SetFlag(cptr, FLAG_NONL);
+            else
+              DBufClear(&(cli_recvQ(cptr)));
+          }
+          else if ((IsServer(cptr) &&
+                    server_dopacket(cptr, readbuf, dolen) == CPTR_KILLED) ||
+                   (!IsServer(cptr) &&
+                    connect_dopacket(cptr, readbuf, dolen) == CPTR_KILLED))
+            return CPTR_KILLED;
+        }
+      }
+    }
+
+    /* If there's still data to process, wait 2 seconds first */
+    if (DBufLength(&(cli_recvQ(cptr))) && !NoNewLine(cptr) &&
+       !t_onqueue(&(cli_proc(cptr))))
+    {
+      Debug((DEBUG_LIST, "Adding client process timer for %C", cptr));
+      cli_freeflag(cptr) |= FREEFLAG_TIMER;
+      timer_add(&(cli_proc(cptr)), client_timer_callback, cli_connect(cptr),
+               TT_RELATIVE, 2);
+    }
+  }
+  return 1;
+}
+
+/** Start a connection to another server.
+ * @param aconf Connect block data for target server.
+ * @param by Client who requested the connection (if any).
+ * @return Non-zero on success; zero on failure.
+ */
+int connect_server(struct ConfItem* aconf, struct Client* by)
+{
+  struct Client*   cptr = 0;
+  assert(0 != aconf);
+
+  if (aconf->dns_pending) {
+    sendto_opmask_butone(0, SNO_OLDSNO, "Server %s connect DNS pending",
+                         aconf->name);
+    return 0;
+  }
+  Debug((DEBUG_NOTICE, "Connect to %s[@%s]", aconf->name,
+         ircd_ntoa(&aconf->address.addr)));
+
+  if ((cptr = FindClient(aconf->name))) {
+    if (IsServer(cptr) || IsMe(cptr)) {
+      sendto_opmask_butone(0, SNO_OLDSNO, "Server %s already present from %s", 
+                           aconf->name, cli_name(cli_from(cptr)));
+      if (by && IsUser(by) && !MyUser(by)) {
+        sendcmdto_one(&me, CMD_NOTICE, by, "%C :Server %s already present "
+                      "from %s", by, aconf->name, cli_name(cli_from(cptr)));
+      }
+      return 0;
+    }
+    else if (IsHandshake(cptr) || IsConnecting(cptr)) {
+      if (by && IsUser(by)) {
+        sendcmdto_one(&me, CMD_NOTICE, by, "%C :Connection to %s already in "
+                      "progress", by, cli_name(cptr));
+      }
+      return 0;
+    }
+  }
+  /*
+   * If we don't know the IP# for this host and it is a hostname and
+   * not a ip# string, then try and find the appropriate host record.
+   */
+  if (!irc_in_addr_valid(&aconf->address.addr)
+      && !ircd_aton(&aconf->address.addr, aconf->host)) {
+    char buf[HOSTLEN + 1];
+
+    host_from_uh(buf, aconf->host, HOSTLEN);
+    gethost_byname(buf, connect_dns_callback, aconf);
+    aconf->dns_pending = 1;
+    return 0;
+  }
+  cptr = make_client(NULL, STAT_UNKNOWN_SERVER);
+
+  /*
+   * Copy these in so we have something for error detection.
+   */
+  ircd_strncpy(cli_name(cptr), aconf->name, HOSTLEN);
+  ircd_strncpy(cli_sockhost(cptr), aconf->host, HOSTLEN);
+
+  /*
+   * Attach config entries to client here rather than in
+   * completed_connection. This to avoid null pointer references
+   */
+  attach_confs_byhost(cptr, aconf->host, CONF_SERVER);
+
+  if (!find_conf_byhost(cli_confs(cptr), aconf->host, CONF_SERVER)) {
+    sendto_opmask_butone(0, SNO_OLDSNO, "Host %s is not enabled for "
+                         "connecting: no Connect block", aconf->name);
+    if (by && IsUser(by) && !MyUser(by)) {
+      sendcmdto_one(&me, CMD_NOTICE, by, "%C :Connect to host %s failed: no "
+                    "Connect block", by, aconf->name);
+    }
+    det_confs_butmask(cptr, 0);
+    free_client(cptr);
+    return 0;
+  }
+  /*
+   * attempt to connect to the server in the conf line
+   */
+  if (!connect_inet(aconf, cptr)) {
+    if (by && IsUser(by) && !MyUser(by)) {
+      sendcmdto_one(&me, CMD_NOTICE, by, "%C :Couldn't connect to %s", by,
+                    cli_name(cptr));
+    }
+    det_confs_butmask(cptr, 0);
+    free_client(cptr);
+    return 0;
+  }
+  /*
+   * NOTE: if we're here we have a valid C:Line and the client should
+   * have started the connection and stored the remote address/port and
+   * ip address name in itself
+   *
+   * The socket has been connected or connect is in progress.
+   */
+  make_server(cptr);
+  if (by && IsUser(by)) {
+    ircd_snprintf(0, cli_serv(cptr)->by, sizeof(cli_serv(cptr)->by), "%s%s",
+                 NumNick(by));
+    assert(0 == cli_serv(cptr)->user);
+    cli_serv(cptr)->user = cli_user(by);
+    cli_user(by)->refcnt++;
+  }
+  else {
+    *(cli_serv(cptr))->by = '\0';
+    /* strcpy(cptr->serv->by, "Auto"); */
+  }
+  cli_serv(cptr)->up = &me;
+  SetConnecting(cptr);
+
+  if (cli_fd(cptr) > HighestFd)
+    HighestFd = cli_fd(cptr);
+
+  LocalClientArray[cli_fd(cptr)] = cptr;
+
+  Count_newunknown(UserStats);
+  /* Actually we lie, the connect hasn't succeeded yet, but we have a valid
+   * cptr, so we register it now.
+   * Maybe these two calls should be merged.
+   */
+  add_client_to_list(cptr);
+  hAddClient(cptr);
+/*    nextping = CurrentTime; */
+
+  return (s_state(&cli_socket(cptr)) == SS_CONNECTED) ?
+    completed_connection(cptr) : 1;
+}
+
+/** Find the real hostname for the host running the server (or one which
+ * matches the server's name) and its primary IP#.  Hostname is stored
+ * in the client structure passed as a pointer.
+ */
+void init_server_identity(void)
+{
+  const struct LocalConf* conf = conf_get_local();
+  assert(0 != conf);
+
+  ircd_strncpy(cli_name(&me), conf->name, HOSTLEN);
+  SetYXXServerName(&me, conf->numeric);
+}
+
+/** Process events on a client socket.
+ * @param ev Socket event structure that has a struct Connection as
+ *   its associated data.
+ */
+void client_sock_callback(struct Event* ev)
+{
+  struct Client* cptr;
+  struct Connection* con;
+  char *fmt = "%s";
+  char *fallback = 0;
+
+  assert(0 != ev_socket(ev));
+  assert(0 != s_data(ev_socket(ev)));
+
+  con = (struct Connection*) s_data(ev_socket(ev));
+
+  assert(0 != con_client(con) || ev_type(ev) == ET_DESTROY);
+
+  cptr = con_client(con);
+
+  assert(0 == cptr || con == cli_connect(cptr));
+
+  switch (ev_type(ev)) {
+  case ET_DESTROY:
+    con_freeflag(con) &= ~FREEFLAG_SOCKET;
+
+    if (!con_freeflag(con) && !cptr)
+      free_connection(con);
+
+    if(ev_socket(ev)->ssl) ssl_session_free(ev_socket(ev)->ssl);
+    break;
+
+  case ET_CONNECT: /* socket connection completed */
+    if (!completed_connection(cptr) || IsDead(cptr))
+      fallback = cli_info(cptr);
+    break;
+
+  case ET_ERROR: /* an error occurred */
+    fallback = cli_info(cptr);
+    cli_error(cptr) = ev_data(ev);
+    if (s_state(&(con_socket(con))) == SS_CONNECTING) {
+      completed_connection(cptr);
+      /* for some reason, the os_get_sockerr() in completed_connect()
+       * can return 0 even when ev_data(ev) indicates a real error, so
+       * re-assign the client error here.
+       */
+      cli_error(cptr) = ev_data(ev);
+      break;
+    }
+    /*FALLTHROUGH*/
+  case ET_EOF: /* end of file on socket */
+    Debug((DEBUG_ERROR, "READ ERROR: fd = %d %d", cli_fd(cptr),
+          cli_error(cptr)));
+    SetFlag(cptr, FLAG_DEADSOCKET);
+    if ((IsServer(cptr) || IsHandshake(cptr)) && cli_error(cptr) == 0) {
+      exit_client_msg(cptr, cptr, &me, "Server %s closed the connection (%s)",
+                     cli_name(cptr), cli_serv(cptr)->last_error_msg);
+      return;
+    } else {
+      fmt = "Read error: %s";
+      fallback = "EOF from client";
+    }
+    break;
+
+  case ET_WRITE: /* socket is writable */
+    ClrFlag(cptr, FLAG_BLOCKED);
+    if (cli_listing(cptr) && MsgQLength(&(cli_sendQ(cptr))) < 2048)
+      list_next_channels(cptr);
+    Debug((DEBUG_SEND, "Sending queued data to %C", cptr));
+    send_queued(cptr);
+    break;
+
+  case ET_READ: /* socket is readable */
+    if (!IsDead(cptr)) {
+      Debug((DEBUG_DEBUG, "Reading data from %C", cptr));
+      if (read_packet(cptr, 1) == 0) /* error while reading packet */
+       fallback = "EOF from client";
+    }
+    break;
+
+  default:
+    assert(0 && "Unrecognized socket event in client_sock_callback()");
+    break;
+  }
+
+  assert(0 == cptr || 0 == cli_connect(cptr) || con == cli_connect(cptr));
+
+  if (fallback) {
+    const char* msg = (cli_error(cptr)) ? strerror(cli_error(cptr)) : fallback;
+    if (!msg)
+      msg = "Unknown error";
+    exit_client_msg(cptr, cptr, &me, fmt, msg);
+  }
+}
+
+/** Process a timer on client socket.
+ * @param ev Timer event that has a struct Connection as its
+ * associated data.
+ */
+static void client_timer_callback(struct Event* ev)
+{
+  struct Client* cptr;
+  struct Connection* con;
+
+  assert(0 != ev_timer(ev));
+  assert(0 != t_data(ev_timer(ev)));
+  assert(ET_DESTROY == ev_type(ev) || ET_EXPIRE == ev_type(ev));
+
+  con = (struct Connection*) t_data(ev_timer(ev));
+
+  assert(0 != con_client(con) || ev_type(ev) == ET_DESTROY);
+
+  cptr = con_client(con);
+
+  assert(0 == cptr || con == cli_connect(cptr));
+
+  if (ev_type(ev)== ET_DESTROY) {
+    con_freeflag(con) &= ~FREEFLAG_TIMER; /* timer has expired... */
+
+    if (!con_freeflag(con) && !cptr)
+      free_connection(con); /* client is being destroyed */
+  } else {
+    Debug((DEBUG_LIST, "Client process timer for %C expired; processing",
+          cptr));
+    read_packet(cptr, 0); /* read_packet will re-add timer if needed */
+  }
+
+  assert(0 == cptr || 0 == cli_connect(cptr) || con == cli_connect(cptr));
+}
diff --git a/ircd/s_conf.c b/ircd/s_conf.c
new file mode 100644 (file)
index 0000000..4a68576
--- /dev/null
@@ -0,0 +1,1296 @@
+/*
+ * IRC - Internet Relay Chat, ircd/s_conf.c
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ *                    University of Oulu, Computing Center
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+/** @file
+ * @brief ircd configuration file driver
+ * @version $Id: s_conf.c 1839 2007-10-30 02:13:09Z entrope $
+ */
+#include "config.h"
+
+#include "s_conf.h"
+#include "IPcheck.h"
+#include "class.h"
+#include "client.h"
+#include "crule.h"
+#include "ircd_features.h"
+#include "fileio.h"
+#include "gline.h"
+#include "hash.h"
+#include "ircd.h"
+#include "ircd_alloc.h"
+#include "ircd_chattr.h"
+#include "ircd_log.h"
+#include "ircd_reply.h"
+#include "ircd_snprintf.h"
+#include "ircd_string.h"
+#include "list.h"
+#include "listener.h"
+#include "match.h"
+#include "motd.h"
+#include "numeric.h"
+#include "numnicks.h"
+#include "opercmds.h"
+#include "parse.h"
+#include "res.h"
+#include "s_auth.h"
+#include "s_bsd.h"
+#include "s_debug.h"
+#include "s_misc.h"
+#include "send.h"
+#include "struct.h"
+#include "sys.h"
+
+/* #include <assert.h> -- Now using assert in ircd_log.h */
+#include <errno.h>
+#include <fcntl.h>
+#include <netdb.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+/** Global list of all ConfItem structures. */
+struct ConfItem  *GlobalConfList;
+/** Count of items in #GlobalConfList. */
+int              GlobalConfCount;
+/** Global list of service mappings. */
+struct s_map     *GlobalServiceMapList;
+/** Global list of channel quarantines. */
+struct qline     *GlobalQuarantineList;
+/** Global list of WebIRC blocks. */
+struct webirc_block *GlobalWebIRCConf;
+
+/** Current line number in scanner input. */
+int lineno;
+
+/** Configuration information for #me. */
+struct LocalConf   localConf;
+/** Global list of connection rules. */
+struct CRuleConf*  cruleConfList;
+/** Global list of K-lines. */
+struct DenyConf*   denyConfList;
+
+/** Tell a user that they are banned, dumping the message from a file.
+ * @param sptr Client being rejected
+ * @param filename Send this file's contents to \a sptr
+ */
+static void killcomment(struct Client* sptr, const char* filename)
+{
+  FBFILE*     file = 0;
+  char        line[80];
+  struct stat sb;
+  struct tm*  tm;
+
+  if (NULL == (file = fbopen(filename, "r"))) {
+    send_reply(sptr, ERR_NOMOTD);
+    send_reply(sptr, SND_EXPLICIT | ERR_YOUREBANNEDCREEP,
+               ":Connection from your host is refused on this server.");
+    return;
+  }
+  fbstat(&sb, file);
+  tm = localtime((time_t*) &sb.st_mtime);        /* NetBSD needs cast */
+  while (fbgets(line, sizeof(line) - 1, file)) {
+    char* end = line + strlen(line);
+    while (end > line) {
+      --end;
+      if ('\n' == *end || '\r' == *end)
+        *end = '\0';
+      else
+        break;
+    }
+    send_reply(sptr, RPL_MOTD, line);
+  }
+  send_reply(sptr, SND_EXPLICIT | ERR_YOUREBANNEDCREEP,
+             ":Connection from your host is refused on this server.");
+  fbclose(file);
+}
+
+/** Allocate a new struct ConfItem and link it to #GlobalConfList.
+ * @return Newly allocated structure.
+ */
+struct ConfItem* make_conf(int type)
+{
+  struct ConfItem* aconf;
+
+  aconf = (struct ConfItem*) MyMalloc(sizeof(struct ConfItem));
+  assert(0 != aconf);
+  ++GlobalConfCount;
+  memset(aconf, 0, sizeof(struct ConfItem));
+  aconf->status  = type;
+  aconf->next    = GlobalConfList;
+  GlobalConfList = aconf;
+  return aconf;
+}
+
+/** Free a struct ConfItem and any resources it owns.
+ * @param aconf Item to free.
+ */
+void free_conf(struct ConfItem *aconf)
+{
+  Debug((DEBUG_DEBUG, "free_conf: %s %s %d",
+         aconf->host ? aconf->host : "*",
+         aconf->name ? aconf->name : "*",
+         aconf->address.port));
+  if (aconf->dns_pending)
+    delete_resolver_queries(aconf);
+  MyFree(aconf->username);
+  MyFree(aconf->host);
+  MyFree(aconf->origin_name);
+  if (aconf->passwd)
+    memset(aconf->passwd, 0, strlen(aconf->passwd));
+  MyFree(aconf->passwd);
+  MyFree(aconf->name);
+  MyFree(aconf->hub_limit);
+  MyFree(aconf);
+  --GlobalConfCount;
+}
+
+/** Disassociate configuration from the client.
+ * @param cptr Client to operate on.
+ * @param aconf ConfItem to detach.
+ */
+static void detach_conf(struct Client* cptr, struct ConfItem* aconf)
+{
+  struct SLink** lp;
+  struct SLink*  tmp;
+
+  assert(0 != aconf);
+  assert(0 != cptr);
+  assert(0 < aconf->clients);
+
+  lp = &(cli_confs(cptr));
+
+  while (*lp) {
+    if ((*lp)->value.aconf == aconf) {
+      if (aconf->conn_class && (aconf->status & CONF_CLIENT_MASK) && ConfLinks(aconf) > 0)
+        --ConfLinks(aconf);
+
+      assert(0 < aconf->clients);
+      if (0 == --aconf->clients && IsIllegal(aconf))
+        free_conf(aconf);
+      tmp = *lp;
+      *lp = tmp->next;
+      free_link(tmp);
+      return;
+    }
+    lp = &((*lp)->next);
+  }
+}
+
+/** Parse a user\@host mask into username and host or IP parts.
+ * If \a host contains no username part, set \a aconf->username to
+ * NULL.  If the host part of \a host looks like an IP mask, set \a
+ * aconf->addrbits and \a aconf->address to match.  Otherwise, set
+ * \a aconf->host, and set \a aconf->addrbits to -1.
+ * @param[in,out] aconf Configuration item to set.
+ * @param[in] host user\@host mask to parse.
+ */
+void conf_parse_userhost(struct ConfItem *aconf, char *host)
+{
+  char *host_part;
+  unsigned char addrbits;
+
+  MyFree(aconf->username);
+  MyFree(aconf->host);
+  host_part = strchr(host, '@');
+  if (host_part) {
+    *host_part = '\0';
+    DupString(aconf->username, host);
+    host_part++;
+  } else {
+    aconf->username = NULL;
+    host_part = host;
+  }
+  DupString(aconf->host, host_part);
+  if (ipmask_parse(aconf->host, &aconf->address.addr, &addrbits))
+    aconf->addrbits = addrbits;
+  else
+    aconf->addrbits = -1;
+}
+
+/** Copies a completed DNS query into its ConfItem.
+ * @param vptr Pointer to struct ConfItem for the block.
+ * @param hp DNS reply, or NULL if the lookup failed.
+ */
+static void conf_dns_callback(void* vptr, const struct irc_in_addr *addr, const char *h_name)
+{
+  struct ConfItem* aconf = (struct ConfItem*) vptr;
+  assert(aconf);
+  aconf->dns_pending = 0;
+  if (addr)
+    memcpy(&aconf->address.addr, addr, sizeof(aconf->address.addr));
+}
+
+/** Start a nameserver lookup of the conf host.  If the conf entry is
+ * currently doing a lookup, do nothing.
+ * @param aconf ConfItem for which to start a request.
+ */
+static void conf_dns_lookup(struct ConfItem* aconf)
+{
+  if (!aconf->dns_pending) {
+    char            buf[HOSTLEN + 1];
+
+    host_from_uh(buf, aconf->host, HOSTLEN);
+    gethost_byname(buf, conf_dns_callback, aconf);
+    aconf->dns_pending = 1;
+  }
+}
+
+
+/** Start lookups of all addresses in the conf line.  The origin must
+ * be a numeric IP address.  If the remote host field is not an IP
+ * address, start a DNS lookup for it.
+ * @param aconf Connection to do lookups for.
+ */
+void
+lookup_confhost(struct ConfItem *aconf)
+{
+  if (EmptyString(aconf->host) || EmptyString(aconf->name)) {
+    Debug((DEBUG_ERROR, "Host/server name error: (%s) (%s)",
+           aconf->host, aconf->name));
+    return;
+  }
+  if (aconf->origin_name
+      && !ircd_aton(&aconf->origin.addr, aconf->origin_name)) {
+    Debug((DEBUG_ERROR, "Origin name error: (%s) (%s)",
+        aconf->origin_name, aconf->name));
+  }
+  /*
+   * Do name lookup now on hostnames given and store the
+   * ip numbers in conf structure.
+   */
+  if (IsIP6Char(*aconf->host)) {
+    if (!ircd_aton(&aconf->address.addr, aconf->host)) {
+      Debug((DEBUG_ERROR, "Host/server name error: (%s) (%s)",
+          aconf->host, aconf->name));
+    }
+  }
+  else
+    conf_dns_lookup(aconf);
+}
+
+/** Find a server by name or hostname.
+ * @param name Server name to find.
+ * @return Pointer to the corresponding ConfItem, or NULL if none exists.
+ */
+struct ConfItem* conf_find_server(const char* name)
+{
+  struct ConfItem* conf;
+  assert(0 != name);
+
+  for (conf = GlobalConfList; conf; conf = conf->next) {
+    if (CONF_SERVER == conf->status) {
+      /*
+       * Check first servernames, then try hostnames.
+       * XXX - match returns 0 if there _is_ a match... guess they
+       * haven't decided what true is yet
+       */
+      if (0 == match(name, conf->name))
+        return conf;
+    }
+  }
+  return 0;
+}
+
+/** Evaluate connection rules.
+ * @param name Name of server to check
+ * @param mask Filter for CRule types (only consider if type & \a mask != 0).
+ * @return Name of rule that forbids the connection; NULL if no prohibitions.
+ */
+const char* conf_eval_crule(const char* name, int mask)
+{
+  struct CRuleConf* p = cruleConfList;
+  assert(0 != name);
+
+  for ( ; p; p = p->next) {
+    if (0 != (p->type & mask) && 0 == match(p->hostmask, name)) {
+      if (crule_eval(p->node))
+        return p->rule;
+    }
+  }
+  return 0;
+}
+
+/** Remove all conf entries from the client except those which match
+ * the status field mask.
+ * @param cptr Client to operate on.
+ * @param mask ConfItem types to keep.
+ */
+void det_confs_butmask(struct Client* cptr, int mask)
+{
+  struct SLink* link;
+  struct SLink* next;
+  assert(0 != cptr);
+
+  for (link = cli_confs(cptr); link; link = next) {
+    next = link->next;
+    if ((link->value.aconf->status & mask) == 0)
+      detach_conf(cptr, link->value.aconf);
+  }
+}
+
+/** Find the first (best) Client block to attach.
+ * @param cptr Client for whom to check rules.
+ * @return Authorization check result.
+ */
+enum AuthorizationCheckResult attach_iline(struct Client* cptr)
+{
+  struct ConfItem* aconf;
+  int maximum_exceeded = 0;
+
+  assert(0 != cptr);
+
+  for (aconf = GlobalConfList; aconf; aconf = aconf->next) {
+    if (aconf->status != CONF_CLIENT)
+      continue;
+    /* If you change any of this logic, please make corresponding
+     * changes in conf_debug_iline() below.
+     */
+    if (aconf->address.port && aconf->address.port != cli_listener(cptr)->addr.port)
+      continue;
+    if (aconf->username && match(aconf->username, cli_username(cptr)))
+      continue;
+    if (aconf->host && match(aconf->host, cli_sockhost(cptr)))
+      continue;
+    if ((aconf->addrbits >= 0)
+        && !ipmask_check(&cli_ip(cptr), &aconf->address.addr, aconf->addrbits))
+      continue;
+    if (IPcheck_nr(cptr) > aconf->maximum) {
+      maximum_exceeded = 1;
+      continue;
+    }
+    if (aconf->username)
+      SetFlag(cptr, FLAG_DOID);
+    return attach_conf(cptr, aconf);
+  }
+  if(maximum_exceeded) return ACR_TOO_MANY_FROM_IP;
+  return ACR_NO_AUTHORIZATION;
+}
+
+/** Interpret \a client as a client specifier and show which Client
+ * block(s) match that client.
+ *
+ * The client specifier may contain an IP address, hostname, listener
+ * port, or a combination of those separated by commas.  IP addresses
+ * and hostnamese may be preceded by "username@"; the last given
+ * username will be used for the match.
+ *
+ * @param[in] client Client specifier.
+ * @return Matching Client block structure.
+ */
+struct ConfItem *conf_debug_iline(const char *client)
+{
+  struct irc_in_addr address;
+  struct ConfItem *aconf;
+  struct DenyConf *deny;
+  char *sep;
+  unsigned short listener;
+  char username[USERLEN+1], hostname[HOSTLEN+1], realname[REALLEN+1];
+
+  /* Initialize variables. */
+  listener = 0;
+  memset(&address, 0, sizeof(address));
+  memset(&username, 0, sizeof(username));
+  memset(&hostname, 0, sizeof(hostname));
+  memset(&realname, 0, sizeof(realname));
+
+  /* Parse client specifier. */
+  while (*client) {
+    struct irc_in_addr tmpaddr;
+    long tmp;
+
+    /* Try to parse as listener port number first. */
+    tmp = strtol(client, &sep, 10);
+    if (tmp && (*sep == '\0' || *sep == ',')) {
+      listener = tmp;
+      client = sep + (*sep != '\0');
+      continue;
+    }
+
+    /* Maybe username@ before an IP address or hostname? */
+    tmp = strcspn(client, ",@");
+    if (client[tmp] == '@') {
+      if (tmp > USERLEN)
+        tmp = USERLEN;
+      ircd_strncpy(username, client, tmp);
+      /* and fall through */
+      client += tmp + 1;
+    }
+
+    /* Looks like an IP address? */
+    tmp = ircd_aton(&tmpaddr, client);
+    if (tmp && (client[tmp] == '\0' || client[tmp] == ',')) {
+        memcpy(&address, &tmpaddr, sizeof(address));
+        client += tmp + (client[tmp] != '\0');
+        continue;
+    }
+
+    /* Realname? */
+    if (client[0] == '$' && client[1] == 'R') {
+      client += 2;
+      for (tmp = 0; *client != '\0' && *client != ',' && tmp < REALLEN; ++client, ++tmp) {
+        if (*client == '\\')
+          realname[tmp] = *++client;
+        else
+          realname[tmp] = *client;
+      }
+      continue;
+    }
+
+    /* Else must be a hostname. */
+    tmp = strcspn(client, ",");
+    if (tmp > HOSTLEN)
+      tmp = HOSTLEN;
+    ircd_strncpy(hostname, client, tmp);
+    client += tmp + (client[tmp] != '\0');
+  }
+
+  /* Walk configuration to find matching Client block. */
+  for (aconf = GlobalConfList; aconf; aconf = aconf->next) {
+    if (aconf->status != CONF_CLIENT)
+      continue;
+    if (aconf->address.port && aconf->address.port != listener) {
+      fprintf(stdout, "Listener port mismatch: %u != %u\n", aconf->address.port, listener);
+      continue;
+    }
+    if (aconf->username && match(aconf->username, username)) {
+      fprintf(stdout, "Username mismatch: %s != %s\n", aconf->username, username);
+      continue;
+    }
+    if (aconf->host && match(aconf->host, hostname)) {
+      fprintf(stdout, "Hostname mismatch: %s != %s\n", aconf->host, hostname);
+      continue;
+    }
+    if ((aconf->addrbits >= 0)
+        && !ipmask_check(&address, &aconf->address.addr, aconf->addrbits)) {
+      fprintf(stdout, "IP address mismatch: %s != %s\n", aconf->name, ircd_ntoa(&address));
+      continue;
+    }
+    fprintf(stdout, "Match! username=%s host=%s ip=%s class=%s maxlinks=%u password=%s\n",
+            (aconf->username ? aconf->username : "(null)"),
+            (aconf->host ? aconf->host : "(null)"),
+            (aconf->name ? aconf->name : "(null)"),
+            ConfClass(aconf), aconf->maximum,
+            (aconf->passwd ? aconf->passwd : "(null)"));
+    break;
+  }
+
+  /* If no authorization, say so and exit. */
+  if (!aconf)
+  {
+    fprintf(stdout, "No authorization found.\n");
+    return NULL;
+  }
+
+  /* Look for a Kill block with the user's name on it. */
+  for (deny = denyConfList; deny; deny = deny->next) {
+    if (deny->usermask && match(deny->usermask, username))
+      continue;
+    if (deny->realmask && match(deny->realmask, realname))
+      continue;
+    if (deny->bits > 0) {
+      if (!ipmask_check(&address, &deny->address, deny->bits))
+        continue;
+    } else if (deny->hostmask && match(deny->hostmask, hostname))
+      continue;
+
+    /* Looks like a match; report it. */
+    fprintf(stdout, "Denied! usermask=%s realmask=\"%s\" hostmask=%s (bits=%u)\n",
+            deny->usermask ? deny->usermask : "(null)",
+            deny->realmask ? deny->realmask : "(null)",
+            deny->hostmask ? deny->hostmask : "(null)",
+            deny->bits);
+  }
+
+  return aconf;
+}
+
+/** Check whether a particular ConfItem is already attached to a
+ * Client.
+ * @param aconf ConfItem to search for
+ * @param cptr Client to check
+ * @return Non-zero if \a aconf is attached to \a cptr, zero if not.
+ */
+static int is_attached(struct ConfItem *aconf, struct Client *cptr)
+{
+  struct SLink *lp;
+
+  for (lp = cli_confs(cptr); lp; lp = lp->next) {
+    if (lp->value.aconf == aconf)
+      return 1;
+  }
+  return 0;
+}
+
+/** Associate a specific configuration entry to a *local* client (this
+ * is the one which used in accepting the connection). Note, that this
+ * automatically changes the attachment if there was an old one...
+ * @param cptr Client to attach \a aconf to
+ * @param aconf ConfItem to attach
+ * @return Authorization check result.
+ */
+enum AuthorizationCheckResult attach_conf(struct Client *cptr, struct ConfItem *aconf)
+{
+  struct SLink *lp;
+
+  if (is_attached(aconf, cptr))
+    return ACR_ALREADY_AUTHORIZED;
+  if (IsIllegal(aconf))
+    return ACR_NO_AUTHORIZATION;
+  if ((aconf->status & (CONF_OPERATOR | CONF_CLIENT)) &&
+      ConfLinks(aconf) >= ConfMaxLinks(aconf) && ConfMaxLinks(aconf) > 0)
+    return ACR_TOO_MANY_IN_CLASS;  /* Use this for printing error message */
+  lp = make_link();
+  lp->next = cli_confs(cptr);
+  lp->value.aconf = aconf;
+  cli_confs(cptr) = lp;
+  ++aconf->clients;
+  if (aconf->status & CONF_CLIENT_MASK)
+    ConfLinks(aconf)++;
+  return ACR_OK;
+}
+
+/** Return our LocalConf configuration structure.
+ * @return A pointer to #localConf.
+ */
+const struct LocalConf* conf_get_local(void)
+{
+  return &localConf;
+}
+
+/** Attach ConfItems to a client if the name passed matches that for
+ * the ConfItems or is an exact match for them.
+ * @param cptr Client getting the ConfItem attachments.
+ * @param name Filter to match ConfItem::name.
+ * @param statmask Filter to limit ConfItem::status.
+ * @return First ConfItem attached to \a cptr.
+ */
+struct ConfItem* attach_confs_byname(struct Client* cptr, const char* name,
+                                     int statmask)
+{
+  struct ConfItem* tmp;
+  struct ConfItem* first = NULL;
+
+  assert(0 != name);
+
+  if (HOSTLEN < strlen(name))
+    return 0;
+
+  for (tmp = GlobalConfList; tmp; tmp = tmp->next) {
+    if (0 != (tmp->status & statmask) && !IsIllegal(tmp)) {
+      assert(0 != tmp->name);
+      if (0 == match(tmp->name, name) || 0 == ircd_strcmp(tmp->name, name)) { 
+        if (ACR_OK == attach_conf(cptr, tmp) && !first)
+          first = tmp;
+      }
+    }
+  }
+  return first;
+}
+
+/** Attach ConfItems to a client if the host passed matches that for
+ * the ConfItems or is an exact match for them.
+ * @param cptr Client getting the ConfItem attachments.
+ * @param host Filter to match ConfItem::host.
+ * @param statmask Filter to limit ConfItem::status.
+ * @return First ConfItem attached to \a cptr.
+ */
+struct ConfItem* attach_confs_byhost(struct Client* cptr, const char* host,
+                                     int statmask)
+{
+  struct ConfItem* tmp;
+  struct ConfItem* first = 0;
+
+  assert(0 != host);
+  if (HOSTLEN < strlen(host))
+    return 0;
+
+  for (tmp = GlobalConfList; tmp; tmp = tmp->next) {
+    if (0 != (tmp->status & statmask) && !IsIllegal(tmp)) {
+      assert(0 != tmp->host);
+      if (0 == match(tmp->host, host) || 0 == ircd_strcmp(tmp->host, host)) { 
+        if (ACR_OK == attach_conf(cptr, tmp) && !first)
+          first = tmp;
+      }
+    }
+  }
+  return first;
+}
+
+/** Find a ConfItem that has the same name and user+host fields as
+ * specified.  Requires an exact match for \a name.
+ * @param name Name to match
+ * @param cptr Client to match against
+ * @param statmask Filter for ConfItem::status
+ * @return First found matching ConfItem.
+ */
+struct ConfItem* find_conf_exact(const char* name, struct Client *cptr, int statmask)
+{
+  struct ConfItem *tmp;
+
+  for (tmp = GlobalConfList; tmp; tmp = tmp->next) {
+    if (!(tmp->status & statmask) || !tmp->name || !tmp->host ||
+        0 != ircd_strcmp(tmp->name, name))
+      continue;
+    if (tmp->username
+        && (EmptyString(cli_username(cptr))
+            || match(tmp->username, cli_username(cptr))))
+      continue;
+    if (tmp->addrbits < 0)
+    {
+      if (match(tmp->host, cli_sockhost(cptr)))
+        continue;
+    }
+    else if (!ipmask_check(&cli_ip(cptr), &tmp->address.addr, tmp->addrbits))
+      continue;
+    if ((tmp->status & CONF_OPERATOR)
+        && (MaxLinks(tmp->conn_class) > 0)
+        && (tmp->clients >= MaxLinks(tmp->conn_class)))
+      continue;
+    return tmp;
+  }
+  return 0;
+}
+
+/** Find a ConfItem from a list that has a name that matches \a name.
+ * @param lp List to search in.
+ * @param name Filter for ConfItem::name field; matches either exactly
+ * or as a glob.
+ * @param statmask Filter for ConfItem::status.
+ * @return First matching ConfItem from \a lp.
+ */
+struct ConfItem* find_conf_byname(struct SLink* lp, const char* name,
+                                  int statmask)
+{
+  struct ConfItem* tmp;
+  assert(0 != name);
+
+  if (HOSTLEN < strlen(name))
+    return 0;
+
+  for (; lp; lp = lp->next) {
+    tmp = lp->value.aconf;
+    if (0 != (tmp->status & statmask)) {
+      assert(0 != tmp->name);
+      if (0 == ircd_strcmp(tmp->name, name) || 0 == match(tmp->name, name))
+        return tmp;
+    }
+  }
+  return 0;
+}
+
+/** Find a ConfItem from a list that has a host that matches \a host.
+ * @param lp List to search in.
+ * @param host Filter for ConfItem::host field; matches as a glob.
+ * @param statmask Filter for ConfItem::status.
+ * @return First matching ConfItem from \a lp.
+ */
+struct ConfItem* find_conf_byhost(struct SLink* lp, const char* host,
+                                  int statmask)
+{
+  struct ConfItem* tmp = NULL;
+  assert(0 != host);
+
+  if (HOSTLEN < strlen(host))
+    return 0;
+
+  for (; lp; lp = lp->next) {
+    tmp = lp->value.aconf;
+    if (0 != (tmp->status & statmask)) {
+      assert(0 != tmp->host);
+      if (0 == match(tmp->host, host))
+        return tmp;
+    }
+  }
+  return 0;
+}
+
+/** Find a ConfItem from a list that has an address equal to \a ip.
+ * @param lp List to search in.
+ * @param ip Filter for ConfItem::address field; matches exactly.
+ * @param statmask Filter for ConfItem::status.
+ * @return First matching ConfItem from \a lp.
+ */
+struct ConfItem* find_conf_byip(struct SLink* lp, const struct irc_in_addr* ip,
+                                int statmask)
+{
+  struct ConfItem* tmp;
+
+  for (; lp; lp = lp->next) {
+    tmp = lp->value.aconf;
+    if (0 != (tmp->status & statmask)
+        && !irc_in_addr_cmp(&tmp->address.addr, ip))
+      return tmp;
+  }
+  return 0;
+}
+
+/** Free all CRules from #cruleConfList. */
+void conf_erase_crule_list(void)
+{
+  struct CRuleConf* next;
+  struct CRuleConf* p = cruleConfList;
+
+  for ( ; p; p = next) {
+    next = p->next;
+    crule_free(&p->node);
+    MyFree(p->hostmask);
+    MyFree(p->rule);
+    MyFree(p);
+  }
+  cruleConfList = 0;
+}
+
+/** Return #cruleConfList.
+ * @return #cruleConfList
+ */
+const struct CRuleConf* conf_get_crule_list(void)
+{
+  return cruleConfList;
+}
+
+/** Free all deny rules from #denyConfList. */
+void conf_erase_deny_list(void)
+{
+  struct DenyConf* next;
+  struct DenyConf* p = denyConfList;
+  for ( ; p; p = next) {
+    next = p->next;
+    MyFree(p->hostmask);
+    MyFree(p->usermask);
+    MyFree(p->message);
+    MyFree(p->realmask);
+    MyFree(p);
+  }
+  denyConfList = 0;
+}
+
+/** Return #denyConfList.
+ * @return #denyConfList
+ */
+const struct DenyConf* conf_get_deny_list(void)
+{
+  return denyConfList;
+}
+
+/** Find any existing quarantine for the named channel.
+ * @param chname Channel name to search for.
+ * @return Reason for channel's quarantine, or NULL if none exists.
+ */
+const char*
+find_quarantine(const char *chname)
+{
+  struct qline *qline;
+
+  for (qline = GlobalQuarantineList; qline; qline = qline->next)
+    if (!ircd_strcmp(qline->chname, chname))
+      return qline->reason;
+  return NULL;
+}
+
+/** Free all qline structs from #GlobalQuarantineList. */
+void clear_quarantines(void)
+{
+  struct qline *qline;
+  while ((qline = GlobalQuarantineList))
+  {
+    GlobalQuarantineList = qline->next;
+    MyFree(qline->reason);
+    MyFree(qline->chname);
+    MyFree(qline);
+  }
+}
+
+/** When non-zero, indicates that a configuration error has been seen in this pass. */
+static int conf_error;
+/** When non-zero, indicates that the configuration file was loaded at least once. */
+static int conf_already_read;
+extern void yyparse(void);
+extern int init_lexer(void);
+extern void deinit_lexer(void);
+
+/** Read configuration file.
+ * @return Zero on failure, non-zero on success. */
+int read_configuration_file(void)
+{
+  conf_error = 0;
+  feature_unmark(); /* unmark all features for resetting later */
+  clear_nameservers(); /* clear previous list of DNS servers */
+  if (!init_lexer())
+    return 0;
+  yyparse();
+  deinit_lexer();
+  feature_mark(); /* reset unmarked features */
+  conf_already_read = 1;
+  return 1;
+}
+
+/** Report an error message about the configuration file.
+ * @param msg The error to report.
+ */
+void
+yyerror(const char *msg)
+{
+ sendto_opmask_butone(0, SNO_ALL, "Config file parse error line %d: %s",
+                      lineno, msg);
+ log_write(LS_CONFIG, L_ERROR, 0, "Config file parse error line %d: %s",
+           lineno, msg);
+ if (!conf_already_read)
+   fprintf(stderr, "Config file parse error line %d: %s\n", lineno, msg);
+ conf_error = 1;
+}
+
+/** Attach CONF_UWORLD items to a server and everything attached to it. */
+static void
+attach_conf_uworld(struct Client *cptr)
+{
+  struct DLink *lp;
+
+  attach_confs_byhost(cptr, cli_name(cptr), CONF_UWORLD);
+  for (lp = cli_serv(cptr)->down; lp; lp = lp->next)
+    attach_conf_uworld(lp->value.cptr);
+}
+
+/** Free all memory associated with service mapping \a smap.
+ * @param smap[in] The mapping to free.
+ */
+void free_mapping(struct s_map *smap)
+{
+  struct nick_host *nh, *next;
+  for (nh = smap->services; nh; nh = next)
+  {
+    next = nh->next;
+    MyFree(nh);
+  }
+  MyFree(smap->name);
+  MyFree(smap->command);
+  MyFree(smap->prepend);
+  MyFree(smap);
+}
+
+/** Unregister and free all current service mappings. */
+static void close_mappings(void)
+{
+  struct s_map *map, *next;
+
+  for (map = GlobalServiceMapList; map; map = next) {
+    next = map->next;
+    unregister_mapping(map);
+    free_mapping(map);
+  }
+  GlobalServiceMapList = NULL;
+}
+
+/** Reload the configuration file.
+ * @param cptr Client that requested rehash (if a signal, &me).
+ * @param sig Type of rehash (0 = oper-requested, 1 = signal, 2 =
+ *   oper-requested but do not restart resolver)
+ * @return CPTR_KILLED if any client was K/G-lined because of the
+ * rehash; otherwise 0.
+ */
+int rehash(struct Client *cptr, int sig)
+{
+  struct ConfItem** tmp = &GlobalConfList;
+  struct ConfItem*  tmp2;
+  struct Client*    acptr;
+  int               i;
+  int               ret = 0;
+  int               found_g = 0;
+
+  if (1 == sig)
+    sendto_opmask_butone(0, SNO_OLDSNO,
+                         "Got signal SIGHUP, reloading ircd conf. file");
+
+  while ((tmp2 = *tmp)) {
+    if (tmp2->clients) {
+      /*
+       * Configuration entry is still in use by some
+       * local clients, cannot delete it--mark it so
+       * that it will be deleted when the last client
+       * exits...
+       */
+      if (CONF_CLIENT == (tmp2->status & CONF_CLIENT))
+        tmp = &tmp2->next;
+      else {
+        *tmp = tmp2->next;
+        tmp2->next = 0;
+      }
+      tmp2->status |= CONF_ILLEGAL;
+    }
+    else {
+      *tmp = tmp2->next;
+      free_conf(tmp2);
+    }
+  }
+  conf_erase_crule_list();
+  conf_erase_deny_list();
+  motd_clear();
+  webirc_clear();
+
+  /*
+   * delete the juped nicks list
+   */
+  clearNickJupes();
+
+  clear_quarantines();
+
+  class_mark_delete();
+  mark_listeners_closing();
+  auth_mark_closing();
+  close_mappings();
+  ssl_clearcert();
+  ssl_cleartrusts();
+  ssl_setcert("ircd_cert.pem");
+  ssl_addtrust("ircd_ca.pem");
+
+  read_configuration_file();
+
+  if (sig != 2)
+    restart_resolver();
+
+  log_reopen(); /* reopen log files */
+
+  auth_close_unused();
+  close_listeners();
+  class_delete_marked();         /* unless it fails */
+
+  /*
+   * Flush out deleted I and P lines although still in use.
+   */
+  for (tmp = &GlobalConfList; (tmp2 = *tmp);) {
+    if (CONF_ILLEGAL == (tmp2->status & CONF_ILLEGAL)) {
+      *tmp = tmp2->next;
+      tmp2->next = NULL;
+      if (!tmp2->clients)
+        free_conf(tmp2);
+    }
+    else
+      tmp = &tmp2->next;
+  }
+
+  for (i = 0; i <= HighestFd; i++) {
+    if ((acptr = LocalClientArray[i])) {
+      assert(!IsMe(acptr));
+      if (IsServer(acptr))
+        det_confs_butmask(acptr, ~(CONF_UWORLD | CONF_ILLEGAL));
+      /* Because admin's are getting so uppity about people managing to
+       * get past K/G's etc, we'll "fix" the bug by actually explaining
+       * whats going on.
+       */
+      if ((found_g = find_kill(acptr))) {
+        sendto_opmask_butone(0, found_g == -2 ? SNO_GLINE : SNO_OPERKILL,
+                             found_g == -2 ? "G-line active for %s%s" :
+                             "K-line active for %s%s",
+                             IsUnknown(acptr) ? "Unregistered Client ":"",
+                             get_client_name(acptr, SHOW_IP));
+        if (exit_client(cptr, acptr, &me, found_g == -2 ? "G-lined" :
+            "K-lined") == CPTR_KILLED)
+          ret = CPTR_KILLED;
+      }
+    }
+  }
+
+  attach_conf_uworld(&me);
+
+  return ret;
+}
+
+/** Read configuration file for the very first time.
+ * @return Non-zero on success, zero on failure.
+ */
+
+int init_conf(void)
+{
+  ssl_clearcert();
+  ssl_cleartrusts();
+  ssl_setcert("ircd_cert.pem");
+  ssl_addtrust("ircd_ca.pem");
+  if (read_configuration_file()) {
+    /*
+     * make sure we're sane to start if the config
+     * file read didn't get everything we need.
+     * XXX - should any of these abort the server?
+     * TODO: add warning messages
+     */
+    if (0 == localConf.name || 0 == localConf.numeric)
+      return 0;
+    if (conf_error)
+      return 0;
+
+    if (0 == localConf.location1)
+      DupString(localConf.location1, "");
+    if (0 == localConf.location2)
+      DupString(localConf.location2, "");
+    if (0 == localConf.contact)
+      DupString(localConf.contact, "");
+
+    return 1;
+  }
+  return 0;
+}
+
+/** Searches for a K/G-line for a client.  If one is found, notify the
+ * user and disconnect them.
+ * @param cptr Client to search for.
+ * @return 0 if client is accepted; -1 if client was locally denied
+ * (K-line); -2 if client was globally denied (G-line).
+ */
+int find_kill(struct Client *cptr)
+{
+  const char*      host;
+  const char*      name;
+  const char*      realname;
+  struct DenyConf* deny;
+  struct Gline*    agline = NULL;
+
+  assert(0 != cptr);
+
+  if (!cli_user(cptr))
+    return 0;
+
+  host = cli_sockhost(cptr);
+  name = cli_user(cptr)->username;
+  realname = cli_info(cptr);
+
+  assert(strlen(host) <= HOSTLEN);
+  assert((name ? strlen(name) : 0) <= HOSTLEN);
+  assert((realname ? strlen(realname) : 0) <= REALLEN);
+
+  /* 2000-07-14: Rewrote this loop for massive speed increases.
+   *             -- Isomer
+   */
+  for (deny = denyConfList; deny; deny = deny->next) {
+    if (deny->usermask && match(deny->usermask, name))
+      continue;
+    if (deny->realmask && match(deny->realmask, realname))
+      continue;
+    if (deny->bits > 0) {
+      if (!ipmask_check(&cli_ip(cptr), &deny->address, deny->bits))
+        continue;
+    } else if (deny->hostmask && match(deny->hostmask, host))
+      continue;
+
+    if (EmptyString(deny->message))
+      send_reply(cptr, SND_EXPLICIT | ERR_YOUREBANNEDCREEP,
+                 ":Connection from your host is refused on this server.");
+    else {
+      if (deny->flags & DENY_FLAGS_FILE)
+        killcomment(cptr, deny->message);
+      else
+        send_reply(cptr, SND_EXPLICIT | ERR_YOUREBANNEDCREEP, ":%s.", deny->message);
+    }
+    return -1;
+  }
+
+  if (!feature_bool(FEAT_DISABLE_GLINES) && (agline = gline_lookup(cptr, 0))) {
+    /*
+     * find active glines
+     * added a check against the user's IP address to find_gline() -Kev
+     */
+    send_reply(cptr, SND_EXPLICIT | ERR_YOUREBANNEDCREEP, ":%s.", GlineReason(agline));
+    return -2;
+  }
+
+  return 0;
+}
+
+/** Attempt to attach Client blocks to \a cptr.  If attach_iline()
+ * fails for the client, emit a debugging message.
+ * @param cptr Client to check for access.
+ * @return Access check result.
+ */
+enum AuthorizationCheckResult conf_check_client(struct Client *cptr)
+{
+  enum AuthorizationCheckResult acr = ACR_OK;
+
+  if ((acr = attach_iline(cptr))) {
+    Debug((DEBUG_DNS, "ch_cl: access denied: %s[%s]", 
+          cli_name(cptr), cli_sockhost(cptr)));
+    return acr;
+  }
+  return ACR_OK;
+}
+
+/** Check access for a server given its name (passed in cptr struct).
+ * Must check for all C/N lines which have a name which matches the
+ * name given and a host which matches. A host alias which is the
+ * same as the server name is also acceptable in the host field of a
+ * C/N line.
+ * @param cptr Peer server to check.
+ * @return 0 if accepted, -1 if access denied.
+ */
+int conf_check_server(struct Client *cptr)
+{
+  struct ConfItem* c_conf = NULL;
+  struct SLink*    lp;
+
+  Debug((DEBUG_DNS, "sv_cl: check access for %s[%s]", 
+        cli_name(cptr), cli_sockhost(cptr)));
+
+  if (IsUnknown(cptr) && !attach_confs_byname(cptr, cli_name(cptr), CONF_SERVER)) {
+    Debug((DEBUG_DNS, "No C/N lines for %s", cli_sockhost(cptr)));
+    return -1;
+  }
+  lp = cli_confs(cptr);
+  /*
+   * We initiated this connection so the client should have a C and N
+   * line already attached after passing through the connect_server()
+   * function earlier.
+   */
+  if (IsConnecting(cptr) || IsHandshake(cptr)) {
+    c_conf = find_conf_byname(lp, cli_name(cptr), CONF_SERVER);
+    if (!c_conf) {
+      sendto_opmask_butone(0, SNO_OLDSNO,
+                           "Connect Error: lost Connect block for %s",
+                           cli_name(cptr));
+      det_confs_butmask(cptr, 0);
+      return -1;
+    }
+  }
+
+  /* Try finding the Connect block by DNS name and IP next. */
+  if (!c_conf && !(c_conf = find_conf_byhost(lp, cli_sockhost(cptr), CONF_SERVER)))
+        c_conf = find_conf_byip(lp, &cli_ip(cptr), CONF_SERVER);
+
+  /*
+   * Attach by IP# only if all other checks have failed.
+   * It is quite possible to get here with the strange things that can
+   * happen when using DNS in the way the irc server does. -avalon
+   */
+  if (!c_conf)
+    c_conf = find_conf_byip(lp, &cli_ip(cptr), CONF_SERVER);
+  /*
+   * detach all conf lines that got attached by attach_confs()
+   */
+  det_confs_butmask(cptr, 0);
+  /*
+   * if no Connect block, then deny access
+   */
+  if (!c_conf) {
+    Debug((DEBUG_DNS, "sv_cl: access denied: %s[%s@%s]",
+          cli_name(cptr), cli_username(cptr), cli_sockhost(cptr)));
+    return -1;
+  }
+  /*
+   * attach the Connect block to the client structure for later use.
+   */
+  attach_conf(cptr, c_conf);
+
+  if (!irc_in_addr_valid(&c_conf->address.addr))
+    memcpy(&c_conf->address.addr, &cli_ip(cptr), sizeof(c_conf->address.addr));
+
+  Debug((DEBUG_DNS, "sv_cl: access ok: %s[%s]",
+         cli_name(cptr), cli_sockhost(cptr)));
+  return 0;
+}
+
+/* Creates a new webirc-block and returns it. It's not added to the global list, yet. */
+struct webirc_block *webirc_block() {
+    struct webirc_block *block = MyMalloc(sizeof(struct webirc_block));
+    memset(block, 0, sizeof(struct webirc_block));
+    return block;
+}
+
+/* Adds a previously created webirc-block to the global list. */
+void webirc_establish(struct webirc_block *block) {
+    if(!GlobalWebIRCConf) {
+        block->next = block;
+        block->prev = block;
+        GlobalWebIRCConf = block;
+    }
+    else {
+        block->next = GlobalWebIRCConf;
+        block->prev = GlobalWebIRCConf->prev;
+        GlobalWebIRCConf->prev->next = block;
+        GlobalWebIRCConf->prev = block;
+        GlobalWebIRCConf = block;
+    }
+}
+
+/* Adds a new value to one webirc-block. */
+void webirc_set(struct webirc_block *block, unsigned int type, const char *content, unsigned int len, unsigned int neg) {
+    struct webirc_node *iter, *node;
+
+    ++len; /* add \0 to len */
+
+    /* default type is password */
+    if(type != WEBIRC_HOST && type != WEBIRC_SPOOF) type = WEBIRC_PASS;
+
+    node = MyMalloc(sizeof(struct webirc_node) + len);
+    node->type = type;
+    node->neg = neg;
+    node->content = (char*)((void*)node + sizeof(struct webirc_node));
+    memcpy(node->content, content, len);
+
+    /* insert into sorted list */
+    if(!block->list) {
+        node->next = node->prev = node;
+        block->list = node;
+    }
+    else if(block->list->next == block->list) {
+        node->next = node->prev = block->list;
+        block->list->next = block->list->prev = node;
+        if(block->list->type > type) block->list = node;
+    }
+    else { /* insert into sorted list */
+        iter = block->list;
+        /* find last entry with same type */
+        if(iter->type <= type) iter = iter->next;
+        while(iter->type <= type && iter != block->list) iter = iter->next;
+        node->next = iter;
+        node->prev = iter->prev;
+        iter->prev->next = node;
+        iter->prev = node;
+    }
+}
+
+void webirc_list_clear(struct webirc_block *block) {
+    struct webirc_node *iter;
+
+    if(!block->list) return;
+
+    block->list->prev->next = NULL;
+    while(block->list->next) {
+        iter = block->list;
+        block->list = block->list->next;
+        MyFree(iter);
+    }
+    MyFree(block->list);
+    block->list = NULL;
+}
+
+/* Removes the whole webirc-block list. */
+void webirc_clear() {
+    struct webirc_block *iter;
+
+    if(!GlobalWebIRCConf) return;
+
+    GlobalWebIRCConf->prev->next = NULL;
+    while(GlobalWebIRCConf->next) {
+        iter = GlobalWebIRCConf;
+        GlobalWebIRCConf = iter->next;
+        webirc_list_clear(iter);
+        MyFree(iter);
+    }
+    webirc_list_clear(GlobalWebIRCConf);
+    MyFree(GlobalWebIRCConf);
+    GlobalWebIRCConf = NULL;
+}
+
diff --git a/ircd/s_debug.c b/ircd/s_debug.c
new file mode 100644 (file)
index 0000000..76bf8c0
--- /dev/null
@@ -0,0 +1,396 @@
+/*
+ * IRC - Internet Relay Chat, ircd/s_debug.c
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ *                    University of Oulu, Computing Center
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+/** @file
+ * @brief Debug support for the ircd.
+ * @version $Id: s_debug.c 1429 2005-06-19 02:31:27Z entrope $
+ */
+#include "config.h"
+
+#include "s_debug.h"
+#include "channel.h"
+#include "class.h"
+#include "client.h"
+#include "gline.h"
+#include "hash.h"
+#include "ircd_alloc.h"
+#include "ircd_features.h"
+#include "ircd_log.h"
+#include "ircd_osdep.h"
+#include "ircd_reply.h"
+#include "ircd.h"
+#include "jupe.h"
+#include "list.h"
+#include "listener.h"
+#include "motd.h"
+#include "msgq.h"
+#include "numeric.h"
+#include "numnicks.h"
+#include "res.h"
+#include "s_bsd.h"
+#include "s_conf.h"
+#include "s_user.h"
+#include "s_stats.h"
+#include "send.h"
+#include "ssl.h"
+#include "struct.h"
+#include "sys.h"
+#include "whowas.h"
+
+/* #include <assert.h> -- Now using assert in ircd_log.h */
+#include <errno.h>
+#include <fcntl.h>
+#include <stdarg.h>
+#include <stddef.h>     /* offsetof */
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+/*
+ * Option string.  Must be before #ifdef DEBUGMODE.
+ */
+static char serveropts[256]; /* should be large enough for anything */
+
+/** Return a string describing important configuration information.
+ * @return Pointer to a static buffer.
+ */
+const char* debug_serveropts(void)
+{
+  int bp;
+  int i = 0;
+#define AddC(c)        serveropts[i++] = (c)
+
+  bp = feature_int(FEAT_BUFFERPOOL);
+  if (bp < 1000000) {
+    AddC('b');
+    if (bp > 99999)
+      AddC((char)('0' + (bp / 100000)));
+    if (bp > 9999)
+      AddC((char)('0' + (bp / 10000) % 10));
+    AddC((char)('0' + (bp / 1000) % 10));
+  } else {
+    AddC('B');
+    if (bp > 99999999)
+      AddC((char)('0' + (bp / 100000000)));
+    if (bp > 9999999)
+      AddC((char)('0' + (bp / 10000000) % 10));
+    AddC((char)('0' + (bp / 1000000) % 10));
+  }
+
+#ifndef NDEBUG
+  AddC('A');
+#endif
+#ifdef  DEBUGMODE
+  AddC('D');
+#endif
+
+  if (feature_bool(FEAT_HUB))
+    AddC('H');
+
+  if (feature_bool(FEAT_IDLE_FROM_MSG))
+    AddC('M');
+
+  if (feature_bool(FEAT_RELIABLE_CLOCK))
+    AddC('R');
+
+#if defined(USE_POLL) && defined(HAVE_POLL_H)
+  AddC('U');
+#endif
+#ifdef  IPV6
+  AddC('6');
+#endif
+
+  serveropts[i] = '\0';
+
+  return serveropts;
+}
+
+/** Initialize debugging.
+ * If the -t option is not given on the command line when the server is
+ * started, all debugging output is sent to the file set by LPATH in config.h
+ * Here we just open that file and make sure it is opened to fd 2 so that
+ * any fprintf's to stderr also go to the logfile.  If the debuglevel is not
+ * set from the command line by -x, use /dev/null as the dummy logfile as long
+ * as DEBUGMODE has been defined, else don't waste the fd.
+ * @param use_tty Passed to log_debug_init().
+ */
+void debug_init(int use_tty)
+{
+#ifdef  DEBUGMODE
+  if (debuglevel >= 0) {
+    printf("isatty = %d ttyname = %s\n", isatty(2), ttyname(2));
+    log_debug_init(use_tty);
+  }
+#endif
+}
+
+#ifdef DEBUGMODE
+/** Log a debug message using a va_list.
+ * If the current #debuglevel is less than \a level, do not display.
+ * @param level Debug level for message.
+ * @param form Format string, passed to log_vwrite().
+ * @param vl Varargs argument list for format string.
+ */
+void vdebug(int level, const char *form, va_list vl)
+{
+  static int loop = 0;
+  int err = errno;
+
+  if (!loop && (debuglevel >= 0) && (level <= debuglevel))
+  {
+    loop = 1;
+    log_vwrite(LS_DEBUG, L_DEBUG, 0, form, vl);
+    loop = 0;
+  }
+  errno = err;
+}
+
+/** Log a debug message using a variable number of arguments.
+ * This is a simple wrapper around debug(\a level, \a form, vl).
+ * @param level Debug level for message.
+ * @param form Format string of message.
+ */
+void debug(int level, const char *form, ...)
+{
+  va_list vl;
+  va_start(vl, form);
+  vdebug(level, form, vl);
+  va_end(vl);
+}
+
+/** Send a literal RPL_STATSDEBUG message to a user.
+ * @param cptr Client to receive the message.
+ * @param msg Text message to send to user.
+ */
+static void debug_enumerator(struct Client* cptr, const char* msg)
+{
+  assert(0 != cptr);
+  send_reply(cptr, SND_EXPLICIT | RPL_STATSDEBUG, ":%s", msg);
+}
+
+/** Send resource usage statistics to a client.
+ * @param cptr Client to send data to.
+ * @param sd StatDesc that generated the stats request (ignored).
+ * @param param Extra parameter from user (ignored).
+ */
+void send_usage(struct Client *cptr, const struct StatDesc *sd,
+                char *param)
+{
+  os_get_rusage(cptr, CurrentTime - cli_since(&me), debug_enumerator);
+
+  send_reply(cptr, SND_EXPLICIT | RPL_STATSDEBUG, ":DBUF alloc %d used %d",
+            DBufAllocCount, DBufUsedCount);
+}
+#endif /* DEBUGMODE */
+
+/** Report memory usage statistics to a client.
+ * @param cptr Client to send data to.
+ * @param sd StatDesc that generated the stats request (ignored).
+ * @param param Extra parameter from user (ignored).
+ */
+void count_memory(struct Client *cptr, const struct StatDesc *sd,
+                  char *param)
+{
+  struct Client *acptr;
+  struct SLink *link;
+  struct Ban *ban;
+  struct Channel *chptr;
+  struct ConfItem *aconf;
+  const struct ConnectionClass* cltmp;
+  struct Membership* member;
+
+  int acc = 0,                  /* accounts */
+      c = 0,                    /* clients */
+      cn = 0,                   /* connections */
+      ch = 0,                   /* channels */
+      lcc = 0,                  /* local client conf links */
+      chi = 0,                  /* channel invites */
+      chb = 0,                  /* channel bans */
+      wwu = 0,                  /* whowas users */
+      cl = 0,                   /* classes */
+      co = 0,                   /* conf lines */
+      listeners = 0,            /* listeners */
+      memberships = 0;          /* channel memberships */
+
+  int usi = 0,                  /* users invited */
+      aw = 0,                   /* aways set */
+      wwa = 0,                  /* whowas aways */
+      gl = 0,                   /* glines */
+      ju = 0;                   /* jupes */
+
+  size_t chm = 0,               /* memory used by channels */
+      chbm = 0,                 /* memory used by channel bans */
+      cm = 0,                   /* memory used by clients */
+      cnm = 0,                  /* memory used by connections */
+      us = 0,                   /* user structs */
+      usm = 0,                  /* memory used by user structs */
+      awm = 0,                  /* memory used by aways */
+      wwam = 0,                 /* whowas away memory used */
+      wwm = 0,                  /* whowas array memory used */
+      glm = 0,                  /* memory used by glines */
+      jum = 0,                  /* memory used by jupes */
+      com = 0,                  /* memory used by conf lines */
+      dbufs_allocated = 0,      /* memory used by dbufs */
+      dbufs_used = 0,           /* memory used by dbufs */
+      msg_allocated = 0,       /* memory used by struct Msg */
+      msgbuf_allocated = 0,    /* memory used by struct MsgBuf */
+      listenersm = 0,           /* memory used by listetners */
+      rm = 0,                   /* res memory used */
+      totcl = 0, totch = 0, totww = 0, tot = 0;
+
+  count_whowas_memory(&wwu, &wwm, &wwa, &wwam);
+  wwm += sizeof(struct Whowas) * feature_int(FEAT_NICKNAMEHISTORYLENGTH);
+  wwm += sizeof(struct Whowas *) * WW_MAX;
+
+  for (acptr = GlobalClientList; acptr; acptr = cli_next(acptr))
+  {
+    c++;
+    if (MyConnect(acptr))
+    {
+      cn++;
+      for (link = cli_confs(acptr); link; link = link->next)
+        lcc++;
+    }
+    if (cli_user(acptr))
+    {
+      for (link = cli_user(acptr)->invited; link; link = link->next)
+        usi++;
+      for (member = cli_user(acptr)->channel; member; member = member->next_channel)
+        ++memberships;
+      if (cli_user(acptr)->away)
+      {
+        aw++;
+        awm += (strlen(cli_user(acptr)->away) + 1);
+      }
+    }
+
+    if (IsAccount(acptr))
+      acc++;
+  }
+  cm = c * sizeof(struct Client);
+  cnm = cn * sizeof(struct Connection);
+  user_count_memory(&us, &usm);
+
+  for (chptr = GlobalChannelList; chptr; chptr = chptr->next)
+  {
+    ch++;
+    chm += (strlen(chptr->chname) + sizeof(struct Channel));
+    for (link = chptr->invites; link; link = link->next)
+      chi++;
+    for (ban = chptr->banlist; ban; ban = ban->next)
+    {
+      chb++;
+      chbm += strlen(ban->who) + strlen(ban->banstr) + 2 + sizeof(*ban);
+    }
+  }
+
+  for (aconf = GlobalConfList; aconf; aconf = aconf->next)
+  {
+    co++;
+    com += aconf->host ? strlen(aconf->host) + 1 : 0;
+    com += aconf->passwd ? strlen(aconf->passwd) + 1 : 0;
+    com += aconf->name ? strlen(aconf->name) + 1 : 0;
+    com += sizeof(struct ConfItem);
+  }
+
+  for (cltmp = get_class_list(); cltmp; cltmp = cltmp->next)
+    cl++;
+
+  send_reply(cptr, SND_EXPLICIT | RPL_STATSDEBUG,
+            ":Clients %d(%zu) Connections %d(%zu)", c, cm, cn, cnm);
+  send_reply(cptr, SND_EXPLICIT | RPL_STATSDEBUG,
+            ":Users %zu(%zu) Accounts %d(%zu) Invites %d(%zu)",
+             us, usm, acc, acc * (ACCOUNTLEN + 1),
+            usi, usi * sizeof(struct SLink));
+  send_reply(cptr, SND_EXPLICIT | RPL_STATSDEBUG,
+            ":User channels %d(%zu) Aways %d(%zu)", memberships,
+            memberships * sizeof(struct Membership), aw, awm);
+
+  totcl = cm + cnm + us * sizeof(struct User) + memberships * sizeof(struct Membership) + awm;
+  totcl += lcc * sizeof(struct SLink) + usi * sizeof(struct SLink);
+
+  send_reply(cptr, SND_EXPLICIT | RPL_STATSDEBUG, ":Conflines %d(%zu) Attached %d(%zu) Classes %d(%zu)",
+             co, com, lcc, lcc * sizeof(struct SLink),
+             cl, cl * sizeof(struct ConnectionClass));
+
+  send_reply(cptr, SND_EXPLICIT | RPL_STATSDEBUG,
+            ":Channels %d(%zu) Bans %d(%zu)", ch, chm, chb, chbm);
+  send_reply(cptr, SND_EXPLICIT | RPL_STATSDEBUG,
+            ":Channel Members %d(%zu) Invites %d(%zu)", memberships,
+            memberships * sizeof(struct Membership), chi,
+            chi * sizeof(struct SLink));
+
+  totch = chm + chbm + chi * sizeof(struct SLink);
+
+  send_reply(cptr, SND_EXPLICIT | RPL_STATSDEBUG,
+            ":Whowas Users %d(%zu) Away %d(%zu) Array %d(%zu)",
+             wwu, wwu * sizeof(struct User), wwa, wwam,
+             feature_int(FEAT_NICKNAMEHISTORYLENGTH), wwm);
+
+  totww = wwu * sizeof(struct User) + wwam + wwm;
+
+  motd_memory_count(cptr);
+
+  gl = gline_memory_count(&glm);
+  ju = jupe_memory_count(&jum);
+  send_reply(cptr, SND_EXPLICIT | RPL_STATSDEBUG,
+            ":Glines %d(%zu) Jupes %d(%zu)", gl, glm, ju, jum);
+
+  send_reply(cptr, SND_EXPLICIT | RPL_STATSDEBUG,
+            ":Hash: client %d(%zu), chan is the same", HASHSIZE,
+            sizeof(void *) * HASHSIZE);
+
+  count_listener_memory(&listeners, &listenersm);
+  send_reply(cptr, SND_EXPLICIT | RPL_STATSDEBUG,
+             ":Listeners allocated %d(%zu)", listeners, listenersm);
+  /*
+   * NOTE: this count will be accurate only for the exact instant that this
+   * message is being sent, so the count is affected by the dbufs that
+   * are being used to send this message out. If this is not desired, move
+   * the dbuf_count_memory call to a place before we start sending messages
+   * and cache DBufAllocCount and DBufUsedCount in variables until they 
+   * are sent.
+   */
+  dbuf_count_memory(&dbufs_allocated, &dbufs_used);
+  send_reply(cptr, SND_EXPLICIT | RPL_STATSDEBUG,
+            ":DBufs allocated %d(%zu) used %d(%zu)", DBufAllocCount,
+            dbufs_allocated, DBufUsedCount, dbufs_used);
+
+  /* The DBuf caveats now count for this, but this routine now sends
+   * replies all on its own.
+   */
+  msgq_count_memory(cptr, &msg_allocated, &msgbuf_allocated);
+
+  rm = cres_mem(cptr);
+
+  tot =
+      totww + totch + totcl + com + cl * sizeof(struct ConnectionClass) +
+      dbufs_allocated + msg_allocated + msgbuf_allocated + rm;
+  tot += sizeof(void *) * HASHSIZE * 3;
+
+#if defined(MDEBUG)
+  send_reply(cptr, SND_EXPLICIT | RPL_STATSDEBUG, ":Allocations: %zu(%zu)",
+            fda_get_block_count(), fda_get_byte_count());
+#endif
+
+  send_reply(cptr, SND_EXPLICIT | RPL_STATSDEBUG,
+            ":Total: ww %zu ch %zu cl %zu co %zu db %zu ms %zu mb %zu",
+            totww, totch, totcl, com, dbufs_allocated, msg_allocated,
+            msgbuf_allocated);
+}
diff --git a/ircd/s_err.c b/ircd/s_err.c
new file mode 100644 (file)
index 0000000..552add9
--- /dev/null
@@ -0,0 +1,1273 @@
+/*
+ * IRC - Internet Relay Chat, ircd/s_err.c
+ * Copyright (C) 1992 Darren Reed
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+/** @file
+ * @brief Error handling support.
+ * @version $Id: s_err.c 1905 2009-02-09 01:30:13Z entrope $
+ */
+#include "config.h"
+
+#include "numeric.h"
+#include "ircd_log.h"
+#include "s_debug.h"
+
+/* #include <assert.h> -- Now using assert in ircd_log.h */
+#include <string.h>
+
+/** Array of Numeric replies, indexed by numeric. */
+static Numeric replyTable[] = {
+/* 000 */
+  { 0 },
+/* 001 */
+  { RPL_WELCOME, ":Welcome to the %s IRC Network%s%s, %s", "001" },
+/* 002 */
+  { RPL_YOURHOST, ":Your host is %s, running version %s", "002" },
+/* 003 */
+  { RPL_CREATED, ":This server was created %s", "003" },
+/* 004 */
+  { RPL_MYINFO, "%s %s %s %s %s", "004" },
+/* 005 */
+  { RPL_ISUPPORT, "%s :are supported by this server", "005" },
+/* 006 */
+  { 0 },
+/* 007 */
+  { 0 },
+/* 008 */
+  { RPL_SNOMASK, "%u :: Server notice mask (%#x)", "008" },
+/* 009 */
+  { 0 },
+/* 010 */
+  { 0 },
+/* 011 */
+  { 0 },
+/* 012 */
+  { 0 },
+/* 013 */
+  { 0 },
+/* 014 */
+  { 0 },
+/* 015 */
+  { RPL_MAP, ":%s%s%s %s [%u clients]", "015" },
+/* 016 */
+  { RPL_MAPMORE, ":%s%s --> *more*", "016" },
+/* 017 */
+  { RPL_MAPEND, ":End of /MAP", "017" },
+/* 018 */
+  { 0 },
+/* 019 */
+  { 0 },
+/* 020 */
+  { 0 },
+/* 021 */
+  { 0 },
+/* 022 */
+  { 0 },
+/* 023 */
+  { 0 },
+/* 024 */
+  { 0 },
+/* 025 */
+  { 0 },
+/* 026 */
+  { 0 },
+/* 027 */
+  { 0 },
+/* 028 */
+  { 0 },
+/* 029 */
+  { 0 },
+/* 030 */
+  { RPL_APASSWARN_SET, ":Channel Admin password (+A) set to '%s'.  Are you SURE you want to use this as Admin password? You will NOT be able to change this password anymore once the channel is more than 48 hours old!", "030" },
+/* 031 */
+  { RPL_APASSWARN_SECRET, ":Use \"/MODE %s -A %s\" to remove the password and then immediately set a new one.  IMPORTANT: YOU CANNOT RECOVER THIS PASSWORD, EVER; WRITE THE PASSWORD DOWN (don't store this rescue password on disk)! Now set the channel user password (+U).", "031" },
+/* 032 */
+  { RPL_APASSWARN_CLEAR, ":WARNING: You removed the channel Admin password (+A). If you disconnect or leave the channel without setting a new password then you will not be able to set it again!  SET A NEW PASSWORD NOW!", "032" },
+/* 033 */
+  { 0 },
+/* 034 */
+  { 0 },
+/* 035 */
+  { 0 },
+/* 036 */
+  { 0 },
+/* 037 */
+  { 0 },
+/* 038 */
+  { 0 },
+/* 039 */
+  { 0 },
+/* 040 */
+  { 0 },
+/* 041 */
+  { 0 },
+/* 042 */
+  { 0 },
+/* 043 */
+  { 0 },
+/* 044 */
+  { 0 },
+/* 045 */
+  { 0 },
+/* 046 */
+  { 0 },
+/* 047 */
+  { 0 },
+/* 048 */
+  { 0 },
+/* 049 */
+  { 0 },
+/* 050 */
+  { 0 },
+/* 051 */
+  { 0 },
+/* 052 */
+  { 0 },
+/* 053 */
+  { 0 },
+/* 054 */
+  { 0 },
+/* 055 */
+  { 0 },
+/* 056 */
+  { 0 },
+/* 057 */
+  { 0 },
+/* 058 */
+  { 0 },
+/* 059 */
+  { 0 },
+/* 060 */
+  { 0 },
+/* 061 */
+  { 0 },
+/* 062 */
+  { 0 },
+/* 063 */
+  { 0 },
+/* 064 */
+  { 0 },
+/* 065 */
+  { 0 },
+/* 066 */
+  { 0 },
+/* 067 */
+  { 0 },
+/* 068 */
+  { 0 },
+/* 069 */
+  { 0 },
+/* 070 */
+  { 0 },
+/* 071 */
+  { 0 },
+/* 072 */
+  { 0 },
+/* 073 */
+  { 0 },
+/* 074 */
+  { 0 },
+/* 075 */
+  { 0 },
+/* 076 */
+  { 0 },
+/* 077 */
+  { 0 },
+/* 078 */
+  { 0 },
+/* 079 */
+  { 0 },
+/* 080 */
+  { 0 },
+/* 081 */
+  { 0 },
+/* 082 */
+  { 0 },
+/* 083 */
+  { 0 },
+/* 084 */
+  { 0 },
+/* 085 */
+  { 0 },
+/* 086 */
+  { 0 },
+/* 087 */
+  { 0 },
+/* 088 */
+  { 0 },
+/* 089 */
+  { 0 },
+/* 090 */
+  { 0 },
+/* 091 */
+  { 0 },
+/* 092 */
+  { 0 },
+/* 093 */
+  { 0 },
+/* 094 */
+  { 0 },
+/* 095 */
+  { 0 },
+/* 096 */
+  { 0 },
+/* 097 */
+  { 0 },
+/* 098 */
+  { 0 },
+/* 099 */
+  { 0 },
+/* 100 */
+  { 0 },
+/* 101 */
+  { 0 },
+/* 102 */
+  { 0 },
+/* 103 */
+  { 0 },
+/* 104 */
+  { 0 },
+/* 105 */
+  { 0 },
+/* 106 */
+  { 0 },
+/* 107 */
+  { 0 },
+/* 108 */
+  { 0 },
+/* 109 */
+  { 0 },
+/* 110 */
+  { 0 },
+/* 111 */
+  { 0 },
+/* 112 */
+  { 0 },
+/* 113 */
+  { 0 },
+/* 114 */
+  { 0 },
+/* 115 */
+  { 0 },
+/* 116 */
+  { 0 },
+/* 117 */
+  { 0 },
+/* 118 */
+  { 0 },
+/* 119 */
+  { 0 },
+/* 120 */
+  { 0 },
+/* 121 */
+  { 0 },
+/* 122 */
+  { 0 },
+/* 123 */
+  { 0 },
+/* 124 */
+  { 0 },
+/* 125 */
+  { 0 },
+/* 126 */
+  { 0 },
+/* 127 */
+  { 0 },
+/* 128 */
+  { 0 },
+/* 129 */
+  { 0 },
+/* 130 */
+  { 0 },
+/* 131 */
+  { 0 },
+/* 132 */
+  { 0 },
+/* 133 */
+  { 0 },
+/* 134 */
+  { 0 },
+/* 135 */
+  { 0 },
+/* 136 */
+  { 0 },
+/* 137 */
+  { 0 },
+/* 138 */
+  { 0 },
+/* 139 */
+  { 0 },
+/* 140 */
+  { 0 },
+/* 141 */
+  { 0 },
+/* 142 */
+  { 0 },
+/* 143 */
+  { 0 },
+/* 144 */
+  { 0 },
+/* 145 */
+  { 0 },
+/* 146 */
+  { 0 },
+/* 147 */
+  { 0 },
+/* 148 */
+  { 0 },
+/* 149 */
+  { 0 },
+/* 150 */
+  { 0 },
+/* 151 */
+  { 0 },
+/* 152 */
+  { 0 },
+/* 153 */
+  { 0 },
+/* 154 */
+  { 0 },
+/* 155 */
+  { 0 },
+/* 156 */
+  { 0 },
+/* 157 */
+  { 0 },
+/* 158 */
+  { 0 },
+/* 159 */
+  { 0 },
+/* 160 */
+  { 0 },
+/* 161 */
+  { 0 },
+/* 162 */
+  { 0 },
+/* 163 */
+  { 0 },
+/* 164 */
+  { 0 },
+/* 165 */
+  { 0 },
+/* 166 */
+  { 0 },
+/* 167 */
+  { 0 },
+/* 168 */
+  { 0 },
+/* 169 */
+  { 0 },
+/* 170 */
+  { 0 },
+/* 171 */
+  { 0 },
+/* 172 */
+  { 0 },
+/* 173 */
+  { 0 },
+/* 174 */
+  { 0 },
+/* 175 */
+  { 0 },
+/* 176 */
+  { 0 },
+/* 177 */
+  { 0 },
+/* 178 */
+  { 0 },
+/* 179 */
+  { 0 },
+/* 180 */
+  { 0 },
+/* 181 */
+  { 0 },
+/* 182 */
+  { 0 },
+/* 183 */
+  { 0 },
+/* 184 */
+  { 0 },
+/* 185 */
+  { 0 },
+/* 186 */
+  { 0 },
+/* 187 */
+  { 0 },
+/* 188 */
+  { 0 },
+/* 189 */
+  { 0 },
+/* 190 */
+  { 0 },
+/* 191 */
+  { 0 },
+/* 192 */
+  { 0 },
+/* 193 */
+  { 0 },
+/* 194 */
+  { 0 },
+/* 195 */
+  { 0 },
+/* 196 */
+  { 0 },
+/* 197 */
+  { 0 },
+/* 198 */
+  { 0 },
+/* 199 */
+  { 0 },
+/* 200 */
+  { RPL_TRACELINK, "Link %s.%s %s %s", "200" },
+/* 201 */
+  { RPL_TRACECONNECTING, "Try. %s %s", "201" },
+/* 202 */
+  { RPL_TRACEHANDSHAKE, "H.S. %s %s", "202" },
+/* 203 */
+  { RPL_TRACEUNKNOWN, "???? %s %s", "203" },
+/* 204 */
+  { RPL_TRACEOPERATOR, "Oper %s %s %ld", "204" },
+/* 205 */
+  { RPL_TRACEUSER, "User %s %s %ld", "205" },
+/* 206 */
+  { RPL_TRACESERVER, "Serv %s %dS %dC %s %s!%s@%s %ld %ld", "206" },
+/* 207 */
+  { 0 },
+/* 208 */
+  { RPL_TRACENEWTYPE, "<newtype> 0 %s", "208" },
+/* 209 */
+  { RPL_TRACECLASS, "Class %s %u", "209" },
+/* 210 */
+  { 0 },
+/* 211 */
+  { RPL_STATSLINKINFO, 0, "211" },
+/* 212 */
+  { RPL_STATSCOMMANDS, "%s %u %u", "212" },
+/* 213 */
+  { RPL_STATSCLINE, "C %s * %d %d %s %s", "213" },
+/* 214 */
+  { 0 },
+/* 215 */
+  { RPL_STATSILINE, "I %s%s%s %d %s%s %d %s", "215" },
+/* 216 */
+  { RPL_STATSKLINE, "%c %s@%s \"%s\" \"%s\" 0 0", "216" },
+/* 217 */
+  { RPL_STATSPLINE, "P %d %d %s %s", "217" },
+/* 218 */
+  { RPL_STATSYLINE, "%c %s %d %d %u %u %u %u", "218" },
+/* 219 */
+  { RPL_ENDOFSTATS, "%s :End of /STATS report", "219" },
+/* 220 */
+  { 0 },
+/* 221 */
+  { RPL_UMODEIS, "%s", "221" },
+/* 222 */
+  { RPL_STATSJLINE, "J %s", "222" },
+/* 223 */
+  { 0 },
+/* 224 */
+  { 0 },
+/* 225 */
+  { 0 },
+/* 226 */
+  { RPL_STATSALINE, "%s", "226" },
+/* 227 */
+  { 0 },
+/* 228 */
+  { RPL_STATSQLINE, "Q %s :%s", "228" },
+/* 229 */
+  { 0 },
+/* 230 */
+  { 0 },
+/* 231 */
+  { 0 },
+/* 232 */
+  { 0 },
+/* 233 */
+  { 0 },
+/* 234 */
+  { 0 },
+/* 235 */
+  { 0 },
+/* 236 */
+  { RPL_STATSVERBOSE, "V :Sent as explicit", "236" },
+/* 237 */
+  { RPL_STATSENGINE, "%s :Event loop engine", "237" },
+/* 238 */
+  { RPL_STATSFLINE, "F %s %s", "238" },
+/* 239 */
+  { 0 },
+/* 240 */
+  { 0 },
+/* 241 */
+  { RPL_STATSLLINE, "Module Description EntryPoint", "241" },
+/* 242 */
+  { RPL_STATSUPTIME, ":Server Up %d days, %d:%02d:%02d", "242" },
+/* 243 */
+  { RPL_STATSOLINE, "%c %s@%s * %s %s", "243" },
+/* 244 */
+  { 0 },
+/* 245 */
+  { 0 },
+/* 246 */
+  { RPL_STATSTLINE, "%c %s %s", "246" },
+/* 247 */
+  { RPL_STATSGLINE, "%c %s%s%s %Tu %Tu %Tu %s%c :%s", "247" },
+/* 248 */
+  { RPL_STATSULINE, "U %s", "248" },
+/* 249 */
+  { RPL_STATSDEBUG, 0, "249" },
+/* 250 */
+  { RPL_STATSCONN, ":Highest connection count: %u (%u clients)", "250" },
+/* 251 */
+  { RPL_LUSERCLIENT, ":There are %u users and %u invisible on %u servers", "251" },
+/* 252 */
+  { RPL_LUSEROP, "%u :operator(s) online", "252" },
+/* 253 */
+  { RPL_LUSERUNKNOWN, "%u :unknown connection(s)", "253" },
+/* 254 */
+  { RPL_LUSERCHANNELS, "%u :channels formed", "254" },
+/* 255 */
+  { RPL_LUSERME, ":I have %u clients and %u servers", "255" },
+/* 256 */
+  { RPL_ADMINME, ":Administrative info about %s", "256" },
+/* 257 */
+  { RPL_ADMINLOC1, ":%s", "257" },
+/* 258 */
+  { RPL_ADMINLOC2, ":%s", "258" },
+/* 259 */
+  { RPL_ADMINEMAIL, ":%s", "259" },
+/* 260 */
+  { 0 },
+/* 261 */
+  { 0 },
+/* 262 */
+  { RPL_TRACEEND, ":End of TRACE", "262" },
+/* 263 */
+  { 0 },
+/* 264 */
+  { 0 },
+/* 265 */
+  { 0 },
+/* 266 */
+  { 0 },
+/* 267 */
+  { 0 },
+/* 268 */
+  { 0 },
+/* 269 */
+  { 0 },
+/* 270 */
+  { RPL_PRIVS, "%s :", "270" },
+/* 271 */
+  { RPL_SILELIST, "%s %s%s", "271" },
+/* 272 */
+  { RPL_ENDOFSILELIST, "%s :End of Silence List", "272" },
+/* 273 */
+  { 0 },
+/* 274 */
+  { 0 },
+/* 275 */
+  { RPL_STATSDLINE, "%c %s %s", "275" },
+/* 276 */
+  { RPL_STATSRLINE, "%-9s %-9s %-10s %s", "276" },
+/* 277 */
+  { 0 },
+/* 278 */
+  { 0 },
+/* 279 */
+  { 0 },
+/* 280 */
+  { RPL_GLIST, "%s%s%s %Tu %Tu %Tu %s %s%c :%s", "280" },
+/* 281 */
+  { RPL_ENDOFGLIST, ":End of G-line List", "281" },
+/* 282 */
+  { RPL_JUPELIST, "%s %Tu %s %c :%s", "282" },
+/* 283 */
+  { RPL_ENDOFJUPELIST, ":End of Jupe List", "283" },
+/* 284 */
+  { RPL_FEATURE, 0, "284" },
+/* 285 */
+  { 0 },
+/* 286 */
+  { RPL_CHKHEAD, ":Information for %s %s", "286" },
+/* 287 */
+  { RPL_CHANUSER, ":    %s%s (%s@%s)   (%s) %s", "287" },
+/* 288 */
+  { 0 },
+/* 289 */
+  { 0 },
+/* 290 */
+  { RPL_DATASTR, ":%s", "290" },
+/* 291 */
+  { RPL_ENDOFCHECK, ":%s", "291" },
+/* 292 */
+  { 0 },
+/* 293 */
+  { 0 },
+/* 294 */
+  { 0 },
+/* 295 */
+  { 0 },
+/* 296 */
+  { 0 },
+/* 297 */
+  { 0 },
+/* 298 */
+  { 0 },
+/* 299 */
+  { 0 },
+/* 300 */
+  { 0 },
+/* 301 */
+  { RPL_AWAY, "%s :%s", "301" },
+/* 302 */
+  { RPL_USERHOST, ":", "302" },
+/* 303 */
+  { RPL_ISON, ":", "303" },
+/* 304 */
+  { 0 },
+/* 305 */
+  { RPL_UNAWAY, ":You are no longer marked as being away", "305" },
+/* 306 */
+  { RPL_NOWAWAY, ":You have been marked as being away", "306" },
+/* 307 */
+  { 0 },
+/* 308 */
+  { 0 },
+/* 309 */
+  { 0 },
+/* 310 */
+  { 0 },
+/* 311 */
+  { RPL_WHOISUSER, "%s %s %s * :%s", "311" },
+/* 312 */
+  { RPL_WHOISSERVER, "%s %s :%s (%s%s)", "312" },
+/* 313 */
+  { RPL_WHOISOPERATOR, "%s :%s", "313" },
+/* 314 */
+  { RPL_WHOWASUSER, "%s %s %s * :%s", "314" },
+/* 315 */
+  { RPL_ENDOFWHO, "%s :End of /WHO list.", "315" },
+/* 316 */
+  { 0 },
+/* 317 */
+  { RPL_WHOISIDLE, "%s %ld %ld :seconds idle, signon time", "317" },
+/* 318 */
+  { RPL_ENDOFWHOIS, "%s :End of /WHOIS list.", "318" },
+/* 319 */
+  { RPL_WHOISCHANNELS, "%s :%s", "319" },
+/* 320 */
+  { RPL_WHOISSSL, " %s :is connected via SSL", "320" },
+/* 321 */
+  { RPL_LISTSTART, "Channel :Users  Name", "321" },
+/* 322 */
+  { RPL_LIST, "%s %u :%s", "322" },
+/* 323 */
+  { RPL_LISTEND, ":End of /LIST", "323" },
+/* 324 */
+  { RPL_CHANNELMODEIS, "%s %s %s", "324" },
+/* 325 */
+  { 0 },
+/* 326 */
+  { 0 },
+/* 327 */
+  { 0 },
+/* 328 */
+  { 0 },
+/* 329 */
+  { RPL_CREATIONTIME, "%s %Tu", "329" },
+/* 330 */
+  { RPL_WHOISACCOUNT, "%s %s :is logged in as", "330" },
+/* 331 */
+  { RPL_NOTOPIC, "%s :No topic is set.", "331" },
+/* 332 */
+  { RPL_TOPIC, "%s :%s", "332" },
+/* 333 */
+  { RPL_TOPICWHOTIME, "%s %s %Tu", "333" },
+/* 334 */
+  { RPL_LISTUSAGE, ":%s", "334" },
+/* 335 */
+  { 0 },
+/* 336 */
+  { 0 },
+/* 337 */
+  { 0 },
+/* 338 */
+  { RPL_WHOISACTUALLY, "%s %s@%s %s :Actual user@host, Actual IP", "338" },
+/* 339 */
+  { 0 },
+/* 340 */
+  { RPL_USERIP, ":", "340" },
+/* 341 */
+  { RPL_INVITING, "%s %s", "341" },
+/* 342 */
+  { 0 },
+/* 343 */
+  { 0 },
+/* 344 */
+  { 0 },
+/* 345 */
+  { RPL_ISSUEDINVITE, "%s %s %s :%s has been invited by %s", "345" },
+/* 346 */
+  { RPL_INVITELIST, ":%s", "346" },
+/* 347 */
+  { RPL_ENDOFINVITELIST, ":End of Invite List", "347" },
+/* 348 */
+  { RPL_EXCEPTIONLIST, "%s %s %s %Tu", "348" },
+/* 349 */
+  { RPL_ENDOFEXCEPTIONLIST, "%s :End of Channel Exception List", "349" },
+/* 350 */
+  { 0 },
+/* 351 */
+  { RPL_VERSION, "%s.%s %s :%s", "351" },
+/* 352 */
+  { RPL_WHOREPLY, "%s", "352" },
+/* 353 */
+  { RPL_NAMREPLY, "%s", "353" },
+/* 354 */
+  { RPL_WHOSPCRPL, "%s", "354" },
+/* 355 */
+  { RPL_DELNAMREPLY, "%s", "355" },
+/* 356 */
+  { 0 },
+/* 357 */
+  { 0 },
+/* 358 */
+  { 0 },
+/* 359 */
+  { 0 },
+/* 360 */
+  { 0 },
+/* 361 */
+  { 0 },
+/* 362 */
+  { RPL_CLOSING, "%s :Operator enforced Close", "362" },
+/* 363 */
+  { RPL_CLOSEEND, "%d :Connections Closed", "363" },
+/* 364 */
+  { RPL_LINKS, "%s %s :%u P%u %s", "364" },
+/* 365 */
+  { RPL_ENDOFLINKS, "%s :End of /LINKS list.", "365" },
+/* 366 */
+  { RPL_ENDOFNAMES, "%s :End of /NAMES list.", "366" },
+/* 367 */
+  { RPL_BANLIST, "%s %s %s %Tu", "367" },
+/* 368 */
+  { RPL_ENDOFBANLIST, "%s :End of Channel Ban List", "368" },
+/* 369 */
+  { RPL_ENDOFWHOWAS, "%s :End of WHOWAS", "369" },
+/* 370 */
+  { 0 },
+/* 371 */
+  { RPL_INFO, ":%s", "371" },
+/* 372 */
+  { RPL_MOTD, ":- %s", "372" },
+/* 373 */
+  { 0 },
+/* 374 */
+  { RPL_ENDOFINFO, ":End of /INFO list.", "374" },
+/* 375 */
+  { RPL_MOTDSTART, ":- %s Message of the Day - ", "375" },
+/* 376 */
+  { RPL_ENDOFMOTD, ":End of /MOTD command.", "376" },
+/* 377 */
+  { RPL_WHOISWEBIRC, " %s :is a WebIRC user", "377" },
+/* 378 */
+  { RPL_WHOISWEBIRCLONG, " %s :is a WebIRC user via %s: %s (%s)", "378" },
+/* 379 */
+  { 0 },
+/* 380 */
+  { 0 },
+/* 381 */
+  { RPL_YOUREOPER, ":You are now an IRC Operator", "381" },
+/* 382 */
+  { RPL_REHASHING, "%s :Rehashing", "382" },
+/* 383 */
+  { 0 },
+/* 384 */
+  { 0 },
+/* 385 */
+  { 0 },
+/* 386 */
+  { 0 },
+/* 387 */
+  { 0 },
+/* 388 */
+  { 0 },
+/* 389 */
+  { 0 },
+/* 390 */
+  { 0 },
+/* 391 */
+  { RPL_TIME, "%s %Tu %ld :%s", "391" },
+/* 392 */
+  { 0 },
+/* 393 */
+  { 0 },
+/* 394 */
+  { 0 },
+/* 395 */
+  { 0 },
+/* 396 */
+  { RPL_HOSTHIDDEN, "%s :is now your hidden host", "396" },
+/* 397 */
+  { 0 },
+/* 398 */
+  { 0 },
+/* 399 */
+  { 0 },
+/* 400 */
+  { 0 },
+/* 401 */
+  { ERR_NOSUCHNICK, "%s :No such nick", "401" },
+/* 402 */
+  { ERR_NOSUCHSERVER, "%s :No such server", "402" },
+/* 403 */
+  { ERR_NOSUCHCHANNEL, "%s :No such channel", "403" },
+/* 404 */
+  { ERR_CANNOTSENDTOCHAN, "%s :Cannot send to channel", "404" },
+/* 405 */
+  { ERR_TOOMANYCHANNELS, "%s :You have joined too many channels", "405" },
+/* 406 */
+  { ERR_WASNOSUCHNICK, "%s :There was no such nickname", "406" },
+/* 407 */
+  { ERR_TOOMANYTARGETS, "%s :Duplicate recipients. No message delivered", "407" },
+/* 408 */
+  { ERR_SEARCHNOMATCH, ":%s %s No matching record(s) found", "408" },
+/* 409 */
+  { ERR_NOORIGIN, ":No origin specified", "409" },
+/* 410 */
+  { ERR_UNKNOWNCAPCMD, "%s :Unknown CAP subcommand", "410" },
+/* 411 */
+  { ERR_NORECIPIENT, ":No recipient given (%s)", "411" },
+/* 412 */
+  { ERR_NOTEXTTOSEND, ":No text to send", "412" },
+/* 413 */
+  { ERR_NOTOPLEVEL, "%s :No toplevel domain specified", "413" },
+/* 414 */
+  { ERR_WILDTOPLEVEL, "%s :Wildcard in toplevel Domain", "414" },
+/* 415 */
+  { 0 },
+/* 416 */
+  { ERR_QUERYTOOLONG, "%s :Too many lines in the output, restrict your query", "416" },
+/* 417 */
+  { ERR_INPUTTOOLONG, ":Input line was too long", "417" },
+/* 418 */
+  { 0 },
+/* 419 */
+  { 0 },
+/* 420 */
+  { 0 },
+/* 421 */
+  { ERR_UNKNOWNCOMMAND, "%s :Unknown command", "421" },
+/* 422 */
+  { ERR_NOMOTD, ":MOTD File is missing", "422" },
+/* 423 */
+  { ERR_NOADMININFO, "%s :No administrative info available", "423" },
+/* 424 */
+  { 0 },
+/* 425 */
+  { 0 },
+/* 426 */
+  { 0 },
+/* 427 */
+  { 0 },
+/* 428 */
+  { 0 },
+/* 429 */
+  { 0 },
+/* 430 */
+  { 0 },
+/* 431 */
+  { ERR_NONICKNAMEGIVEN, ":No nickname given", "431" },
+/* 432 */
+  { ERR_ERRONEUSNICKNAME, "%s :Erroneous Nickname", "432" },
+/* 433 */
+  { ERR_NICKNAMEINUSE, "%s :Nickname is already in use.", "433" },
+/* 434 */
+  { 0 },
+/* 435 */
+  { 0 },
+/* 436 */
+  { ERR_NICKCOLLISION, "%s :Nickname collision KILL", "436" },
+/* 437 */
+  { ERR_BANNICKCHANGE, "%s :Cannot change nickname while banned on channel or channel is moderated", "437" },
+/* 438 */
+  { ERR_NICKTOOFAST, "%s :Nick change too fast. Please wait %d seconds.", "438" },
+/* 439 */
+  { ERR_TARGETTOOFAST, "%s :Target change too fast. Please wait %d seconds.", "439" },
+/* 440 */
+  { ERR_SERVICESDOWN, "%s :Services are currently unavailable.", "440" },
+/* 441 */
+  { ERR_USERNOTINCHANNEL, "%s %s :They aren't on that channel", "441" },
+/* 442 */
+  { ERR_NOTONCHANNEL, "%s :You're not on that channel", "442" },
+/* 443 */
+  { ERR_USERONCHANNEL, "%s %s :is already on channel", "443" },
+/* 444 */
+  { 0 },
+/* 445 */
+  { 0 },
+/* 446 */
+  { 0 },
+/* 447 */
+  { 0 },
+/* 448 */
+  { 0 },
+/* 449 */
+  { 0 },
+/* 450 */
+  { 0 },
+/* 451 */
+  { ERR_NOTREGISTERED, ":You have not registered", "451" },
+/* 452 */
+  { 0 },
+/* 453 */
+  { 0 },
+/* 454 */
+  { 0 },
+/* 455 */
+  { 0 },
+/* 456 */
+  { 0 },
+/* 457 */
+  { 0 },
+/* 458 */
+  { 0 },
+/* 459 */
+  { 0 },
+/* 460 */
+  { 0 },
+/* 461 */
+  { ERR_NEEDMOREPARAMS, "%s :Not enough parameters", "461" },
+/* 462 */
+  { ERR_ALREADYREGISTRED, ":You may not reregister", "462" },
+/* 463 */
+  { ERR_NOPERMFORHOST, ":Your host isn't among the privileged", "463" },
+/* 464 */
+  { ERR_PASSWDMISMATCH, ":Password Incorrect", "464" },
+/* 465 */
+  { ERR_YOUREBANNEDCREEP, ":You are banned from this server", "465" },
+/* 466 */
+  { ERR_YOUWILLBEBANNED, "", "466" },
+/* 467 */
+  { ERR_KEYSET, "%s :Channel key already set", "467" },
+/* 468 */
+  { ERR_INVALIDUSERNAME, 0, "468" },
+/* 469 */
+  { 0 },
+/* 470 */
+  { ERR_JOINACCESS, "%s :Cannot join channel (+a)", "470" },
+/* 471 */
+  { ERR_CHANNELISFULL, "%s :Cannot join channel (+l)", "471" },
+/* 472 */
+  { ERR_UNKNOWNMODE, "%c :is unknown mode char to me", "472" },
+/* 473 */
+  { ERR_INVITEONLYCHAN, "%s :Cannot join channel (+i)", "473" },
+/* 474 */
+  { ERR_BANNEDFROMCHAN, "%s :Cannot join channel (+b)", "474" },
+/* 475 */
+  { ERR_BADCHANNELKEY, "%s :Cannot join channel (+k)", "475" },
+/* 476 */
+  { ERR_BADCHANMASK, "%s :Bad Channel Mask", "476" },
+/* 477 */
+  { ERR_NEEDREGGEDNICK, "%s :Cannot join channel (+r): this channel requires authentication -- you can obtain an account from %s", "477" },
+/* 478 */
+  { ERR_BANLISTFULL, "%s %s :Channel ban/ignore list is full", "478" },
+/* 479 */
+  { ERR_BADCHANNAME, "%s :Cannot join channel (Badchanneled: %s)", "479" },
+/* 480 */
+  { 0 },
+/* 481 */
+  { ERR_NOPRIVILEGES, ":Permission Denied: Insufficient privileges", "481" },
+/* 482 */
+  { ERR_CHANOPRIVSNEEDED, "%s :You're not channel operator", "482" },
+/* 483 */
+  { ERR_CANTKILLSERVER, ":You cant kill a server!", "483" },
+/* 484 */
+  { ERR_ISCHANSERVICE, "%s %s :Cannot kill, kick or deop this IRC operator", "484" },
+/* 485 */
+  { 0 },
+/* 486 */
+  { 0 },
+/* 487 */
+  { 0 },
+/* 488 */
+  { 0 },
+/* 489 */
+  { ERR_VOICENEEDED, "%s :You're neither voiced nor channel operator", "489" },
+/* 490 */
+  { 0 },
+/* 491 */
+  { ERR_NOOPERHOST, ":No Operator block for your host", "491" },
+/* 492 */
+  { 0 },
+/* 493 */
+  { ERR_NOFEATURE, "%s :No such feature", "493" },
+/* 494 */
+  { ERR_BADFEATVALUE, "%s :Bad value for feature %s", "494" },
+/* 495 */
+  { ERR_BADLOGTYPE, "%s :No such log type", "495" },
+/* 496 */
+  { ERR_BADLOGSYS, "%s :No such log subsystem", "496" },
+/* 497 */
+  { ERR_BADLOGVALUE, "%s :Bad value for log type", "497" },
+/* 498 */
+  { ERR_ISOPERLCHAN, "%s %s :Cannot kick or deop an IRC Operator on a local channel", "498" },
+/* 499 */
+  { 0 },
+/* 500 */
+  { 0 },
+/* 501 */
+  { ERR_UMODEUNKNOWNFLAG, "%c :Unknown user MODE flag", "501" },
+/* 502 */
+  { ERR_USERSDONTMATCH, ":Cant change mode for other users", "502" },
+/* 503 */
+  { 0 },
+/* 504 */
+  { 0 },
+/* 505 */
+  { 0 },
+/* 506 */
+  { 0 },
+/* 507 */
+  { 0 },
+/* 508 */
+  { 0 },
+/* 509 */
+  { 0 },
+/* 510 */
+  { 0 },
+/* 511 */
+  { ERR_SILELISTFULL, "%s :Your silence list is full", "511" },
+/* 512 */
+  { ERR_NOSUCHGLINE, "%s :No such gline", "512" },
+/* 513 */
+  { ERR_BADPING, 0, "513" },
+/* 514 */
+  { ERR_NOSUCHJUPE, "%s :No such jupe", "514" },
+/* 515 */
+  { ERR_BADEXPIRE, "%Tu :Bad expire time", "515" },
+/* 516 */
+  { ERR_DONTCHEAT, "%s :Don't Cheat.", "516" },
+/* 517 */
+  { ERR_DISABLED, "%s :Command disabled.", "517" },
+/* 518 */
+  { ERR_LONGMASK, " :Mask is too long", "518" },
+/* 519 */
+  { ERR_TOOMANYUSERS, "%d :Too many users affected by mask", "519" },
+/* 520 */
+  { ERR_MASKTOOWIDE, "%s :Mask is too wide", "520" },
+/* 521 */
+  { ERR_CHANGEDEXPIRE, "%Tu :Bad expire time, changed to %d", "521" },
+/* 522 */
+  { 0 },
+/* 523 */
+  { 0 },
+/* 524 */
+  { ERR_QUARANTINED, "%s :Channel is quarantined : %s", "524" },
+/* 525 */
+  { ERR_INVALIDKEY, "%s :Key is not well-formed", "525" },
+/* 526 */
+  { 0 },
+/* 527 */
+  { 0 },
+/* 528 */
+  { 0 },
+/* 529 */
+  { 0 },
+/* 530 */
+  { 0 },
+/* 531 */
+  { 0 },
+/* 532 */
+  { 0 },
+/* 533 */
+  { 0 },
+/* 534 */
+  { 0 },
+/* 535 */
+  { 0 },
+/* 536 */
+  { 0 },
+/* 537 */
+  { 0 },
+/* 538 */
+  { 0 },
+/* 539 */
+  { 0 },
+/* 540 */
+  { 0 },
+/* 541 */
+  { 0 },
+/* 542 */
+  { 0 },
+/* 543 */
+  { 0 },
+/* 544 */
+  { 0 },
+/* 545 */
+  { 0 },
+/* 546 */
+  { 0 },
+/* 547 */
+  { 0 },
+/* 548 */
+  { 0 },
+/* 549 */
+  { 0 },
+/* 550 */
+  { 0 },
+/* 551 */
+  { 0 },
+/* 552 */
+  { 0 },
+/* 553 */
+  { 0 },
+/* 554 */
+  { 0 },
+/* 555 */
+  { 0 },
+/* 556 */
+  { 0 },
+/* 557 */
+  { 0 },
+/* 558 */
+  { 0 },
+/* 559 */
+  { 0 },
+/* 560 */
+  { ERR_NOTLOWEROPLEVEL, "%s %s %hu %hu :Cannot %s someone with %s op-level", "560" },
+/* 561 */
+  { ERR_NOTMANAGER, "%s :You must be channel Admin to add or remove a password. Use /JOIN %s <AdminPass>.", "561" },
+/* 562 */
+  { ERR_CHANSECURED, "%s :Channel is older than 48 hours and secured. Cannot change Admin pass anymore", "562" },
+/* 563 */
+  { ERR_UPASSSET, "%s :Cannot remove Admin pass (+A) while User pass (+U) is still set. First use /MODE %s -U <userpass>", "563" },
+/* 564 */
+  { ERR_UPASSNOTSET, "%s :Cannot set user pass (+U) until Admin pass (+A) is set. First use /MODE %s +A <adminpass>", "564" },
+/* 565 */
+  { 0 },
+/* 566 */
+  { ERR_NOMANAGER, "%s :Re-create the channel. The channel must be completely empty for a period of %s before it can be recreated.", "566" },
+/* 567 */
+  { ERR_UPASS_SAME_APASS, "%s :Cannot use the same pass for both admin (+A) and user (+U) pass.", "567" },
+/* 568 */
+  { 0 },
+/* 569 */
+  { 0 },
+/* 570 */
+  { 0 },
+/* 571 */
+  { 0 },
+/* 572 */
+  { 0 },
+/* 573 */
+  { 0 },
+/* 574 */
+  { 0 },
+/* 575 */
+  { 0 },
+/* 576 */
+  { 0 },
+/* 577 */
+  { 0 },
+/* 578 */
+  { 0 },
+/* 579 */
+  { 0 },
+/* 580 */
+  { 0 },
+/* 581 */
+  { 0 },
+/* 582 */
+  { 0 },
+/* 583 */
+  { 0 },
+/* 584 */
+  { 0 },
+/* 585 */
+  { 0 },
+/* 586 */
+  { 0 },
+/* 587 */
+  { 0 },
+/* 588 */
+  { 0 },
+/* 589 */
+  { 0 },
+/* 590 */
+  { 0 },
+/* 591 */
+  { 0 },
+/* 592 */
+  { 0 },
+/* 593 */
+  { 0 },
+/* 594 */
+  { 0 },
+/* 595 */
+  { 0 },
+/* 596 */
+  { 0 },
+/* 597 */
+  { 0 },
+/* 598 */
+  { 0 },
+/* 599 */
+  { 0 }
+};
+
+/** Return a pointer to the Numeric for a particular code.
+ * @param n %Numeric to look up.
+ * @return Numeric structure.
+ */
+const struct Numeric* get_error_numeric(int n)
+{
+  assert(0 < n);
+  assert(n < ERR_LASTERROR);
+  assert(0 != replyTable[n].value);
+
+  return &replyTable[n];
+}
+
+/** Return a format string for a numeric response.
+ * @param n %Numeric to look up.
+ * @return Pointer to a static buffer containing the format string.
+ */
+char* rpl_str(int n)
+{
+  static char numbuff[512];
+  Numeric* p;
+
+  assert(0 < n);
+  assert(n < ERR_LASTERROR);
+  assert(0 != replyTable[n].value);
+
+  p = &replyTable[n];
+  strcpy(numbuff, ":%s 000 %s ");
+  if (p->str) {
+    numbuff[4] = p->str[0];
+    numbuff[5] = p->str[1];
+    numbuff[6] = p->str[2];
+    strcpy(numbuff + 11, p->format);
+  }
+
+  return numbuff;
+}
+
diff --git a/ircd/s_misc.c b/ircd/s_misc.c
new file mode 100644 (file)
index 0000000..203f34e
--- /dev/null
@@ -0,0 +1,608 @@
+/*
+ * IRC - Internet Relay Chat, ircd/s_misc.c (formerly ircd/date.c)
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ *                    University of Oulu, Computing Center
+ *
+ * See file AUTHORS in IRC package for additional names of
+ * the programmers.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+/** @file
+ * @brief Miscellaneous support functions.
+ * @version $Id: s_misc.c 1818 2007-07-14 02:40:01Z isomer $
+ */
+#include "config.h"
+
+#include "s_misc.h"
+#include "IPcheck.h"
+#include "channel.h"
+#include "client.h"
+#include "hash.h"
+#include "ircd.h"
+#include "ircd_alloc.h"
+#include "ircd_features.h"
+#include "ircd_log.h"
+#include "ircd_reply.h"
+#include "ircd_snprintf.h"
+#include "ircd_string.h"
+#include "list.h"
+#include "match.h"
+#include "msg.h"
+#include "numeric.h"
+#include "numnicks.h"
+#include "parse.h"
+#include "querycmds.h"
+#include "res.h"
+#include "s_auth.h"
+#include "s_bsd.h"
+#include "s_conf.h"
+#include "s_debug.h"
+#include "s_stats.h"
+#include "s_user.h"
+#include "send.h"
+#include "struct.h"
+#include "sys.h"
+#include "uping.h"
+#include "userload.h"
+
+/* #include <assert.h> -- Now using assert in ircd_log.h */
+#include <fcntl.h>
+#include <netdb.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+/** Array of English month names (0 = January). */
+static char *months[] = {
+  "January", "February", "March", "April",
+  "May", "June", "July", "August",
+  "September", "October", "November", "December"
+};
+
+/** Array of English day names (0 = Sunday). */
+static char *weekdays[] = {
+  "Sunday", "Monday", "Tuesday", "Wednesday",
+  "Thursday", "Friday", "Saturday"
+};
+
+/*
+ * stats stuff
+ */
+/** Global statistics structure. */
+static struct ServerStatistics ircst;
+/** Public pointer to global statistics structure. */
+struct ServerStatistics* ServerStats = &ircst;
+
+/** Formats a Unix time as a readable string.
+ * @param clock Unix time to format (0 means #CurrentTime).
+ * @return Pointer to a static buffer containing something like
+ * "Sunday January 1 2000 -- 09:30 +01:00"
+ */
+char *date(time_t clock)
+{
+  static char buf[80], plus;
+  struct tm *lt, *gm;
+  struct tm gmbuf;
+  int minswest;
+
+  if (!clock)
+    clock = CurrentTime;
+  gm = gmtime(&clock);
+  memcpy(&gmbuf, gm, sizeof(gmbuf));
+  gm = &gmbuf;
+  lt = localtime(&clock);
+
+  /* There is unfortunately no clean portable way to extract time zone
+   * offset information, so do ugly things.
+   */
+  minswest = (gm->tm_hour - lt->tm_hour) * 60 + (gm->tm_min - lt->tm_min);
+  if (lt->tm_yday != gm->tm_yday)
+  {
+    if ((lt->tm_yday > gm->tm_yday && lt->tm_year == gm->tm_year) ||
+        (lt->tm_yday < gm->tm_yday && lt->tm_year != gm->tm_year))
+      minswest -= 24 * 60;
+    else
+      minswest += 24 * 60;
+  }
+
+  plus = (minswest > 0) ? '-' : '+';
+  if (minswest < 0)
+    minswest = -minswest;
+
+  sprintf(buf, "%s %s %d %d -- %02d:%02d %c%02d:%02d",
+      weekdays[lt->tm_wday], months[lt->tm_mon], lt->tm_mday,
+      1900 + lt->tm_year, lt->tm_hour, lt->tm_min,
+      plus, minswest / 60, minswest % 60);
+
+  return buf;
+}
+
+/** Like ctime() but with no trailing newline. Also, it takes
+ * the time value as parameter, instead of pointer to it.
+ * @param value Unix time to format.
+ * @return Pointer to a static buffer containing formatted time.
+ */
+char *myctime(time_t value)
+{
+  /* Use a secondary buffer in case ctime() would not replace an
+   * overwritten newline.
+   */
+  static char buf[28];
+  char *p;
+
+  strcpy(buf, ctime(&value));
+  if ((p = strchr(buf, '\n')) != NULL)
+    *p = '\0';
+
+  return buf;
+}
+
+/** Return the name of the client for various tracking and admin
+ * purposes. The main purpose of this function is to return the
+ * "socket host" name of the client, if that differs from the
+ * advertised name (other than case).  But, this can be used on any
+ * client structure.
+ * @param sptr Client to operate on.
+ * @param showip If non-zero, append [username\@text-ip] to name.
+ * @return Either cli_name(\a sptr) or a static buffer.
+ */
+const char* get_client_name(const struct Client* sptr, int showip)
+{
+  static char nbuf[HOSTLEN * 2 + USERLEN + 5];
+
+  if (!MyConnect(sptr) || !showip)
+    return cli_name(sptr);
+  ircd_snprintf(0, nbuf, sizeof(nbuf), "%s[%s@%s]", cli_name(sptr),
+                IsIdented(sptr) ? cli_username(sptr) : "",
+                cli_sock_ip(sptr));
+  return nbuf;
+}
+
+/**
+ * Exit one client, local or remote. Assuming for local client that
+ * all dependents already have been removed, and socket is closed.
+ * @param bcptr Client being (s)quitted.
+ * @param comment The QUIT comment to send.
+ */
+/* Rewritten by Run - 24 sept 94 */
+static void exit_one_client(struct Client* bcptr, const char* comment)
+{
+  struct SLink *lp;
+  struct Ban *bp;
+
+  if (cli_serv(bcptr) && cli_serv(bcptr)->client_list)  /* Was SetServerYXX called ? */
+    ClearServerYXX(bcptr);      /* Removes server from server_list[] */
+  if (IsUser(bcptr)) {
+    /*
+     * clear out uping requests
+     */
+    if (IsUPing(bcptr))
+      uping_cancel(bcptr, 0);
+    /*
+     * Stop a running /LIST clean
+     */
+    if (MyUser(bcptr) && cli_listing(bcptr)) {
+      MyFree(cli_listing(bcptr));
+      cli_listing(bcptr) = NULL;
+    }
+    /*
+     * If a person is on a channel, send a QUIT notice
+     * to every client (person) on the same channel (so
+     * that the client can show the "**signoff" message).
+     * (Note: The notice is to the local clients *only*)
+     */
+    sendcmdto_common_channels_butone(bcptr, CMD_QUIT, NULL, ":%s", comment);
+
+    remove_user_from_all_channels(bcptr);
+
+    /* Clean up invitefield */
+    while ((lp = cli_user(bcptr)->invited))
+      del_invite(bcptr, lp->value.chptr);
+
+    /* Clean up silencefield */
+    while ((bp = cli_user(bcptr)->silence)) {
+      cli_user(bcptr)->silence = bp->next;
+      free_ban(bp);
+    }
+
+    /* Clean up snotice lists */
+    if (MyUser(bcptr))
+      set_snomask(bcptr, ~0, SNO_DEL);
+
+    if (IsInvisible(bcptr)) {
+      assert(UserStats.inv_clients > 0);
+      --UserStats.inv_clients;
+    }
+    if (IsOper(bcptr)) {
+      assert(UserStats.opers > 0);
+      --UserStats.opers;
+    }
+    if (MyConnect(bcptr))
+      Count_clientdisconnects(bcptr, UserStats);
+    else
+      Count_remoteclientquits(UserStats, bcptr);
+  }
+  else if (IsServer(bcptr))
+  {
+    /* Remove downlink list node of uplink */
+    remove_dlink(&(cli_serv(cli_serv(bcptr)->up))->down, cli_serv(bcptr)->updown);
+    cli_serv(bcptr)->updown = 0;
+
+    if (MyConnect(bcptr))
+      Count_serverdisconnects(UserStats);
+    else
+      Count_remoteserverquits(UserStats);
+  }
+  else if (IsMe(bcptr))
+  {
+    sendto_opmask_butone(0, SNO_OLDSNO, "ERROR: tried to exit me! : %s",
+                        comment);
+    return;                     /* ...must *never* exit self! */
+  }
+  else if (IsUnknown(bcptr) || IsConnecting(bcptr) || IsHandshake(bcptr))
+    Count_unknowndisconnects(UserStats);
+
+  /*
+   * Update IPregistry
+   */
+  if (IsIPChecked(bcptr))
+    IPcheck_disconnect(bcptr);
+
+  /* 
+   * Remove from serv->client_list
+   * NOTE: user is *always* NULL if this is a server
+   */
+  if (cli_user(bcptr)) {
+    assert(!IsServer(bcptr));
+    /* bcptr->user->server->serv->client_list[IndexYXX(bcptr)] = NULL; */
+    RemoveYXXClient(cli_user(bcptr)->server, cli_yxx(bcptr));
+  }
+
+  /* Remove bcptr from the client list */
+#ifdef DEBUGMODE
+  if (hRemClient(bcptr) != 0)
+    Debug((DEBUG_ERROR, "%p !in tab %s[%s] %p %p %p %d %d %p",
+          bcptr, cli_name(bcptr), cli_from(bcptr) ? cli_sockhost(cli_from(bcptr)) : "??host",
+          cli_from(bcptr), cli_next(bcptr), cli_prev(bcptr), cli_fd(bcptr),
+          cli_status(bcptr), cli_user(bcptr)));
+#else
+  hRemClient(bcptr);
+#endif
+  remove_client_from_list(bcptr);
+}
+
+/* exit_downlinks - added by Run 25-9-94 */
+/**
+ * Removes all clients and downlinks (+clients) of any server
+ * QUITs are generated and sent to local users.
+ * @param cptr server that must have all dependents removed
+ * @param sptr source who thought that this was a good idea
+ * @param comment comment sent as sign off message to local clients
+ */
+static void exit_downlinks(struct Client *cptr, struct Client *sptr, char *comment)
+{
+  struct Client *acptr;
+  struct DLink *next;
+  struct DLink *lp;
+  struct Client **acptrp;
+  int i;
+
+  /* Run over all its downlinks */
+  for (lp = cli_serv(cptr)->down; lp; lp = next)
+  {
+    next = lp->next;
+    acptr = lp->value.cptr;
+    /* Remove the downlinks and client of the downlink */
+    exit_downlinks(acptr, sptr, comment);
+    /* Remove the downlink itself */
+    exit_one_client(acptr, cli_name(&me));
+  }
+  /* Remove all clients of this server */
+  acptrp = cli_serv(cptr)->client_list;
+  for (i = 0; i <= cli_serv(cptr)->nn_mask; ++acptrp, ++i) {
+    if (*acptrp)
+      exit_one_client(*acptrp, comment);
+  }
+}
+
+/* exit_client, rewritten 25-9-94 by Run */
+/**
+ * Exits a client of *any* type (user, server, etc)
+ * from this server. Also, this generates all necessary prototol
+ * messages that this exit may cause.
+ *
+ * This function implicitly exits all other clients depending on
+ * this connection.
+ *
+ * For convenience, this function returns a suitable value for
+ * m_function return value:
+ *
+ *   CPTR_KILLED     if (cptr == bcptr)
+ *   0                if (cptr != bcptr)
+ *
+ * This function can be called in two ways:
+ * 1) From before or in parse(), exiting the 'cptr', in which case it was
+ *    invoked as exit_client(cptr, cptr, &me,...), causing it to always
+ *    return CPTR_KILLED.
+ * 2) Via parse from a m_function call, in which case it was invoked as
+ *    exit_client(cptr, acptr, sptr, ...). Here 'sptr' is known; the client
+ *    that generated the message in a way that we can assume he already
+ *    did remove acptr from memory himself (or in other cases we don't mind
+ *    because he will be delinked.) Or invoked as:
+ *    exit_client(cptr, acptr/sptr, &me, ...) when WE decide this one should
+ *    be removed.
+ * In general: No generated SQUIT or QUIT should be sent to source link
+ * sptr->from. And CPTR_KILLED should be returned if cptr got removed (too).
+ *
+ * --Run
+ * @param cptr Connection currently being handled by read_message.
+ * @param victim Client being killed.
+ * @param killer Client that made the decision to remove \a victim.
+ * @param comment Reason for the exit.
+ * @return CPTR_KILLED if cptr == bcptr, else 0.
+ */
+int exit_client(struct Client *cptr,
+    struct Client* victim,
+    struct Client* killer,
+    const char* comment)
+{
+  struct Client* acptr = 0;
+  struct DLink *dlp;
+  time_t on_for;
+
+  char comment1[HOSTLEN + HOSTLEN + 2];
+  assert(killer);
+  if (MyConnect(victim))
+  {
+    SetFlag(victim, FLAG_CLOSING);
+
+    if (feature_bool(FEAT_CONNEXIT_NOTICES) && IsUser(victim))
+      sendto_opmask_butone(0, SNO_CONNEXIT,
+                           "Client exiting: %s (%s@%s) [%s] [%s] <%s%s>",
+                           cli_name(victim), cli_user(victim)->username,
+                           cli_user(victim)->host, comment,
+                           ircd_ntoa(&cli_ip(victim)),
+                           NumNick(victim) /* two %s's */);
+    update_load();
+
+    on_for = CurrentTime - cli_firsttime(victim);
+
+    if (IsUser(victim) || IsUserPort(victim))
+      auth_send_exit(victim);
+
+    if (IsUser(victim))
+      log_write(LS_USER, L_TRACE, 0, "%Tu %i %s@%s %s %s %s%s %s :%s",
+               cli_firsttime(victim), on_for,
+               cli_user(victim)->username, cli_sockhost(victim),
+                ircd_ntoa(&cli_ip(victim)),
+                IsAccount(victim) ? cli_username(victim) : "0",
+                NumNick(victim), /* two %s's */
+                cli_name(victim), cli_info(victim));
+
+    if (victim != cli_from(killer)  /* The source knows already */
+        && IsClient(victim))    /* Not a Ping struct or Log file */
+    {
+      if (IsServer(victim) || IsHandshake(victim))
+       sendcmdto_one(killer, CMD_SQUIT, victim, "%s 0 :%s", cli_name(&me), comment);
+      else if (!IsConnecting(victim)) {
+        if (!IsDead(victim)) {
+         if (IsServer(victim))
+           sendcmdto_one(killer, CMD_ERROR, victim,
+                         ":Closing Link: %s by %s (%s)", cli_name(victim),
+                         cli_name(killer), comment);
+         else
+           sendrawto_one(victim, MSG_ERROR " :Closing Link: %s by %s (%s)",
+                         cli_name(victim),
+                          cli_name(IsServer(killer) ? &his : killer),
+                         comment);
+       }
+      }
+      if ((IsServer(victim) || IsHandshake(victim) || IsConnecting(victim)) &&
+          (killer == &me || (IsServer(killer) &&
+          (strncmp(comment, "Leaf-only link", 14) ||
+          strncmp(comment, "Non-Hub link", 12)))))
+      {
+        /*
+         * Note: check user == user needed to make sure we have the same
+         * client
+         */
+        if (cli_serv(victim)->user && *(cli_serv(victim))->by &&
+            (acptr = findNUser(cli_serv(victim)->by))) {
+          if (cli_user(acptr) == cli_serv(victim)->user) {
+           sendcmdto_one(&me, CMD_NOTICE, acptr,
+                         "%C :Link with %s canceled: %s", acptr,
+                         cli_name(victim), comment);
+          }
+          else {
+            /*
+             * not right client, set by to empty string
+             */
+            acptr = 0;
+            *(cli_serv(victim))->by = '\0';
+          }
+        }
+        if (killer == &me)
+         sendto_opmask_butone(acptr, SNO_OLDSNO, "Link with %s canceled: %s",
+                              cli_name(victim), comment);
+      }
+    }
+    /*
+     *  Close the Client connection first.
+     */
+    close_connection(victim);
+  }
+
+  if (IsServer(victim))
+  {
+    if (feature_bool(FEAT_HIS_NETSPLIT))
+      strcpy(comment1, "*.net *.split");
+    else
+    {
+      strcpy(comment1, cli_name(cli_serv(victim)->up));
+      strcat(comment1, " ");
+      strcat(comment1, cli_name(victim));
+    }
+
+    if (IsUser(killer))
+      sendto_opmask_butone(killer, SNO_OLDSNO, "%s SQUIT by %s [%s]:",
+                          (cli_user(killer)->server == victim ||
+                           cli_user(killer)->server == cli_serv(victim)->up) ?
+                          "Local" : "Remote",
+                          get_client_name(killer, HIDE_IP),
+                          cli_name(cli_user(killer)->server));
+    else if (killer != &me && cli_serv(victim)->up != killer)
+      sendto_opmask_butone(0, SNO_OLDSNO, "Received SQUIT %s from %s :",
+                          cli_name(victim), IsServer(killer) ? cli_name(killer) :
+                          get_client_name(killer, HIDE_IP));
+    sendto_opmask_butone(0, SNO_NETWORK, "Net break: %C %C (%s)",
+                        cli_serv(victim)->up, victim, comment);
+  }
+
+  /*
+   * First generate the needed protocol for the other server links
+   * except the source:
+   */
+  for (dlp = cli_serv(&me)->down; dlp; dlp = dlp->next) {
+    if (dlp->value.cptr != cli_from(killer) && dlp->value.cptr != victim)
+    {
+      if (IsServer(victim))
+       sendcmdto_one(killer, CMD_SQUIT, dlp->value.cptr, "%s %Tu :%s",
+                     cli_name(victim), cli_serv(victim)->timestamp, comment);
+      else if (IsUser(victim) && !HasFlag(victim, FLAG_KILLED))
+       sendcmdto_one(victim, CMD_QUIT, dlp->value.cptr, ":%s", comment);
+    }
+  }
+  /* Then remove the client structures */
+  if (IsServer(victim))
+    exit_downlinks(victim, killer, comment1);
+  exit_one_client(victim, comment);
+
+  /*
+   *  cptr can only have been killed if it was cptr itself that got killed here,
+   *  because cptr can never have been a dependent of victim    --Run
+   */
+  return (cptr == victim) ? CPTR_KILLED : 0;
+}
+
+/**
+ * Exit client with formatted va_list message.
+ * Thin wrapper around exit_client().
+ * @param cptr Connection being processed.
+ * @param bcptr Connection being closed.
+ * @param sptr Connection who asked to close the victim.
+ * @param pattern Format string for message.
+ * @param vl Stdargs argument list.
+ * @return Has a tail call to exit_client().
+ */
+/* added 25-9-94 by Run */
+int vexit_client_msg(struct Client *cptr, struct Client *bcptr, struct Client *sptr,
+    const char *pattern, va_list vl)
+{
+  char msgbuf[1024];
+  ircd_vsnprintf(0, msgbuf, sizeof(msgbuf), pattern, vl);
+  return exit_client(cptr, bcptr, sptr, msgbuf);
+}
+
+/**
+ * Exit client with formatted message using a variable-length argument list.
+ * Thin wrapper around exit_client().
+ * @param cptr Connection being processed.
+ * @param bcptr Connection being closed.
+ * @param sptr Connection who asked to close the victim.
+ * @param pattern Format string for message.
+ * @return Has a tail call to exit_client().
+ */
+int exit_client_msg(struct Client *cptr, struct Client *bcptr,
+    struct Client *sptr, const char *pattern, ...)
+{
+  va_list vl;
+  char msgbuf[1024];
+
+  va_start(vl, pattern);
+  ircd_vsnprintf(0, msgbuf, sizeof(msgbuf), pattern, vl);
+  va_end(vl);
+
+  return exit_client(cptr, bcptr, sptr, msgbuf);
+}
+
+/** Initialize global server statistics. */
+/* (Kind of pointless since C guarantees it's already zero'ed, but... */
+void initstats(void)
+{
+  memset(&ircst, 0, sizeof(ircst));
+}
+
+/** Report server statistics to a client.
+ * @param cptr Client who wants statistics.
+ * @param sd StatDesc structure being looked up (unused).
+ * @param param Extra parameter passed by user (unused).
+ */
+void tstats(struct Client *cptr, const struct StatDesc *sd, char *param)
+{
+  struct Client *acptr;
+  int i;
+  struct ServerStatistics *sp;
+  struct ServerStatistics tmp;
+
+  sp = &tmp;
+  memcpy(sp, ServerStats, sizeof(struct ServerStatistics));
+  for (i = 0; i < MAXCONNECTIONS; i++)
+  {
+    if (!(acptr = LocalClientArray[i]))
+      continue;
+    if (IsServer(acptr))
+    {
+      sp->is_sbs += cli_sendB(acptr);
+      sp->is_sbr += cli_receiveB(acptr);
+      sp->is_sti += CurrentTime - cli_firsttime(acptr);
+      sp->is_sv++;
+    }
+    else if (IsUser(acptr))
+    {
+      sp->is_cbs += cli_sendB(acptr);
+      sp->is_cbr += cli_receiveB(acptr);
+      sp->is_cti += CurrentTime - cli_firsttime(acptr);
+      sp->is_cl++;
+    }
+    else if (IsUnknown(acptr))
+      sp->is_ni++;
+  }
+
+  send_reply(cptr, SND_EXPLICIT | RPL_STATSDEBUG, ":accepts %u refused %u",
+            sp->is_ac, sp->is_ref);
+  send_reply(cptr, SND_EXPLICIT | RPL_STATSDEBUG,
+            ":unknown commands %u prefixes %u", sp->is_unco, sp->is_unpf);
+  send_reply(cptr, SND_EXPLICIT | RPL_STATSDEBUG,
+            ":nick collisions %u unknown closes %u", sp->is_kill, sp->is_ni);
+  send_reply(cptr, SND_EXPLICIT | RPL_STATSDEBUG,
+            ":wrong direction %u empty %u", sp->is_wrdi, sp->is_empt);
+  send_reply(cptr, SND_EXPLICIT | RPL_STATSDEBUG,
+            ":numerics seen %u mode fakes %u", sp->is_num, sp->is_fake);
+  send_reply(cptr, SND_EXPLICIT | RPL_STATSDEBUG,
+            ":auth successes %u fails %u", sp->is_asuc, sp->is_abad);
+  send_reply(cptr, SND_EXPLICIT | RPL_STATSDEBUG, ":local connections %u",
+            sp->is_loc);
+  send_reply(cptr, SND_EXPLICIT | RPL_STATSDEBUG, ":Client server");
+  send_reply(cptr, SND_EXPLICIT | RPL_STATSDEBUG, ":connected %u %u",
+            sp->is_cl, sp->is_sv);
+  send_reply(cptr, SND_EXPLICIT | RPL_STATSDEBUG, ":bytes sent %Lu %Lu",
+            sp->is_cbs, sp->is_sbs);
+  send_reply(cptr, SND_EXPLICIT | RPL_STATSDEBUG, ":bytes recv %Lu %Lu",
+            sp->is_cbr, sp->is_sbr);
+  send_reply(cptr, SND_EXPLICIT | RPL_STATSDEBUG, ":time connected %Lu %Lu",
+            sp->is_cti, sp->is_sti);
+}
diff --git a/ircd/s_numeric.c b/ircd/s_numeric.c
new file mode 100644 (file)
index 0000000..40245ee
--- /dev/null
@@ -0,0 +1,105 @@
+/*
+ * IRC - Internet Relay Chat, ircd/s_numeric.c
+ * Copyright (C) 1990 Jarkko Oikarinen
+ *
+ * Numerous fixes by Markku Savela
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+/** @file
+ * @brief Send a numeric message to a client.
+ * @version $Id: s_numeric.c 1519 2005-10-10 12:18:11Z entrope $
+ */
+#include "config.h"
+
+#include "s_numeric.h"
+#include "channel.h"
+#include "client.h"
+#include "hash.h"
+#include "ircd.h"
+#include "ircd_features.h"
+#include "ircd_snprintf.h"
+#include "numnicks.h"
+#include "send.h"
+#include "struct.h"
+
+
+/*
+ * do_numeric()
+ * Rewritten by Nemesi, Jan 1999, to support numeric nicks in parv[1]
+ *
+ * Called when we get a numeric message from a remote _server_ and we are
+ * supposed to forward it somewhere. Note that we always ignore numerics sent
+ * to 'me' and simply drop the message if we can't handle with this properly:
+ * the savvy approach is NEVER generate an error in response to an... error :)
+ */
+
+/** Forwards a numeric message from a remote server.
+ * @param numeric Value of numeric message.
+ * @param nnn If non-zero, treat parv[1] as a numnick; else as a client name.
+ * @param cptr Client that originated the numeric.
+ * @param sptr Peer that sent us the numeric.
+ * @param parc Count of valid arguments in \a parv.
+ * @param parv Argument list.
+ * @return Zero (always).
+ */
+int do_numeric(int numeric, int nnn, struct Client *cptr, struct Client *sptr,
+    int parc, char *parv[])
+{
+  struct Client *acptr = 0;
+  struct Channel *achptr = 0;
+  char num[4];
+
+  /* Avoid trash, we need it to come from a server and have a target  */
+  if ((parc < 2) || !IsServer(sptr))
+    return 0;
+
+  /* Who should receive this message ? Will we do something with it ?
+     Note that we use findUser functions, so the target can't be neither
+     a server, nor a channel (?) nor a list of targets (?) .. u2.10
+     should never generate numeric replies to non-users anyway
+     Ahem... it can be a channel actually, csc bots use it :\ --Nem */
+
+  if (IsChannelName(parv[1]))
+    achptr = FindChannel(parv[1]);
+  else
+    acptr = (nnn) ? (findNUser(parv[1])) : (FindUser(parv[1]));
+
+  if (((!acptr) || (cli_from(acptr) == cptr)) && !achptr)
+    return 0;
+
+  /* Remap low number numerics, not that I understand WHY.. --Nemesi  */
+  /* numerics below 100 talk about the current 'connection', you're not
+   * connected to a remote server so it doesn't make sense to send them
+   * remotely - but the information they contain may be useful, so we
+   * remap them up.  Weird, but true.  -- Isomer */
+  if (numeric < 100)
+    numeric += 100;
+
+  ircd_snprintf(0, num, sizeof(num), "%03d", numeric);
+
+  /* Since 2.10.10.pl14 we rewrite numerics from remote servers to appear to
+   * come from the local server
+   */
+  if (acptr)
+    sendcmdto_one((feature_bool(FEAT_HIS_REWRITE) && !IsOper(acptr)) ?
+                    &me : sptr,
+                  num, num, acptr, "%C %s", acptr, parv[2]);
+  else
+    sendcmdto_channel_butone(feature_bool(FEAT_HIS_REWRITE) ? &me : sptr,
+                             num, num, achptr, cptr, SKIP_DEAF | SKIP_BURST,
+                             '\0', "%H %s", achptr, parv[2]);
+  return 0;
+}
diff --git a/ircd/s_serv.c b/ircd/s_serv.c
new file mode 100644 (file)
index 0000000..2e736e9
--- /dev/null
@@ -0,0 +1,270 @@
+/*
+ * IRC - Internet Relay Chat, ircd/s_serv.c (formerly ircd/s_msg.c)
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ *                    University of Oulu, Computing Center
+ *
+ * See file AUTHORS in IRC package for additional names of
+ * the programmers.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+/** @file
+ * @brief Miscellaneous server support functions.
+ * @version $Id: s_serv.c 1438 2005-06-28 00:42:06Z entrope $
+ */
+#include "config.h"
+
+#include "s_serv.h"
+#include "IPcheck.h"
+#include "channel.h"
+#include "client.h"
+#include "gline.h"
+#include "hash.h"
+#include "ircd.h"
+#include "ircd_alloc.h"
+#include "ircd_log.h"
+#include "ircd_reply.h"
+#include "ircd_string.h"
+#include "ircd_snprintf.h"
+#include "ircd_crypt.h"
+#include "jupe.h"
+#include "list.h"
+#include "match.h"
+#include "msg.h"
+#include "msgq.h"
+#include "numeric.h"
+#include "numnicks.h"
+#include "parse.h"
+#include "querycmds.h"
+#include "s_bsd.h"
+#include "s_conf.h"
+#include "s_debug.h"
+#include "s_misc.h"
+#include "s_user.h"
+#include "send.h"
+#include "struct.h"
+#include "sys.h"
+#include "userload.h"
+
+/* #include <assert.h> -- Now using assert in ircd_log.h */
+#include <stdlib.h>
+#include <string.h>
+
+/** Maximum connection count since last restart. */
+unsigned int max_connection_count = 0;
+/** Maximum (local) client count since last restart. */
+unsigned int max_client_count = 0;
+
+/** Squit a new (pre-burst) server.
+ * @param cptr Local client that tried to introduce the server.
+ * @param sptr Server to disconnect.
+ * @param host Name of server being disconnected.
+ * @param timestamp Link time of server being disconnected.
+ * @param pattern Format string for squit message.
+ * @return CPTR_KILLED if cptr == sptr, else 0.
+ */
+int exit_new_server(struct Client *cptr, struct Client *sptr, const char *host,
+                    time_t timestamp, const char *pattern, ...)
+{
+  struct VarData vd;
+  int retval = 0;
+
+  vd.vd_format = pattern;
+  va_start(vd.vd_args, pattern);
+
+  if (!IsServer(sptr))
+    retval = vexit_client_msg(cptr, cptr, &me, pattern, vd.vd_args);
+  else
+    sendcmdto_one(&me, CMD_SQUIT, cptr, "%s %Tu :%v", host, timestamp, &vd);
+
+  va_end(vd.vd_args);
+
+  return retval;
+}
+
+/** Indicate whether \a a is between \a b and #me (that is, \a b would
+ * be killed if \a a squits).
+ * @param a A server that may be between us and \a b.
+ * @param b A client that may be on the far side of \a a.
+ * @return Non-zero if \a a is between \a b and #me.
+ */
+int a_kills_b_too(struct Client *a, struct Client *b)
+{
+  for (; b != a && b != &me; b = cli_serv(b)->up);
+  return (a == b ? 1 : 0);
+}
+
+/** Handle a connection that has sent a valid PASS and SERVER.
+ * @param cptr New peer server.
+ * @param aconf Connect block for \a cptr.
+ * @return Zero.
+ */
+int server_estab(struct Client *cptr, struct ConfItem *aconf)
+{
+  struct Client* acptr = 0;
+  const char*    inpath;
+  int            i;
+
+  assert(0 != cptr);
+  assert(0 != cli_local(cptr));
+
+  inpath = cli_name(cptr);
+
+  if (IsUnknown(cptr)) {
+    if (aconf->passwd[0])
+      sendrawto_one(cptr, MSG_PASS " :%s", aconf->passwd);
+    /*
+     *  Pass my info to the new server
+     */
+    sendrawto_one(cptr, MSG_SERVER " %s 1 %Tu %Tu J%s %s%s +%s6 :%s",
+                 cli_name(&me), cli_serv(&me)->timestamp,
+                 cli_serv(cptr)->timestamp, MAJOR_PROTOCOL, NumServCap(&me),
+                 feature_bool(FEAT_HUB) ? "h" : "",
+                 *(cli_info(&me)) ? cli_info(&me) : "IRCers United");
+  }
+
+  det_confs_butmask(cptr, CONF_SERVER | CONF_UWORLD);
+
+  if (!IsHandshake(cptr))
+    hAddClient(cptr);
+  SetServer(cptr);
+  cli_handler(cptr) = SERVER_HANDLER;
+  Count_unknownbecomesserver(UserStats);
+  SetBurst(cptr);
+
+/*    nextping = CurrentTime; */
+
+  /*
+   * NOTE: check for acptr->user == cptr->serv->user is necessary to insure
+   * that we got the same one... bleah
+   */
+  if (cli_serv(cptr)->user && *(cli_serv(cptr))->by &&
+      (acptr = findNUser(cli_serv(cptr)->by))) {
+    if (cli_user(acptr) == cli_serv(cptr)->user) {
+      sendcmdto_one(&me, CMD_NOTICE, acptr, "%C :Link with %s established.",
+                    acptr, inpath);
+    }
+    else {
+      /*
+       * if not the same client, set by to empty string
+       */
+      acptr = 0;
+      *(cli_serv(cptr))->by = '\0';
+    }
+  }
+
+  sendto_opmask_butone(acptr, SNO_OLDSNO, "Link with %s established.", inpath);
+  cli_serv(cptr)->up = &me;
+  cli_serv(cptr)->updown = add_dlink(&(cli_serv(&me))->down, cptr);
+  sendto_opmask_butone(0, SNO_NETWORK, "Net junction: %s %s", cli_name(&me),
+                       cli_name(cptr));
+  SetJunction(cptr);
+  /*
+   * Old sendto_serv_but_one() call removed because we now
+   * need to send different names to different servers
+   * (domain name matching) Send new server to other servers.
+   */
+  for (i = 0; i <= HighestFd; i++)
+  {
+    if (!(acptr = LocalClientArray[i]) || !IsServer(acptr) ||
+        acptr == cptr || IsMe(acptr))
+      continue;
+    if (!match(cli_name(&me), cli_name(cptr)))
+      continue;
+    sendcmdto_one(&me, CMD_SERVER, acptr,
+                 "%s 2 0 %Tu J%02u %s%s +%s%s%s :%s", cli_name(cptr),
+                 cli_serv(cptr)->timestamp, Protocol(cptr), NumServCap(cptr),
+                 IsHub(cptr) ? "h" : "", IsService(cptr) ? "s" : "",
+                 IsIPv6(cptr) ? "6" : "", cli_info(cptr));
+  }
+
+  /* Send these as early as possible so that glined users/juped servers can
+   * be removed from the network while the remote server is still chewing
+   * our burst.
+   */
+  gline_burst(cptr);
+  jupe_burst(cptr);
+
+  /*
+   * Pass on my client information to the new server
+   *
+   * First, pass only servers (idea is that if the link gets
+   * canceled because the server was already there,
+   * there are no NICK's to be canceled...). Of course,
+   * if cancellation occurs, all this info is sent anyway,
+   * and I guess the link dies when a read is attempted...? --msa
+   *
+   * Note: Link cancellation to occur at this point means
+   * that at least two servers from my fragment are building
+   * up connection this other fragment at the same time, it's
+   * a race condition, not the normal way of operation...
+   */
+
+  for (acptr = &me; acptr; acptr = cli_prev(acptr)) {
+    /* acptr->from == acptr for acptr == cptr */
+    if (cli_from(acptr) == cptr)
+      continue;
+    if (IsServer(acptr)) {
+      const char* protocol_str;
+
+      if (Protocol(acptr) > 9)
+        protocol_str = IsBurst(acptr) ? "J" : "P";
+      else
+        protocol_str = IsBurst(acptr) ? "J0" : "P0";
+
+      if (0 == match(cli_name(&me), cli_name(acptr)))
+        continue;
+      sendcmdto_one(cli_serv(acptr)->up, CMD_SERVER, cptr,
+                   "%s %d 0 %Tu %s%u %s%s +%s%s%s :%s", cli_name(acptr),
+                   cli_hopcount(acptr) + 1, cli_serv(acptr)->timestamp,
+                   protocol_str, Protocol(acptr), NumServCap(acptr),
+                   IsHub(acptr) ? "h" : "", IsService(acptr) ? "s" : "",
+                   IsIPv6(acptr) ? "6" : "", cli_info(acptr));
+    }
+  }
+
+  for (acptr = &me; acptr; acptr = cli_prev(acptr))
+  {
+    /* acptr->from == acptr for acptr == cptr */
+    if (cli_from(acptr) == cptr)
+      continue;
+    if (IsUser(acptr))
+    {
+      char xxx_buf[25];
+      char *s = umode_str(acptr);
+      sendcmdto_one(cli_user(acptr)->server, CMD_NICK, cptr,
+                   "%s %d %Tu %s %s %s%s%s%s %s%s :%s",
+                   cli_name(acptr), cli_hopcount(acptr) + 1, cli_lastnick(acptr),
+                   cli_user(acptr)->username, cli_user(acptr)->realhost,
+                   *s ? "+" : "", s, *s ? " " : "",
+                   iptobase64(xxx_buf, &cli_ip(acptr), sizeof(xxx_buf), IsIPv6(cptr)),
+                   NumNick(acptr), cli_info(acptr));
+      if(feature_bool(FEAT_AWAY_BURST) && cli_user(acptr)->away)
+        sendcmdto_one(acptr, CMD_AWAY, cptr, ":%s", cli_user(acptr)->away);
+    }
+  }
+  /*
+   * Last, send the BURST.
+   * (Or for 2.9 servers: pass all channels plus statuses)
+   */
+  {
+    struct Channel *chptr;
+    for (chptr = GlobalChannelList; chptr; chptr = chptr->next)
+      send_channel_modes(cptr, chptr);
+  }
+  sendcmdto_one(&me, CMD_END_OF_BURST, cptr, "");
+  return 0;
+}
+
diff --git a/ircd/s_stats.c b/ircd/s_stats.c
new file mode 100644 (file)
index 0000000..78e0aff
--- /dev/null
@@ -0,0 +1,710 @@
+/*
+ * IRC - Internet Relay Chat, ircd/s_stats.c
+ * Copyright (C) 2000 Joseph Bongaarts
+ *
+ * See file AUTHORS in IRC package for additional names of
+ * the programmers.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#include "config.h"
+
+#include "class.h"
+#include "client.h"
+#include "gline.h"
+#include "hash.h"
+#include "ircd.h"
+#include "ircd_chattr.h"
+#include "ircd_events.h"
+#include "ircd_features.h"
+#include "ircd_crypt.h"
+#include "ircd_log.h"
+#include "ircd_reply.h"
+#include "ircd_string.h"
+#include "listener.h"
+#include "list.h"
+#include "match.h"
+#include "motd.h"
+#include "msg.h"
+#include "msgq.h"
+#include "numeric.h"
+#include "numnicks.h"
+#include "querycmds.h"
+#include "res.h"
+#include "s_auth.h"
+#include "s_bsd.h"
+#include "s_conf.h"
+#include "s_debug.h"
+#include "s_misc.h"
+#include "s_serv.h"
+#include "s_stats.h"
+#include "s_user.h"
+#include "send.h"
+#include "struct.h"
+#include "userload.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/time.h>
+
+/** @file
+ * @brief Report configuration lines and other statistics from this
+ * server.
+ * @version $Id: s_stats.c 1628 2006-03-14 14:56:51Z entrope $
+ *
+ * Note: The info is reported in the order the server uses
+ *       it--not reversed as in ircd.conf!
+ */
+
+/* The statsinfo array should only be used in this file, but just TRY
+ * telling the compiler that you want to forward declare a static
+ * array without specifying a length, and see how it responds.  So we
+ * forward declare it "extern".
+ */
+extern struct StatDesc statsinfo[];
+
+/** Report items from #GlobalConfList.
+ * Uses sd->sd_funcdata as a filter for ConfItem::status.
+ * @param[in] sptr Client requesting statistics.
+ * @param[in] sd Stats descriptor for request.
+ * @param[in] param Extra parameter from user (ignored).
+ */
+static void
+stats_configured_links(struct Client *sptr, const struct StatDesc* sd,
+                       char* param)
+{
+  static char null[] = "<NULL>";
+  struct ConfItem *tmp;
+  unsigned short int port;
+  int maximum;
+  char *host, *pass, *name, *username, *hub_limit;
+
+  for (tmp = GlobalConfList; tmp; tmp = tmp->next)
+  {
+    if ((tmp->status & sd->sd_funcdata))
+    {
+      host = BadPtr(tmp->host) ? null : tmp->host;
+      pass = BadPtr(tmp->passwd) ? null : tmp->passwd;
+      name = BadPtr(tmp->name) ? null : tmp->name;
+      username = BadPtr(tmp->username) ? null : tmp->username;
+      hub_limit = BadPtr(tmp->hub_limit) ? null : tmp->hub_limit;
+      maximum = tmp->maximum;
+      port = tmp->address.port;
+
+      if (tmp->status & CONF_UWORLD)
+       send_reply(sptr, RPL_STATSULINE, host);
+      else if (tmp->status & CONF_SERVER)
+       send_reply(sptr, RPL_STATSCLINE, name, port, maximum, hub_limit, get_conf_class(tmp));
+      else if (tmp->status & CONF_CLIENT)
+        send_reply(sptr, RPL_STATSILINE,
+                   (tmp->username ? tmp->username : ""), (tmp->username ? "@" : ""),
+                   (tmp->host ? tmp->host : "*"), maximum,
+                   (name[0] == ':' ? "0" : ""), (tmp->name ? tmp->name : "*"),
+                   port, get_conf_class(tmp));
+      else if (tmp->status & CONF_OPERATOR)
+        send_reply(sptr, RPL_STATSOLINE,
+                   ((FlagHas(&tmp->privs_dirty, PRIV_PROPAGATE)
+                     && FlagHas(&tmp->privs, PRIV_PROPAGATE))
+                    || (FlagHas(&tmp->conn_class->privs_dirty, PRIV_PROPAGATE)
+                        && FlagHas(&tmp->conn_class->privs, PRIV_PROPAGATE)))
+                   ? 'O' : 'o', username, host, name, get_conf_class(tmp));
+    }
+  }
+}
+
+/** Report connection rules from conf_get_crule_list().
+ * Uses sd->sd_funcdata as a filter for CRuleConf::type.
+ * @param[in] to Client requesting statistics.
+ * @param[in] sd Stats descriptor for request.
+ * @param[in] param Extra parameter from user (ignored).
+ */
+static void
+stats_crule_list(struct Client* to, const struct StatDesc *sd,
+                 char *param)
+{
+  const struct CRuleConf* p = conf_get_crule_list();
+
+  for ( ; p; p = p->next)
+  {
+    if (p->type & sd->sd_funcdata)
+      send_reply(to, RPL_STATSDLINE, (p->type & CRULE_ALL ? 'D' : 'd'), p->hostmask, p->rule);
+  }
+}
+
+/** Report active event engine name.
+ * @param[in] to Client requesting statistics.
+ * @param[in] sd Stats descriptor for request (ignored).
+ * @param[in] param Extra parameter from user (ignored).
+ */
+static void
+stats_engine(struct Client *to, const struct StatDesc *sd, char *param)
+{
+  send_reply(to, RPL_STATSENGINE, engine_name());
+}
+
+/** Report client access lists.
+ * @param[in] to Client requesting statistics.
+ * @param[in] sd Stats descriptor for request.
+ * @param[in] param Filter for hostname or IP (NULL to show all).
+ */
+static void
+stats_access(struct Client *to, const struct StatDesc *sd, char *param)
+{
+  struct ConfItem *aconf;
+  int wilds = 0;
+  int count = 1000;
+
+  if (!param)
+  {
+    stats_configured_links(to, sd, param);
+    return;
+  }
+
+  wilds = string_has_wildcards(param);
+
+  for (aconf = GlobalConfList; aconf; aconf = aconf->next)
+  {
+    if (aconf->status != CONF_CLIENT)
+      continue;
+    if (wilds ? ((aconf->host && !mmatch(aconf->host, param))
+                 || (aconf->name && !mmatch(aconf->name, param)))
+        : ((aconf->host && !match(param, aconf->host))
+           || (aconf->name && !match(param, aconf->name))))
+    {
+      send_reply(to, RPL_STATSILINE,
+                 (aconf->username ? aconf->username : ""), (aconf->username ? "@" : ""), 
+                 (aconf->host ? aconf->host : "*"), aconf->maximum,
+                 (aconf->name && aconf->name[0] == ':' ? "0":""),
+                 aconf->name ? aconf->name : "*",
+                 aconf->address.port, get_conf_class(aconf));
+      if (--count == 0)
+        break;
+    }
+  }
+}
+
+
+/** Report DenyConf entries.
+ * @param[in] to Client requesting list.
+ */
+static void
+report_deny_list(struct Client* to)
+{
+  const struct DenyConf* p = conf_get_deny_list();
+  for ( ; p; p = p->next)
+    send_reply(to, RPL_STATSKLINE, p->bits > 0 ? 'k' : 'K',
+               p->usermask ? p->usermask : "*",
+               p->hostmask ? p->hostmask : "*",
+               p->message ? p->message : "(none)",
+               p->realmask ? p->realmask : "*");
+}
+
+/** Report K/k-lines to a user.
+ * @param[in] sptr Client requesting statistics.
+ * @param[in] sd Stats descriptor for request (ignored).
+ * @param[in] mask Filter for hostmasks to show.
+ */
+static void
+stats_klines(struct Client *sptr, const struct StatDesc *sd, char *mask)
+{
+  int wilds = 0;
+  int count = 3;
+  int limit_query = 0;
+  char *user  = 0;
+  char *host;
+  const struct DenyConf* conf;
+
+  if (!IsAnOper(sptr))
+    limit_query = 1;
+
+  if (!mask)
+  {
+    if (limit_query)
+      need_more_params(sptr, "STATS K");
+    else
+      report_deny_list(sptr);
+    return;
+  }
+
+  if (!limit_query)
+  {
+    wilds = string_has_wildcards(mask);
+    count = 1000;
+  }
+  if ((host = strchr(mask, '@')))
+  {
+    user = mask;
+    *host++ = '\0';
+  }
+  else
+    host = mask;
+
+  for (conf = conf_get_deny_list(); conf; conf = conf->next)
+  {
+    /* Skip this block if the user is searching for a user-matching
+     * mask but the current Kill doesn't have a usermask, or if user
+     * is searching for a host-matching mask but the Kill has no
+     * hostmask, or if the user mask is specified and doesn't match,
+     * or if the host mask is specified and doesn't match.
+     */
+    if ((user && !conf->usermask)
+        || (host && !conf->hostmask)
+        || (user && conf->usermask
+            && (wilds
+                ? mmatch(user, conf->usermask)
+                : match(conf->usermask, user)))
+        || (host && conf->hostmask
+            && (wilds
+                ? mmatch(host, conf->hostmask)
+                : match(conf->hostmask, host))))
+      continue;
+    send_reply(sptr, RPL_STATSKLINE, conf->bits > 0 ? 'k' : 'K',
+               conf->usermask ? conf->usermask : "*",
+               conf->hostmask ? conf->hostmask : "*",
+               conf->message ? conf->message : "(none)",
+               conf->realmask ? conf->realmask : "*");
+    if (--count == 0)
+      return;
+  }
+}
+
+/** Report on servers and/or clients connected to the network.
+ * @param[in] sptr Client requesting statistics.
+ * @param[in] sd Stats descriptor for request (ignored).
+ * @param[in] name Filter for client names to show.
+ */
+static void
+stats_links(struct Client* sptr, const struct StatDesc* sd, char* name)
+{
+  struct Client *acptr;
+  int i;
+  int wilds = 0;
+
+  if (name)
+    wilds = string_has_wildcards(name);
+
+  /*
+   * Send info about connections which match, or all if the
+   * mask matches me.name.  Only restrictions are on those who
+   * are invisible not being visible to 'foreigners' who use
+   * a wild card based search to list it.
+   */
+  send_reply(sptr, SND_EXPLICIT | RPL_STATSLINKINFO, "Connection SendQ "
+             "SendM SendKBytes RcveM RcveKBytes :Open since");
+    for (i = 0; i <= HighestFd; i++)
+    {
+      if (!(acptr = LocalClientArray[i]))
+        continue;
+      /* Don't return clients when this is a request for `all' */
+      if (!name && IsUser(acptr))
+        continue;
+      /* Don't show invisible people to non opers unless they know the nick */
+      if (IsInvisible(acptr) && (!name || wilds) && !IsAnOper(acptr) &&
+          (acptr != sptr))
+        continue;
+      /* Only show the ones that match the given mask - if any */
+      if (name && wilds && match(name, cli_name(acptr)))
+        continue;
+      /* Skip all that do not match the specific query */
+      if (!(!name || wilds) && 0 != ircd_strcmp(name, cli_name(acptr)))
+        continue;
+      send_reply(sptr, SND_EXPLICIT | RPL_STATSLINKINFO,
+                 "%s %u %u %Lu %u %Lu :%Tu",
+                 (*(cli_name(acptr))) ? cli_name(acptr) : "<unregistered>",
+                 (int)MsgQLength(&(cli_sendQ(acptr))), (int)cli_sendM(acptr),
+                 (cli_sendB(acptr) >> 10), (int)cli_receiveM(acptr),
+                 (cli_receiveB(acptr) >> 10), CurrentTime - cli_firsttime(acptr));
+    }
+}
+
+/** Report on loaded modules.
+ * @param[in] to Client requesting statistics.
+ * @param[in] sd Stats descriptor for request (ignored).
+ * @param[in] param Extra parameter from user (ignored).
+ */
+static void
+stats_modules(struct Client* to, const struct StatDesc* sd, char* param)
+{
+crypt_mechs_t* mechs;
+
+  send_reply(to, SND_EXPLICIT | RPL_STATSLLINE, 
+   "Module  Description      Entry Point");
+
+ /* atm the only "modules" we have are the crypto mechanisms,
+    eventualy they'll be part of a global dl module list, for now
+    i'll just output data about them -- hikari */
+
+ if(crypt_mechs_root == NULL)
+  return;
+
+ mechs = crypt_mechs_root->next;
+
+ for(;;)
+ {
+  if(mechs == NULL)
+   return;
+
+  send_reply(to, SND_EXPLICIT | RPL_STATSLLINE, 
+   "%s  %s     0x%X", 
+   mechs->mech->shortname, mechs->mech->description, 
+   mechs->mech->crypt_function);
+
+  mechs = mechs->next;
+ }
+
+}
+
+/** Report how many times each command has been used.
+ * @param[in] to Client requesting statistics.
+ * @param[in] sd Stats descriptor for request (ignored).
+ * @param[in] param Extra parameter from user (ignored).
+ */
+static void
+stats_commands(struct Client* to, const struct StatDesc* sd, char* param)
+{
+  struct Message *mptr;
+
+  for (mptr = msgtab; mptr->cmd; mptr++)
+    if (mptr->count)
+      send_reply(to, RPL_STATSCOMMANDS, mptr->cmd, mptr->count, mptr->bytes);
+}
+
+/** List channel quarantines.
+ * @param[in] to Client requesting statistics.
+ * @param[in] sd Stats descriptor for request (ignored).
+ * @param[in] param Filter for quarantined channel names.
+ */
+static void
+stats_quarantine(struct Client* to, const struct StatDesc* sd, char* param)
+{
+  struct qline *qline;
+
+  for (qline = GlobalQuarantineList; qline; qline = qline->next)
+  {
+    if (param && match(param, qline->chname)) /* narrow search */
+      continue;
+    send_reply(to, RPL_STATSQLINE, qline->chname, qline->reason);
+  }
+}
+
+/** List service pseudo-command mappings.
+ * @param[in] to Client requesting statistics.
+ * @param[in] sd Stats descriptor for request (ignored).
+ * @param[in] param Extra parameter from user (ignored).
+ */
+static void
+stats_mapping(struct Client *to, const struct StatDesc* sd, char* param)
+{
+  struct s_map *map;
+
+  send_reply(to, RPL_STATSRLINE, "Command", "Name", "Prepend", "Target");
+  for (map = GlobalServiceMapList; map; map = map->next) {
+    struct nick_host *nh;
+    for (nh = map->services; nh; nh = nh->next) {
+      send_reply(to, RPL_STATSRLINE, map->command, map->name,
+                 (map->prepend ? map->prepend : "*"), nh->nick);
+    }
+  }
+}
+
+/** Report server uptime and maximum connection/client counts.
+ * @param[in] to Client requesting statistics.
+ * @param[in] sd Stats descriptor for request (ignored).
+ * @param[in] param Extra parameter from user (ignored).
+ */
+static void
+stats_uptime(struct Client* to, const struct StatDesc* sd, char* param)
+{
+  time_t nowr;
+
+  nowr = CurrentTime - cli_since(&me);
+  send_reply(to, RPL_STATSUPTIME, nowr / 86400, (nowr / 3600) % 24,
+             (nowr / 60) % 60, nowr % 60);
+  send_reply(to, RPL_STATSCONN, max_connection_count, max_client_count);
+}
+
+/** Verbosely report on servers connected to the network.
+ * If sd->sd_funcdata != 0, then display in a more human-friendly format.
+ * @param[in] sptr Client requesting statistics.
+ * @param[in] sd Stats descriptor for request.
+ * @param[in] param Filter for server names to display.
+ */
+static void
+stats_servers_verbose(struct Client* sptr, const struct StatDesc* sd,
+                     char* param)
+{
+  struct Client *acptr;
+  const char *fmt;
+
+  /*
+   * lowercase 'v' is for human-readable,
+   * uppercase 'V' is for machine-readable
+   */
+  if (sd->sd_funcdata) {
+    send_reply(sptr, SND_EXPLICIT | RPL_STATSVERBOSE,
+               "%-20s %-20s Flags Hops Numeric   Lag  RTT   Up Down "
+               "Clients/Max Proto %-10s :Info", "Servername", "Uplink",
+               "LinkTS");
+    fmt = "%-20s %-20s %c%c%c%c%c  %4i %s %-4i %5i %4i %4i %4i %5i %5i P%-2i   %Tu :%s";
+  } else {
+    fmt = "%s %s %c%c%c%c%c %i %s %i %i %i %i %i %i %i P%i %Tu :%s";
+  }
+
+  for (acptr = GlobalClientList; acptr; acptr = cli_next(acptr))
+  {
+    if (!IsServer(acptr) && !IsMe(acptr))
+      continue;
+    /* narrow search */
+    if (param && match(param, cli_name(acptr)))
+      continue;
+    send_reply(sptr, SND_EXPLICIT | RPL_STATSVERBOSE, fmt,
+               cli_name(acptr),
+               cli_name(cli_serv(acptr)->up),
+               IsBurst(acptr) ? 'B' : '-',
+               IsBurstAck(acptr) ? 'A' : '-',
+               IsHub(acptr) ? 'H' : '-',
+               IsService(acptr) ? 'S' : '-',
+               IsIPv6(acptr) ? '6' : '-',
+               cli_hopcount(acptr),
+               NumServ(acptr),
+               base64toint(cli_yxx(acptr)),
+               cli_serv(acptr)->lag,
+               cli_serv(acptr)->asll_rtt,
+               cli_serv(acptr)->asll_to,
+               cli_serv(acptr)->asll_from,
+               (acptr == &me ? UserStats.local_clients : cli_serv(acptr)->clients),
+               cli_serv(acptr)->nn_mask,
+               cli_serv(acptr)->prot,
+               cli_serv(acptr)->timestamp,
+               cli_info(acptr));
+  }
+}
+
+/** Display objects allocated (and total memory used by them) for
+ * several types of structures.
+ * @param[in] to Client requesting statistics.
+ * @param[in] sd Stats descriptor for request (ignored).
+ * @param[in] param Extra parameter from user (ignored).
+ */
+static void
+stats_meminfo(struct Client* to, const struct StatDesc* sd, char* param)
+{
+  extern void bans_send_meminfo(struct Client *cptr);
+
+  class_send_meminfo(to);
+  bans_send_meminfo(to);
+  send_listinfo(to, 0);
+}
+
+/** Send a list of available statistics.
+ * @param[in] to Client requesting statistics.
+ * @param[in] sd Stats descriptor for request.
+ * @param[in] param Extra parameter from user (ignored).
+ */
+static void
+stats_help(struct Client* to, const struct StatDesc* sd, char* param)
+{
+  struct StatDesc *asd;
+
+  /* only if it's my user */
+  if (MyUser(to))
+    for (asd = statsinfo; asd->sd_name; asd++)
+      if (asd != sd) /* don't send the help for us */
+        sendcmdto_one(&me, CMD_NOTICE, to, "%C :%c (%s) - %s", to, asd->sd_c,
+                      asd->sd_name, asd->sd_desc);
+}
+
+/** Contains information about all statistics. */
+struct StatDesc statsinfo[] = {
+  { 'a', "nameservers", STAT_FLAG_OPERFEAT|STAT_FLAG_LOCONLY, FEAT_HIS_STATS_a,
+    report_dns_servers, 0,
+    "DNS servers." },
+  { 'c', "connect", STAT_FLAG_OPERFEAT, FEAT_HIS_STATS_c,
+    stats_configured_links, CONF_SERVER,
+    "Remote server connection lines." },
+  { 'd', "maskrules", (STAT_FLAG_OPERFEAT | STAT_FLAG_CASESENS), FEAT_HIS_STATS_d,
+    stats_crule_list, CRULE_MASK,
+    "Dynamic routing configuration." },
+  { 'D', "crules", (STAT_FLAG_OPERFEAT | STAT_FLAG_CASESENS), FEAT_HIS_STATS_d,
+    stats_crule_list, CRULE_ALL,
+    "Dynamic routing configuration." },
+  { 'e', "engine", STAT_FLAG_OPERFEAT, FEAT_HIS_STATS_e,
+    stats_engine, 0,
+    "Report server event loop engine." },
+  { 'f', "features", STAT_FLAG_OPERFEAT, FEAT_HIS_STATS_f,
+    feature_report, 0,
+    "Feature settings." },
+  { 'g', "glines", STAT_FLAG_OPERFEAT, FEAT_HIS_STATS_g,
+    gline_stats, 0,
+    "Global bans (G-lines)." },
+  { 'i', "access", (STAT_FLAG_OPERFEAT | STAT_FLAG_VARPARAM), FEAT_HIS_STATS_i,
+    stats_access, CONF_CLIENT,
+    "Connection authorization lines." },
+  { 'j', "histogram", (STAT_FLAG_OPERFEAT | STAT_FLAG_CASESENS), FEAT_HIS_STATS_j,
+    msgq_histogram, 0,
+    "Message length histogram." },
+  { 'J', "jupes", (STAT_FLAG_OPERFEAT | STAT_FLAG_CASESENS), FEAT_HIS_STATS_J,
+    stats_nickjupes, 0,
+    "Nickname jupes." },
+  { 'k', "klines", (STAT_FLAG_OPERFEAT | STAT_FLAG_VARPARAM), FEAT_HIS_STATS_k,
+    stats_klines, 0,
+    "Local bans (K-Lines)." },
+  { 'l', "links", (STAT_FLAG_OPERFEAT | STAT_FLAG_VARPARAM | STAT_FLAG_CASESENS),
+    FEAT_HIS_STATS_l,
+    stats_links, 0,
+    "Current connections information." },
+  { 'L', "modules", (STAT_FLAG_OPERFEAT | STAT_FLAG_CASESENS),
+    FEAT_HIS_STATS_L,
+    stats_modules, 0,
+    "Dynamically loaded modules." },
+  { 'm', "commands", (STAT_FLAG_OPERFEAT | STAT_FLAG_CASESENS), FEAT_HIS_STATS_m,
+    stats_commands, 0,
+    "Message usage information." },
+  { 'o', "operators", STAT_FLAG_OPERFEAT, FEAT_HIS_STATS_o,
+    stats_configured_links, CONF_OPERATOR,
+    "Operator information." },
+  { 'p', "ports", (STAT_FLAG_OPERFEAT | STAT_FLAG_VARPARAM), FEAT_HIS_STATS_p,
+    show_ports, 0,
+    "Listening ports." },
+  { 'q', "quarantines", (STAT_FLAG_OPERONLY | STAT_FLAG_VARPARAM), FEAT_HIS_STATS_q,
+    stats_quarantine, 0,
+    "Quarantined channels list." },
+  { 'R', "mappings", (STAT_FLAG_OPERFEAT | STAT_FLAG_CASESENS), FEAT_HIS_STATS_R,
+    stats_mapping, 0,
+    "Service mappings." },
+#ifdef DEBUGMODE
+  { 'r', "usage", (STAT_FLAG_OPERFEAT | STAT_FLAG_CASESENS), FEAT_HIS_STATS_r,
+    send_usage, 0,
+    "System resource usage (Debug only)." },
+#endif
+  { 'T', "motds", (STAT_FLAG_OPERFEAT | STAT_FLAG_CASESENS), FEAT_HIS_STATS_T,
+    motd_report, 0,
+    "Configured Message Of The Day files." },
+  { 't', "locals", (STAT_FLAG_OPERFEAT | STAT_FLAG_CASESENS), FEAT_HIS_STATS_t,
+    tstats, 0,
+    "Local connection statistics (Total SND/RCV, etc)." },
+  { 'U', "uworld", (STAT_FLAG_OPERFEAT | STAT_FLAG_CASESENS), FEAT_HIS_STATS_U,
+    stats_configured_links, CONF_UWORLD,
+    "Service server information." },
+  { 'u', "uptime", (STAT_FLAG_OPERFEAT | STAT_FLAG_CASESENS), FEAT_HIS_STATS_u,
+    stats_uptime, 0,
+    "Current uptime & highest connection count." },
+  { 'v', "vservers", (STAT_FLAG_OPERFEAT | STAT_FLAG_VARPARAM | STAT_FLAG_CASESENS), FEAT_HIS_STATS_v,
+    stats_servers_verbose, 1,
+    "Verbose server information." },
+  { 'V', "vserversmach", (STAT_FLAG_OPERFEAT | STAT_FLAG_VARPARAM | STAT_FLAG_CASESENS), FEAT_HIS_STATS_v,
+    stats_servers_verbose, 0,
+    "Verbose server information." },
+  { 'w', "userload", STAT_FLAG_OPERFEAT, FEAT_HIS_STATS_w,
+    calc_load, 0,
+    "Userload statistics." },
+  { 'x', "memusage", STAT_FLAG_OPERFEAT, FEAT_HIS_STATS_x,
+    stats_meminfo, 0,
+    "List usage information." },
+  { 'y', "classes", STAT_FLAG_OPERFEAT, FEAT_HIS_STATS_y,
+    report_classes, 0,
+    "Connection classes." },
+  { 'z', "memory", STAT_FLAG_OPERFEAT, FEAT_HIS_STATS_z,
+    count_memory, 0,
+    "Memory/Structure allocation information." },
+  { ' ', "iauth", STAT_FLAG_OPERFEAT, FEAT_HIS_STATS_IAUTH,
+    report_iauth_stats, 0,
+    "IAuth statistics." },
+  { ' ', "iauthconf", STAT_FLAG_OPERFEAT, FEAT_HIS_STATS_IAUTH,
+    report_iauth_conf, 0,
+    "IAuth configuration." },
+  { '*', "help", STAT_FLAG_CASESENS, FEAT_LAST_F,
+    stats_help, 0,
+    "Send help for stats." },
+  { '\0', 0, FEAT_LAST_F, 0, 0, 0 }
+};
+
+/** Maps from characters to statistics descriptors.
+ * Statistics descriptors with no single-character alias are not included.
+ */
+static struct StatDesc *statsmap[256];
+/** Number of statistics descriptors. */
+static int statscount;
+
+/** Compare two StatDesc structures by long name (StatDesc::sd_name).
+ * @param[in] a_ Pointer to a StatDesc.
+ * @param[in] b_ Pointer to a StatDesc.
+ * @return Less than, equal to, or greater than zero if \a a_ is
+ * lexicographically less than, equal to, or greater than \a b_.
+ */
+static int
+stats_cmp(const void *a_, const void *b_)
+{
+  const struct StatDesc *a = a_;
+  const struct StatDesc *b = b_;
+  return ircd_strcmp(a->sd_name, b->sd_name);
+}
+
+/** Compare a StatDesc's name against a string.
+ * @param[in] key Pointer to a null-terminated string.
+ * @param[in] sd_ Pointer to a StatDesc.
+ * @return Less than, equal to, or greater than zero if \a key is
+ * lexicographically less than, equal to, or greater than \a
+ * sd_->sd_name.
+ */
+static int
+stats_search(const void *key, const void *sd_)
+{
+  const struct StatDesc *sd = sd_;
+  return ircd_strcmp(key, sd->sd_name);
+}
+
+/** Look up a stats handler.  If name_or_char is just one character
+ * long, use that as a character index; otherwise, look it up by name
+ * in #statsinfo.
+ * @param[in] name_or_char Null-terminated string to look up.
+ * @return The statistics descriptor for \a name_or_char (NULL if none).
+ */
+const struct StatDesc *
+stats_find(const char *name_or_char)
+{
+  if (!name_or_char[1])
+    return statsmap[name_or_char[0] - CHAR_MIN];
+  else
+    return bsearch(name_or_char, statsinfo, statscount, sizeof(statsinfo[0]), stats_search);
+}
+
+/** Build statsmap from the statsinfo array. */
+void
+stats_init(void)
+{
+  struct StatDesc *sd;
+
+  /* Count number of stats entries and sort them. */
+  for (statscount = 0, sd = statsinfo; sd->sd_name; sd++, statscount++) {}
+  qsort(statsinfo, statscount, sizeof(statsinfo[0]), stats_cmp);
+
+  /* Build the mapping */
+  for (sd = statsinfo; sd->sd_name; sd++)
+  {
+    if (!sd->sd_c)
+      continue;
+    else if (sd->sd_flags & STAT_FLAG_CASESENS)
+      /* case sensitive character... */
+      statsmap[sd->sd_c - CHAR_MIN] = sd;
+    else
+    {
+      /* case insensitive--make sure to put in two entries */
+      statsmap[ToLower(sd->sd_c) - CHAR_MIN] = sd;
+      statsmap[ToUpper(sd->sd_c) - CHAR_MIN] = sd;
+    }
+  }
+}
diff --git a/ircd/s_user.c b/ircd/s_user.c
new file mode 100644 (file)
index 0000000..87c006d
--- /dev/null
@@ -0,0 +1,1808 @@
+/*
+ * IRC - Internet Relay Chat, ircd/s_user.c (formerly ircd/s_msg.c)
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ *                    University of Oulu, Computing Center
+ *
+ * See file AUTHORS in IRC package for additional names of
+ * the programmers.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+/** @file
+ * @brief Miscellaneous user-related helper functions.
+ * @version $Id: s_user.c 1864 2008-03-15 05:33:22Z entrope $
+ */
+#include "config.h"
+
+#include "s_user.h"
+#include "IPcheck.h"
+#include "channel.h"
+#include "class.h"
+#include "client.h"
+#include "hash.h"
+#include "ircd.h"
+#include "ircd_alloc.h"
+#include "ircd_chattr.h"
+#include "ircd_features.h"
+#include "ircd_log.h"
+#include "ircd_reply.h"
+#include "ircd_snprintf.h"
+#include "ircd_string.h"
+#include "list.h"
+#include "match.h"
+#include "motd.h"
+#include "msg.h"
+#include "msgq.h"
+#include "numeric.h"
+#include "numnicks.h"
+#include "parse.h"
+#include "querycmds.h"
+#include "random.h"
+#include "s_auth.h"
+#include "s_bsd.h"
+#include "s_conf.h"
+#include "s_debug.h"
+#include "s_misc.h"
+#include "s_serv.h" /* max_client_count */
+#include "send.h"
+#include "struct.h"
+#include "supported.h"
+#include "sys.h"
+#include "userload.h"
+#include "version.h"
+#include "whowas.h"
+
+#include "handlers.h" /* m_motd and m_lusers */
+
+/* #include <assert.h> -- Now using assert in ircd_log.h */
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+
+/** Count of allocated User structures. */
+static int userCount = 0;
+
+/** Makes sure that \a cptr has a User information block.
+ * If cli_user(cptr) != NULL, does nothing.
+ * @param[in] cptr Client to attach User struct to.
+ * @return User struct associated with \a cptr.
+ */
+struct User *make_user(struct Client *cptr)
+{
+  assert(0 != cptr);
+
+  if (!cli_user(cptr)) {
+    cli_user(cptr) = (struct User*) MyMalloc(sizeof(struct User));
+    assert(0 != cli_user(cptr));
+
+    /* All variables are 0 by default */
+    memset(cli_user(cptr), 0, sizeof(struct User));
+    ++userCount;
+    cli_user(cptr)->refcnt = 1;
+  }
+  return cli_user(cptr);
+}
+
+/** Dereference \a user.
+ * User structures are reference-counted; if the refcount of \a user
+ * becomes zero, free it.
+ * @param[in] user User to dereference.
+ */
+void free_user(struct User* user)
+{
+  assert(0 != user);
+  assert(0 < user->refcnt);
+
+  if (--user->refcnt == 0) {
+    if (user->away)
+      MyFree(user->away);
+    if (user->lastmsg)
+      MyFree(user->lastmsg);
+    /*
+     * sanity check
+     */
+    assert(0 == user->joined);
+    assert(0 == user->invited);
+    assert(0 == user->channel);
+
+    MyFree(user);
+    assert(userCount>0);
+    --userCount;
+  }
+}
+
+/** Find number of User structs allocated and memory used by them.
+ * @param[out] count_out Receives number of User structs allocated.
+ * @param[out] bytes_out Receives number of bytes used by User structs.
+ */
+void user_count_memory(size_t* count_out, size_t* bytes_out)
+{
+  assert(0 != count_out);
+  assert(0 != bytes_out);
+  *count_out = userCount;
+  *bytes_out = userCount * sizeof(struct User);
+}
+
+
+/** Find the next client (starting at \a next) with a name that matches \a ch.
+ * Normal usage loop is:
+ * for (x = client; x = next_client(x,mask); x = x->next)
+ *     HandleMatchingClient;
+ *
+ * @param[in] next First client to check.
+ * @param[in] ch Name mask to check against.
+ * @return Next matching client found, or NULL if none.
+ */
+struct Client *next_client(struct Client *next, const char* ch)
+{
+  struct Client *tmp = next;
+
+  if (!tmp)
+    return NULL;
+
+  next = FindClient(ch);
+  next = next ? next : tmp;
+  if (cli_prev(tmp) == next)
+    return NULL;
+  if (next != tmp)
+    return next;
+  for (; next; next = cli_next(next))
+    if (!match(ch, cli_name(next)))
+      break;
+  return next;
+}
+
+/** Find the destination server for a command, and forward it if that is not us.
+ *
+ * \a server may be a nickname, server name, server mask (if \a from
+ * is a local user) or server numnick (if \a is a server or remote
+ * user).
+ *
+ * @param[in] from Client that sent the command to us.
+ * @param[in] cmd Long-form command text.
+ * @param[in] tok Token-form command text.
+ * @param[in] one Client that originated the command (ignored).
+ * @param[in] MustBeOper If non-zero and \a from is not an operator, return HUNTED_NOSUCH.
+ * @param[in] pattern Format string of arguments to command.
+ * @param[in] server Index of target name or mask in \a parv.
+ * @param[in] parc Number of valid elements in \a parv (must be less than 9).
+ * @param[in] parv Array of arguments to command.
+ * @return One of HUNTED_ISME, HUNTED_NOSUCH or HUNTED_PASS.
+ */
+int hunt_server_cmd(struct Client *from, const char *cmd, const char *tok,
+                    struct Client *one, int MustBeOper, const char *pattern,
+                    int server, int parc, char *parv[])
+{
+  struct Client *acptr;
+  char *to;
+
+  /* Assume it's me, if no server or an unregistered client */
+  if (parc <= server || EmptyString((to = parv[server])) || IsUnknown(from))
+    return (HUNTED_ISME);
+
+  if (MustBeOper && !IsPrivileged(from))
+  {
+    send_reply(from, ERR_NOPRIVILEGES);
+    return HUNTED_NOSUCH;
+  }
+
+  /* Make sure it's a server */
+  if (MyUser(from)) {
+    /* Make sure it's a server */
+    if (!strchr(to, '*')) {
+      if (0 == (acptr = FindClient(to))) {
+        send_reply(from, ERR_NOSUCHSERVER, to);
+        return HUNTED_NOSUCH;
+      }
+
+      if (cli_user(acptr))
+        acptr = cli_user(acptr)->server;
+    } else if (!(acptr = find_match_server(to))) {
+      send_reply(from, ERR_NOSUCHSERVER, to);
+      return (HUNTED_NOSUCH);
+    }
+  } else if (!(acptr = FindNServer(to))) {
+    send_reply(from, SND_EXPLICIT | ERR_NOSUCHSERVER, "* :Server has disconnected");
+    return (HUNTED_NOSUCH);        /* Server broke off in the meantime */
+  }
+
+  if (IsMe(acptr))
+    return (HUNTED_ISME);
+
+  if (MustBeOper && !IsPrivileged(from)) {
+    send_reply(from, ERR_NOPRIVILEGES);
+    return HUNTED_NOSUCH;
+  }
+
+  /* assert(!IsServer(from)); */
+
+  parv[server] = (char *) acptr; /* HACK! HACK! HACK! ARGH! */
+
+  sendcmdto_one(from, cmd, tok, acptr, pattern, parv[1], parv[2], parv[3],
+                parv[4], parv[5], parv[6], parv[7], parv[8]);
+
+  return (HUNTED_PASS);
+}
+
+/** Find the destination server for a command, and forward it (as a
+ * high-priority command) if that is not us.
+ *
+ * \a server may be a nickname, server name, server mask (if \a from
+ * is a local user) or server numnick (if \a is a server or remote
+ * user).
+ * Unlike hunt_server_cmd(), this appends the message to the
+ * high-priority message queue for the destination server.
+ *
+ * @param[in] from Client that sent the command to us.
+ * @param[in] cmd Long-form command text.
+ * @param[in] tok Token-form command text.
+ * @param[in] one Client that originated the command (ignored).
+ * @param[in] MustBeOper If non-zero and \a from is not an operator, return HUNTED_NOSUCH.
+ * @param[in] pattern Format string of arguments to command.
+ * @param[in] server Index of target name or mask in \a parv.
+ * @param[in] parc Number of valid elements in \a parv (must be less than 9).
+ * @param[in] parv Array of arguments to command.
+ * @return One of HUNTED_ISME, HUNTED_NOSUCH or HUNTED_PASS.
+ */
+int hunt_server_prio_cmd(struct Client *from, const char *cmd, const char *tok,
+                        struct Client *one, int MustBeOper,
+                        const char *pattern, int server, int parc,
+                        char *parv[])
+{
+  struct Client *acptr;
+  char *to;
+
+  /* Assume it's me, if no server or an unregistered client */
+  if (parc <= server || EmptyString((to = parv[server])) || IsUnknown(from))
+    return (HUNTED_ISME);
+
+  /* Make sure it's a server */
+  if (MyUser(from)) {
+    /* Make sure it's a server */
+    if (!strchr(to, '*')) {
+      if (0 == (acptr = FindClient(to))) {
+        send_reply(from, ERR_NOSUCHSERVER, to);
+        return HUNTED_NOSUCH;
+      }
+
+      if (cli_user(acptr))
+        acptr = cli_user(acptr)->server;
+    } else if (!(acptr = find_match_server(to))) {
+      send_reply(from, ERR_NOSUCHSERVER, to);
+      return (HUNTED_NOSUCH);
+    }
+  } else if (!(acptr = FindNServer(to)))
+    return (HUNTED_NOSUCH);        /* Server broke off in the meantime */
+
+  if (IsMe(acptr))
+    return (HUNTED_ISME);
+
+  if (MustBeOper && !IsPrivileged(from)) {
+    send_reply(from, ERR_NOPRIVILEGES);
+    return HUNTED_NOSUCH;
+  }
+
+  /* assert(!IsServer(from)); SETTIME to particular destinations permitted */
+
+  parv[server] = (char *) acptr; /* HACK! HACK! HACK! ARGH! */
+
+  sendcmdto_prio_one(from, cmd, tok, acptr, pattern, parv[1], parv[2], parv[3],
+                    parv[4], parv[5], parv[6], parv[7], parv[8]);
+
+  return (HUNTED_PASS);
+}
+
+/* Helper function for register_user that splits up the parameters of the
+ * default user modes and sets them on the user.
+ */
+static void set_initial_user_modes(struct Client *cptr) {
+  char **umodev;
+  int i, num, l, offset;
+  char *tmpstr = (char*)client_get_default_umode(cptr);
+  char *back;
+
+  if(!tmpstr) return;
+  tmpstr = strdup(tmpstr);
+
+  /* \tmpstr may have multiple parameters and \set_user_mode needs them
+   * to be split up. We just copy the default string and then replace the
+   * spaces with \0 to split the strings up.
+   */
+  num = 0;
+  for(i = 0; tmpstr[i]; ++i) {
+    if(tmpstr[i] == ' ') {
+      tmpstr[i] = 0;
+      ++num;
+    }
+  }
+
+  umodev = MyMalloc((6 + num) * sizeof(char*));
+  memset(umodev, 0, (6 + num) * sizeof(char*));
+
+  back = tmpstr;
+  offset = 0;
+  ++num;
+  for(i = 0; i < num; ++i) {
+    for(l = 0; back[l]; ++l) /* do nothing */;
+    /* Ignore empty parameters. */
+    if(l > 0) umodev[2 + i + offset] = back;
+    else --offset;
+    back = back + l + 1;
+  }
+
+  if(num + offset > 0)
+    set_user_mode(&me, cptr, 2 + num + offset, umodev, ALLOWMODES_WITHSECSERV);
+  MyFree(umodev);
+  MyFree(tmpstr);
+}
+
+/*
+ * register_user
+ *
+ * This function is called when both NICK and USER messages
+ * have been accepted for the client, in whatever order. Only
+ * after this the USER message is propagated.
+ *
+ * NICK's must be propagated at once when received, although
+ * it would be better to delay them too until full info is
+ * available. Doing it is not so simple though, would have
+ * to implement the following:
+ *
+ * 1) user telnets in and gives only "NICK foobar" and waits
+ * 2) another user far away logs in normally with the nick
+ *    "foobar" (quite legal, as this server didn't propagate it).
+ * 3) now this server gets nick "foobar" from outside, but
+ *    has already the same defined locally. Current server
+ *    would just issue "KILL foobar" to clean out dups. But,
+ *    this is not fair. It should actually request another
+ *    nick from local user or kill him/her...
+ */
+/** Finish registering a user who has sent both NICK and USER.
+ * For local connections, possibly check IAuth; make sure there is a
+ * matching Client config block; clean the username field; check
+ * K/k-lines; check for "hacked" looking usernames; assign a numnick;
+ * and send greeting (WELCOME, ISUPPORT, MOTD, etc).
+ * For all connections, update the invisible user and operator counts;
+ * run IPcheck against their address; and forward the NICK.
+ *
+ * @param[in] cptr Client who introduced the user.
+ * @param[in,out] sptr Client who has been fully introduced.
+ * @return Zero or CPTR_KILLED.
+ */
+int register_user(struct Client *cptr, struct Client *sptr)
+{
+  char*            parv[4];
+  char*            tmpstr;
+  struct User*     user = cli_user(sptr);
+  char             ip_base64[25];
+
+  user->last = CurrentTime;
+  parv[0] = cli_name(sptr);
+  parv[1] = parv[2] = NULL;
+
+  if (MyConnect(sptr))
+  {
+    assert(cptr == sptr);
+
+    Count_unknownbecomesclient(sptr, UserStats);
+
+    /*
+     * Set user's initial modes
+     */
+    set_initial_user_modes(sptr);
+
+    SetUser(sptr);
+    if(MyConnect(sptr) && cli_socket(sptr).ssl)
+      SetSSL(sptr);
+
+    cli_handler(sptr) = CLIENT_HANDLER;
+    SetLocalNumNick(sptr);
+    send_reply(sptr,
+               RPL_WELCOME,
+               feature_str(FEAT_NETWORK),
+               feature_str(FEAT_PROVIDER) ? " via " : "",
+               feature_str(FEAT_PROVIDER) ? feature_str(FEAT_PROVIDER) : "",
+               cli_name(sptr));
+    /*
+     * This is a duplicate of the NOTICE but see below...
+     */
+    send_reply(sptr, RPL_YOURHOST, cli_name(&me), version);
+    send_reply(sptr, RPL_CREATED, creation);
+    send_reply(sptr, RPL_MYINFO, cli_name(&me), version, infousermodes,
+               infochanmodes, infochanmodeswithparams);
+    send_supported(sptr);
+
+    if(IsSSL(sptr))
+      sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :You are connected to %s with %s", sptr,
+                    cli_name(&me), ssl_cipherstr(cli_socket(sptr).ssl));
+
+    m_lusers(sptr, sptr, 1, parv);
+    update_load();
+    motd_signon(sptr);
+    if (cli_snomask(sptr) & SNO_NOISY)
+      set_snomask(sptr, cli_snomask(sptr) & SNO_NOISY, SNO_ADD);
+    if (feature_bool(FEAT_CONNEXIT_NOTICES))
+      sendto_opmask_butone(0, SNO_CONNEXIT,
+                           "Client connecting: %s (%s@%s) [%s] {%s} [%s] <%s%s>",
+                           cli_name(sptr), user->username, user->host,
+                           cli_sock_ip(sptr), get_client_class(sptr),
+                           cli_info(sptr), NumNick(cptr) /* two %s's */);
+    IPcheck_connect_succeeded(sptr);
+  }
+  else {
+    struct Client *acptr = user->server;
+
+    if (cli_from(acptr) != cli_from(sptr))
+    {
+      sendcmdto_one(&me, CMD_KILL, cptr, "%C :%s (%s != %s[%s])",
+                    sptr, cli_name(&me), cli_name(user->server), cli_name(cli_from(acptr)),
+                    cli_sockhost(cli_from(acptr)));
+      SetFlag(sptr, FLAG_KILLED);
+      return exit_client(cptr, sptr, &me, "NICK server wrong direction");
+    }
+    else if (HasFlag(acptr, FLAG_TS8))
+      SetFlag(sptr, FLAG_TS8);
+
+    /*
+     * Check to see if this user is being propagated
+     * as part of a net.burst, or is using protocol 9.
+     * FIXME: This can be sped up - its stupid to check it for
+     * every NICK message in a burst again  --Run.
+     */
+    for (; acptr != &me; acptr = cli_serv(acptr)->up)
+    {
+      if (IsBurst(acptr) || Protocol(acptr) < 10)
+        break;
+    }
+    if (!IPcheck_remote_connect(sptr, (acptr != &me)))
+    {
+      /*
+       * We ran out of bits to count this
+       */
+      sendcmdto_one(&me, CMD_KILL, sptr, "%C :%s (Too many connections from your host -- Ghost)",
+                    sptr, cli_name(&me));
+      return exit_client(cptr, sptr, &me,"Too many connections from your host -- throttled");
+    }
+    SetUser(sptr);
+  }
+
+  /* If they get both +x and an account during registration, hide
+   * their hostmask here.  Calling hide_hostmask() from IAuth's
+   * account assignment causes a numeric reply during registration.
+   */
+  if (HasHiddenHost(sptr))
+    hide_hostmask(sptr, FLAG_HIDDENHOST);
+  if (IsInvisible(sptr))
+    ++UserStats.inv_clients;
+  if (IsOper(sptr))
+    ++UserStats.opers;
+  if (MyUser(sptr))
+    client_set_uprivs(sptr, cli_confs(sptr)->value.aconf);
+  if (MyUser(sptr) && HasPriv(sptr, PRIV_SEE_IDLETIME))
+    SetSeeIdletime(sptr);
+
+  tmpstr = umode_str(sptr);
+  /* Send full IP address to IPv6-grokking servers. */
+  sendcmdto_flag_serv_butone(user->server, CMD_NICK, cptr,
+                             FLAG_IPV6, FLAG_LAST_FLAG,
+                             "%s %d %Tu %s %s %s%s%s%s %s%s :%s",
+                             cli_name(sptr), cli_hopcount(sptr) + 1,
+                             cli_lastnick(sptr),
+                             user->username, user->realhost,
+                             *tmpstr ? "+" : "", tmpstr, *tmpstr ? " " : "",
+                             iptobase64(ip_base64, &cli_ip(sptr), sizeof(ip_base64), 1),
+                             NumNick(sptr), cli_info(sptr));
+  /* Send fake IPv6 addresses to pre-IPv6 servers. */
+  sendcmdto_flag_serv_butone(user->server, CMD_NICK, cptr,
+                             FLAG_LAST_FLAG, FLAG_IPV6,
+                             "%s %d %Tu %s %s %s%s%s%s %s%s :%s",
+                             cli_name(sptr), cli_hopcount(sptr) + 1,
+                             cli_lastnick(sptr),
+                             user->username, user->realhost,
+                             *tmpstr ? "+" : "", tmpstr, *tmpstr ? " " : "",
+                             iptobase64(ip_base64, &cli_ip(sptr), sizeof(ip_base64), 0),
+                             NumNick(sptr), cli_info(sptr));
+
+  /* Send user mode to client */
+  if (MyUser(sptr))
+  {
+    static struct Flags flags; /* automatically initialized to zeros */
+    /* To avoid sending +r to the client due to auth-on-connect, set
+     * the "old" FLAG_ACCOUNT bit to match the client's value.
+     */
+    if (IsAccount(cptr))
+      FlagSet(&flags, FLAG_ACCOUNT);
+    else
+      FlagClr(&flags, FLAG_ACCOUNT);
+
+    if(IsOper(sptr)) {
+      send_reply(sptr, RPL_YOUREOPER);
+      FlagSet(&cli_confs(sptr)->value.aconf->conn_class->privs_dirty, PRIV_PROPAGATE);
+      client_set_privs(sptr, cli_confs(sptr)->value.aconf);
+      sendto_opmask_butone(0, SNO_OLDSNO, "%s (%s@%s) is now operator (%c)",
+                           cli_name(sptr), cli_user(sptr)->username, cli_sockhost(sptr),
+                           IsOper(sptr) ? 'O' : 'o');
+      log_write(LS_OPER, L_INFO, 0, "OPER (<OOC>) by (%#C)", sptr);
+      cli_handler(sptr) = OPER_HANDLER;
+    }
+    
+    if(*cli_connclass(sptr)) 
+        sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :Your connection class is: %s", sptr, cli_connclass(sptr));
+    else
+        sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :Your connection class is: %s", sptr, get_client_class(sptr));
+    if(HasPriv(sptr, PRIV_CHAN_LIMIT))
+      sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :You have no channel number limitation.", sptr);
+    else {
+        unsigned int maxchan = cli_confs(sptr)->value.aconf ? ConfMaxChannels(cli_confs(sptr)->value.aconf): feature_int(FEAT_MAXCHANNELSPERUSER);
+        if(sptr -> maxchans > 0) 
+            maxchan = sptr->maxchans;
+      sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :You may join %d channels.", sptr, maxchan);
+    }
+
+    send_umode(cptr, sptr, &flags, ALL_UMODES, 0);
+    if ((cli_snomask(sptr) != SNO_DEFAULT) && HasFlag(sptr, FLAG_SERVNOTICE))
+      send_reply(sptr, RPL_SNOMASK, cli_snomask(sptr), cli_snomask(sptr));
+  }
+  return 0;
+}
+
+/** List of user mode characters. */
+static const struct UserMode {
+  unsigned int flag; /**< User mode constant. */
+  char         c;    /**< Character corresponding to the mode. */
+} userModeList[] = {
+  { FLAG_OPER,        'o' },
+  { FLAG_LOCOP,       'O' },
+  { FLAG_INVISIBLE,   'i' },
+  { FLAG_WALLOP,      'w' },
+  { FLAG_SERVNOTICE,  's' },
+  { FLAG_DEAF,        'd' },
+  { FLAG_CHSERV,      'k' },
+  { FLAG_DEBUG,       'g' },
+  { FLAG_ACCOUNT,     'r' },
+  { FLAG_FAKEHOST,    'f' },
+  { FLAG_NOCHAN,      'n' },
+  { FLAG_NOIDLE,      'I' },
+  { FLAG_XTRAOP,      'X' },
+  { FLAG_NETSERV,     'S' },
+  { FLAG_HIDDENOPER,  'H' },
+  { FLAG_OVERRIDECC,  'c' },
+  { FLAG_WEBIRC,      'W' },
+  { FLAG_SEE_IDLETIME,'t' },
+  { FLAG_SECURITY_SERV,'D' },
+  { FLAG_HIDDENHOST,  'x' }
+};
+
+/** Length of #userModeList. */
+#define USERMODELIST_SIZE sizeof(userModeList) / sizeof(struct UserMode)
+
+/*
+ * XXX - find a way to get rid of this
+ */
+/** Nasty global buffer used for communications with umode_str() and others. */
+static char umodeBuf[BUFSIZE];
+
+/** Try to set a user's nickname.
+ * If \a sptr is a server, the client is being introduced for the first time.
+ * @param[in] cptr Client to set nickname.
+ * @param[in] sptr Client sending the NICK.
+ * @param[in] nick New nickname.
+ * @param[in] parc Number of arguments to NICK.
+ * @param[in] parv Argument list to NICK.
+ * @param[in] force Boolean; forced nickchange
+ * @return CPTR_KILLED if \a cptr was killed, else 0.
+ */
+int set_nick_name(struct Client* cptr, struct Client* sptr,
+                  const char* nick, int parc, char* parv[], unsigned int force)
+{
+  if (IsServer(sptr)) {
+
+    /*
+     * A server introducing a new client, change source
+     */
+    struct Client* new_client = make_client(cptr, STAT_UNKNOWN);
+    assert(0 != new_client);
+
+    cli_hopcount(new_client) = atoi(parv[2]);
+    cli_lastnick(new_client) = atoi(parv[3]);
+
+    /*
+     * Set new nick name.
+     */
+    strcpy(cli_name(new_client), nick);
+    cli_user(new_client) = make_user(new_client);
+    cli_user(new_client)->server = sptr;
+    SetRemoteNumNick(new_client, parv[parc - 2]);
+    /*
+     * IP# of remote client
+     */
+    base64toip(parv[parc - 3], &cli_ip(new_client));
+
+    add_client_to_list(new_client);
+    hAddClient(new_client);
+
+    cli_serv(sptr)->ghost = 0;        /* :server NICK means end of net.burst */
+    ircd_strncpy(cli_username(new_client), parv[4], USERLEN);
+    ircd_strncpy(cli_user(new_client)->username, parv[4], USERLEN);
+    ircd_strncpy(cli_user(new_client)->host, parv[5], HOSTLEN);
+    ircd_strncpy(cli_user(new_client)->realhost, parv[5], HOSTLEN);
+    ircd_strncpy(cli_info(new_client), parv[parc - 1], REALLEN);
+
+    Count_newremoteclient(UserStats, sptr);
+
+    if (parc > 7 && *parv[6] == '+') {
+      /* (parc-4) -3 for the ip, numeric nick, realname */
+      set_user_mode(cptr, new_client, parc-7, parv+4, ALLOWMODES_WITHSECSERV);
+    }
+
+    return register_user(cptr, new_client);
+  }
+  else if ((cli_name(sptr))[0]) {
+    /*
+     * Client changing its nick
+     *
+     * If the client belongs to me, then check to see
+     * if client is on any channels where it is currently
+     * banned.  If so, do not allow the nick change to occur.
+     */
+    if (MyUser(sptr)) {
+      const char* channel_name;
+      struct Membership *member;
+      if (!force && !IsXtraOp(sptr) && (channel_name = find_no_nickchange_channel(sptr))) {
+        return send_reply(cptr, ERR_BANNICKCHANGE, channel_name);
+      }
+      /*
+       * Refuse nick change if the last nick change was less
+       * then 30 seconds ago. This is intended to get rid of
+       * clone bots doing NICK FLOOD. -SeKs
+       * If someone didn't change their nick for more then 60 seconds
+       * however, allow to do two nick changes immediately after another
+       * before limiting the nick flood. -Run
+       */
+      if (!force && (CurrentTime < cli_nextnick(cptr)))
+      {
+        cli_nextnick(cptr) += 2;
+        send_reply(cptr, ERR_NICKTOOFAST, parv[1],
+                   cli_nextnick(cptr) - CurrentTime);
+        /* Send error message */
+        sendcmdto_one(cptr, CMD_NICK, cptr, "%s", cli_name(cptr));
+        /* bounce NICK to user */
+        return 0;                /* ignore nick change! */
+      }
+      else if(!force) {
+        /* Limit total to 1 change per NICK_DELAY seconds: */
+        cli_nextnick(cptr) += NICK_DELAY;
+        /* However allow _maximal_ 1 extra consecutive nick change: */
+        if (cli_nextnick(cptr) < CurrentTime)
+          cli_nextnick(cptr) = CurrentTime;
+      }
+      /* Invalidate all bans against the user so we check them again */
+      for (member = (cli_user(cptr))->channel; member;
+          member = member->next_channel)
+       ClearBanValid(member);
+    }
+    /*
+     * Also set 'lastnick' to current time, if changed.
+     */
+    if (0 != ircd_strcmp(parv[0], nick))
+      cli_lastnick(sptr) = (sptr == cptr) ? TStime() : atoi(parv[2]);
+
+    /*
+     * Client just changing his/her nick. If he/she is
+     * on a channel, send note of change to all clients
+     * on that channel. Propagate notice to other servers.
+     */
+    if (IsUser(sptr)) {
+      sendcmdto_common_channels_butone(sptr, CMD_NICK, NULL, ":%s", nick);
+      add_history(sptr, 1);
+      sendcmdto_serv_butone(sptr, CMD_NICK, cptr, "%s %Tu", nick,
+                            cli_lastnick(sptr));
+    }
+    else
+      sendcmdto_one(sptr, CMD_NICK, sptr, ":%s", nick);
+
+    if ((cli_name(sptr))[0])
+      hRemClient(sptr);
+    strcpy(cli_name(sptr), nick);
+    hAddClient(sptr);
+  }
+  else {
+    /* Local client setting NICK the first time */
+    strcpy(cli_name(sptr), nick);
+    hAddClient(sptr);
+    return auth_set_nick(cli_auth(sptr), nick);
+  }
+  return 0;
+}
+
+/* Refreshs the users host to the current fakehost. If no fakehost
+ * is set, the account-host is created. If no Account is set,
+ * nothing is done.
+ * Returns 1 if the host changed and 0 if not.
+ */
+int apply_fakehost(struct Client *cptr) {
+    char buf[HOSTLEN];
+    if(IsFakeHost(cptr)) {
+        ircd_strncpy(buf, cli_user(cptr)->fakehost, HOSTLEN);
+    }
+    else if (IsAccount(cptr)) {
+        ircd_snprintf(0, buf, HOSTLEN, "%s.%s", cli_user(cptr)->account, feature_str(FEAT_HIDDEN_HOST));
+    }
+    if(strncmp(buf, cli_user(cptr)->host, HOSTLEN) == 0) return 0;
+    ircd_strncpy(cli_user(cptr)->host, buf, HOSTLEN);
+    return 1;
+}
+
+/** Calculate the hash value for a target.
+ * @param[in] target Pointer to target, cast to unsigned int.
+ * @return Hash value constructed from the pointer.
+ */
+static unsigned char hash_target(unsigned int target)
+{
+  return (unsigned char) (target >> 16) ^ (target >> 8);
+}
+
+/** Records \a target as a recent target for \a sptr.
+ * @param[in] sptr User who has sent to a new target.
+ * @param[in] target Target to add.
+ */
+void
+add_target(struct Client *sptr, void *target)
+{
+  /* Ok, this shouldn't work esp on alpha
+  */
+  unsigned char  hash = hash_target((unsigned long) target);
+  unsigned char* targets;
+  int            i;
+  assert(0 != sptr);
+  assert(cli_local(sptr));
+
+  targets = cli_targets(sptr);
+
+  /* 
+   * Already in table?
+   */
+  for (i = 0; i < MAXTARGETS; ++i) {
+    if (targets[i] == hash)
+      return;
+  }
+  /*
+   * New target
+   */
+  memmove(&targets[RESERVEDTARGETS + 1],
+          &targets[RESERVEDTARGETS], MAXTARGETS - RESERVEDTARGETS - 1);
+  targets[RESERVEDTARGETS] = hash;
+}
+
+/** Check whether \a sptr can send to or join \a target yet.
+ * @param[in] sptr User trying to join a channel or send a message.
+ * @param[in] target Target of the join or message.
+ * @param[in] name Name of the target.
+ * @param[in] created If non-zero, trying to join a new channel.
+ * @return Non-zero if too many target changes; zero if okay to send.
+ */
+int check_target_limit(struct Client *sptr, void *target, const char *name,
+    int created)
+{
+  unsigned char hash = hash_target((unsigned long) target);
+  int            i;
+  unsigned char* targets;
+
+  assert(0 != sptr);
+  assert(cli_local(sptr));
+  targets = cli_targets(sptr);
+
+  if(HasPriv(sptr, PRIV_UNLIMITED_TARGET))
+    return 0;
+
+  /*
+   * Same target as last time?
+   */
+  if (targets[0] == hash)
+    return 0;
+  for (i = 1; i < MAXTARGETS; ++i) {
+    if (targets[i] == hash) {
+      memmove(&targets[1], &targets[0], i);
+      targets[0] = hash;
+      return 0;
+    }
+  }
+  /*
+   * New target
+   */
+  if (!created) {
+    if (CurrentTime < cli_nexttarget(sptr)) {
+      /* If user is invited to channel, give him/her a free target */
+      if (IsChannelName(name) && IsInvited(sptr, target))
+        return 0;
+
+      if (cli_nexttarget(sptr) - CurrentTime < TARGET_DELAY + 8) {
+        /*
+         * No server flooding
+         */
+        cli_nexttarget(sptr) += 2;
+        send_reply(sptr, ERR_TARGETTOOFAST, name,
+                   cli_nexttarget(sptr) - CurrentTime);
+      }
+      return 1;
+    }
+    else {
+      cli_nexttarget(sptr) += TARGET_DELAY;
+      if (cli_nexttarget(sptr) < CurrentTime - (TARGET_DELAY * (MAXTARGETS - 1)))
+        cli_nexttarget(sptr) = CurrentTime - (TARGET_DELAY * (MAXTARGETS - 1));
+    }
+  }
+  memmove(&targets[1], &targets[0], MAXTARGETS - 1);
+  targets[0] = hash;
+  return 0;
+}
+
+/** Allows a channel operator to avoid target change checks when
+ * sending messages to users on their channel.
+ * @param[in] source User sending the message.
+ * @param[in] nick Destination of the message.
+ * @param[in] channel Name of channel being sent to.
+ * @param[in] text Message to send.
+ * @param[in] is_notice If non-zero, use CNOTICE instead of CPRIVMSG.
+ */
+/* Added 971023 by Run. */
+int whisper(struct Client* source, const char* nick, const char* channel,
+            const char* text, int is_notice)
+{
+  struct Client*     dest;
+  struct Channel*    chptr;
+  struct Membership* membership;
+
+  assert(0 != source);
+  assert(0 != nick);
+  assert(0 != channel);
+  assert(MyUser(source));
+
+  if (!(dest = FindUser(nick))) {
+    return send_reply(source, ERR_NOSUCHNICK, nick);
+  }
+  if (!(chptr = FindChannel(channel))) {
+    return send_reply(source, ERR_NOSUCHCHANNEL, channel);
+  }
+  /*
+   * compare both users channel lists, instead of the channels user list
+   * since the link is the same, this should be a little faster for channels
+   * with a lot of users
+   */
+  for (membership = cli_user(source)->channel; membership; membership = membership->next_channel) {
+    if (chptr == membership->channel)
+      break;
+  }
+  if (0 == membership) {
+    return send_reply(source, ERR_NOTONCHANNEL, chptr->chname);
+  }
+  if (!IsVoicedOrOpped(membership)) {
+    return send_reply(source, ERR_VOICENEEDED, chptr->chname);
+  }
+  /*
+   * lookup channel in destination
+   */
+  assert(0 != cli_user(dest));
+  for (membership = cli_user(dest)->channel; membership; membership = membership->next_channel) {
+    if (chptr == membership->channel)
+      break;
+  }
+  if (0 == membership || IsZombie(membership)) {
+    return send_reply(source, ERR_USERNOTINCHANNEL, cli_name(dest), chptr->chname);
+  }
+  if (is_silenced(source, dest))
+    return 0;
+          
+  if (is_notice)
+    sendcmdto_one(source, CMD_NOTICE, dest, "%C :%s", dest, text);
+  else
+  {
+    if (cli_user(dest)->away)
+      send_reply(source, RPL_AWAY, cli_name(dest), cli_user(dest)->away);
+    sendcmdto_one(source, CMD_PRIVATE, dest, "%C :%s", dest, text);
+  }
+  return 0;
+}
+
+
+/** Send a user mode change for \a cptr to neighboring servers.
+ * @param[in] cptr User whose mode is changing.
+ * @param[in] sptr Client who sent us the mode change message.
+ * @param[in] old Prior set of user flags.
+ * @param[in] prop If non-zero, also include FLAG_OPER.
+ */
+void send_umode_out(struct Client *cptr, struct Client *sptr,
+                    struct Flags *old, int prop)
+{
+  int i, server = 0, ret;
+  struct Client *acptr;
+
+  if(cptr && (IsServer(cptr) || IsMe(cptr))) server = 1;
+
+  ret = send_umode(NULL, sptr, old, prop ? SEND_UMODES : SEND_UMODES_BUT_OPER, server);
+
+  for (i = HighestFd; i >= 0; i--)
+  {
+    if ((acptr = LocalClientArray[i]) && IsServer(acptr) &&
+        (acptr != cptr) && (acptr != sptr) && *umodeBuf)
+      sendcmdto_one(sptr, CMD_MODE, acptr, ret?"%s %s":"%s :%s", cli_name(sptr), umodeBuf);
+  }
+  if (cptr && MyUser(cptr))
+    send_umode(cptr, sptr, old, ALL_UMODES, 0);
+}
+
+
+/** Call \a fmt for each Client named in \a names.
+ * @param[in] sptr Client requesting information.
+ * @param[in] names Space-delimited list of nicknames.
+ * @param[in] rpl Base reply string for messages.
+ * @param[in] fmt Formatting callback function.
+ */
+void send_user_info(struct Client* sptr, char* names, int rpl, InfoFormatter fmt)
+{
+  char*          name;
+  char*          p = 0;
+  int            arg_count = 0;
+  int            users_found = 0;
+  struct Client* acptr;
+  struct MsgBuf* mb;
+
+  assert(0 != sptr);
+  assert(0 != names);
+  assert(0 != fmt);
+
+  mb = msgq_make(sptr, rpl_str(rpl), cli_name(&me), cli_name(sptr));
+
+  for (name = ircd_strtok(&p, names, " "); name; name = ircd_strtok(&p, 0, " ")) {
+    if ((acptr = FindUser(name))) {
+      if (users_found++)
+       msgq_append(0, mb, " ");
+      (*fmt)(acptr, sptr, mb);
+    }
+    if (5 == ++arg_count)
+      break;
+  }
+  send_buffer(sptr, mb, 0);
+  msgq_clean(mb);
+}
+
+/** Set \a flag on \a cptr and possibly hide the client's hostmask.
+ * @param[in,out] cptr User who is getting a new flag.
+ * @param[in] flag Some flag that affects host-hiding (FLAG_HIDDENHOST, FLAG_ACCOUNT, FLAG_FAKEHOST).
+ * @return Zero.
+ */
+int
+hide_hostmask(struct Client *cptr, unsigned int flag)
+{
+  struct Membership *chan;
+  char buf[HOSTLEN];
+
+  switch (flag) {
+  case FLAG_HIDDENHOST:
+    /* Local users cannot set +x unless FEAT_HOST_HIDING is true. */
+    if (MyConnect(cptr) && !feature_bool(FEAT_HOST_HIDING))
+      return 0;
+    break;
+  case FLAG_ACCOUNT:
+  case FLAG_FAKEHOST:
+    /* Invalidate all bans against the user so we check them again */
+    for (chan = (cli_user(cptr))->channel; chan;
+         chan = chan->next_channel)
+      ClearBanValid(chan);
+    break;
+  default:
+    /* default: no special handling */
+    break;
+  }
+
+  /* Set flags and stop if no fakehost has to be applied. */
+  SetFlag(cptr, flag);
+  if(!HasHiddenHost(cptr))
+    return 0;
+
+  /* Generate new fakehost. */
+  if(IsFakeHost(cptr)) ircd_strncpy(buf, cli_user(cptr)->fakehost, HOSTLEN);
+  else if (IsAccount(cptr)) ircd_snprintf(0, buf, HOSTLEN, "%s.%s", cli_user(cptr)->account, feature_str(FEAT_HIDDEN_HOST));
+  else return 0;
+  if(strncmp(buf, cli_user(cptr)->host, HOSTLEN) == 0) return 0;
+
+  /* Remove all "valid" marks on the bans. This forces them to be
+   * rechecked if the ban is accessed again.
+   */
+  for(chan = (cli_user(cptr))->channel; chan; chan = chan->next_channel) {
+    ClearBanValid(chan);
+  }
+
+  /* Quit user and set the previously generated fakehost. */
+  sendcmdto_common_channels_butone(cptr, CMD_QUIT, cptr, ":Registered");
+  ircd_strncpy(cli_user(cptr)->host, buf, HOSTLEN);
+
+  /* ok, the client is now fully hidden, so let them know -- hikari */
+  if (MyConnect(cptr))
+   send_reply(cptr, RPL_HOSTHIDDEN, cli_user(cptr)->host);
+
+  /*
+   * Go through all channels the client was on, rejoin him
+   * and set the modes, if any
+   */
+  for (chan = cli_user(cptr)->channel; chan; chan = chan->next_channel)
+  {
+    if (IsZombie(chan))
+      continue;
+    /* If the channel has delayed joins, we have to handle the join especially. */
+    if((!(chan->channel->mode.mode & MODE_DELJOINS) && !IsInvisibleJoin(chan)) || IsChanOp(chan) || HasVoice(chan)) {
+        sendcmdto_channel_butserv_butone(cptr, CMD_JOIN, chan->channel, cptr, 0,
+                                         "%H", chan->channel);
+        if(IsChanOp(chan) && HasVoice(chan)) {
+            sendcmdto_channel_butserv_butone(&his, CMD_MODE, chan->channel, cptr, 0,
+                                             "%H +ov %C %C", chan->channel, cptr,
+                                             cptr);
+        }
+        else if(IsChanOp(chan) || HasVoice(chan)) {
+            sendcmdto_channel_butserv_butone(&his, CMD_MODE, chan->channel, cptr, 0,
+                                             "%H +%c %C", chan->channel, IsChanOp(chan) ? 'o' : 'v', cptr);
+        }
+    }
+    else {
+        SetDelayedJoin(chan);
+    }
+  }
+  return 0;
+}
+
+/** Set a user's mode.  This function checks that \a cptr is trying to
+ * set his own mode, prevents local users from setting inappropriate
+ * modes through this function, and applies any other side effects of
+ * a successful mode change.
+ *
+ * @param[in,out] cptr User setting someone's mode.
+ * @param[in] sptr Client who sent the mode change message.
+ * @param[in] parc Number of parameters in \a parv.
+ * @param[in] parv Parameters to MODE.
+ * @param[in] allow_modes ALLOWMODES_ANY for any mode, ALLOWMODES_DEFAULT for 
+ *                        only permitting legitimate default user modes.
+ * @return Zero.
+ */
+int set_user_mode(struct Client *cptr, struct Client *sptr, int parc, 
+               char *parv[], int allow_modes)
+{
+  char** p;
+  char*  m;
+  int what;
+  int i;
+  struct Flags setflags;
+  unsigned int tmpmask = 0;
+  int snomask_given = 0;
+  char buf[BUFSIZE];
+  int prop = 0;
+  int do_host_hiding = 0;
+  char* account = NULL, *fakehost = NULL;
+  struct Membership *chan;
+
+  what = MODE_ADD;
+
+  if (parc < 3)
+  {
+    m = buf;
+    *m++ = '+';
+    for (i = 0; i < USERMODELIST_SIZE; i++)
+    {
+      if (HasFlag(sptr, userModeList[i].flag) &&
+          (userModeList[i].flag != FLAG_ACCOUNT) &&
+          (userModeList[i].flag != FLAG_FAKEHOST))
+        *m++ = userModeList[i].c;
+    }
+    *m = '\0';
+    send_reply(sptr, RPL_UMODEIS, buf);
+    if (HasFlag(sptr, FLAG_SERVNOTICE) && MyConnect(sptr)
+        && cli_snomask(sptr) !=
+        (unsigned int)(IsOper(sptr) ? SNO_OPERDEFAULT : SNO_DEFAULT))
+      send_reply(sptr, RPL_SNOMASK, cli_snomask(sptr), cli_snomask(sptr));
+    return 0;
+  }
+
+  /*
+   * find flags already set for user
+   * why not just copy them?
+   */
+  setflags = cli_flags(sptr);
+
+  if (MyConnect(sptr))
+    tmpmask = cli_snomask(sptr);
+
+  /*
+   * parse mode change string(s)
+   */
+  for (p = &parv[2]; *p && p<&parv[parc]; p++) {       /* p is changed in loop too */
+    for (m = *p; *m; m++) {
+      switch (*m) {
+      case '+':
+        what = MODE_ADD;
+        break;
+      case '-':
+        what = MODE_DEL;
+        break;
+      case 's':
+        if (*(p + 1) && is_snomask(*(p + 1))) {
+          snomask_given = 1;
+          tmpmask = umode_make_snomask(tmpmask, *++p, what);
+          tmpmask &= (IsAnOper(sptr) ? SNO_ALL : SNO_USER);
+        }
+        else
+          tmpmask = (what == MODE_ADD) ?
+              (IsAnOper(sptr) ? SNO_OPERDEFAULT : SNO_DEFAULT) : 0;
+        if (tmpmask)
+         SetServNotice(sptr);
+        else
+         ClearServNotice(sptr);
+        break;
+      case 'w':
+        if (what == MODE_ADD)
+          SetWallops(sptr);
+        else
+          ClearWallops(sptr);
+        break;
+      case 'o':
+        if (what == MODE_ADD)
+          SetOper(sptr);
+        else {
+          ClrFlag(sptr, FLAG_OPER);
+          ClrFlag(sptr, FLAG_LOCOP);
+          if (MyConnect(sptr))
+          {
+            tmpmask = cli_snomask(sptr) & ~SNO_OPER;
+            cli_handler(sptr) = CLIENT_HANDLER;
+          }
+        }
+        break;
+      case 'O':
+        if (what == MODE_ADD)
+          SetLocOp(sptr);
+        else
+        { 
+          ClrFlag(sptr, FLAG_OPER);
+          ClrFlag(sptr, FLAG_LOCOP);
+          if (MyConnect(sptr))
+          {
+            tmpmask = cli_snomask(sptr) & ~SNO_OPER;
+            cli_handler(sptr) = CLIENT_HANDLER;
+          }
+        }
+        break;
+      case 'i':
+        if (what == MODE_ADD)
+          SetInvisible(sptr);
+        else
+          ClearInvisible(sptr);
+        break;
+      case 'd':
+        if (what == MODE_ADD)
+          SetDeaf(sptr);
+        else
+          ClearDeaf(sptr);
+        break;
+      case 'c':
+        if (what == MODE_ADD)
+            SetOverrideCC(sptr);
+        else
+            ClearOverrideCC(sptr);
+        break;
+      case 'k':
+        if (what == MODE_ADD)
+          SetChannelService(sptr);
+        else
+          ClearChannelService(sptr);
+        break;
+      case 'g':
+        if (what == MODE_ADD)
+          SetDebug(sptr);
+        else
+          ClearDebug(sptr);
+        break;
+      case 'x':
+        if(what == MODE_ADD && !FlagHas(&setflags, FLAG_HIDDENHOST) &&
+           (!MyConnect(sptr) || feature_bool(FEAT_HOST_HIDING))) {
+            do_host_hiding = 1;
+            SetHiddenHost(sptr);
+        }
+        break;
+      case 'n':
+        if (what == MODE_ADD)
+          SetNoChan(sptr);
+        else
+          ClearNoChan(sptr);
+        break;
+      case 'I':
+        if (what == MODE_ADD)
+          SetNoIdle(sptr);
+        else
+          ClearNoIdle(sptr);
+        break;
+      case 'X':
+        if (what == MODE_ADD)
+           SetXtraOp(sptr);
+        else
+           ClearXtraOp(sptr);
+        break;
+      case 'S':
+        if (what == MODE_ADD)
+           SetNetServ(sptr);
+        else
+           ClearNetServ(sptr);
+        break;
+      case 'H':
+        if (what == MODE_ADD)
+           SetHiddenOper(sptr);
+        else
+           ClearHiddenOper(sptr);
+        break;
+         case 'D':
+        if (what == MODE_ADD)
+           SetSecurityServ(sptr);
+        else
+           ClearSecurityServ(sptr);
+        break;
+      case 'W':
+        if (what == MODE_ADD)
+          SetWebIRC(sptr);
+        else
+          ClearWebIRC(sptr);
+        break;
+      case 'r':
+        if (*(p + 1) && (what == MODE_ADD)) {
+          account = *(++p);
+          SetAccount(sptr);
+          for(chan = (cli_user(sptr))->channel; chan; chan = chan->next_channel) ClearBanValid(chan);
+          if(HasFlag(sptr, FLAG_HIDDENHOST))
+            do_host_hiding = 1;
+        }
+        /* There is no -r */
+        break;
+      case 'f':
+        if (*(p + 1) && (what == MODE_ADD)) {
+          fakehost = *(++p);
+          SetFakeHost(sptr);
+          for(chan = (cli_user(sptr))->channel; chan; chan = chan->next_channel) ClearBanValid(chan);
+          if(HasFlag(sptr, FLAG_HIDDENHOST))
+            do_host_hiding = 1;
+        }
+        /* There is no -f */
+        break;
+      case 't': /* This can only be set by servers and cannot be removed. */
+       if (what == MODE_ADD)
+         SetSeeIdletime(sptr);
+        break;
+#ifdef OLD_OGN_IRCU_COMPAT
+      case 'z': /* Formerly SSL mode; we ignore it. */
+        break;
+#endif
+      default:
+        send_reply(sptr, ERR_UMODEUNKNOWNFLAG, *m);
+        break;
+      }
+    }
+  }
+  /*
+   * Evaluate rules for new user mode
+   * Stop users making themselves operators too easily:
+   */
+  if (!IsServer(cptr) && !IsMe(cptr))
+  {
+    if (!FlagHas(&setflags, FLAG_OPER) && IsOper(sptr))
+      ClearOper(sptr);
+    if (!FlagHas(&setflags, FLAG_LOCOP) && IsLocOp(sptr))
+      ClearLocOp(sptr);
+    if (!FlagHas(&setflags, FLAG_ACCOUNT) && IsAccount(sptr))
+      ClrFlag(sptr, FLAG_ACCOUNT);
+    if (!FlagHas(&setflags, FLAG_FAKEHOST) && IsFakeHost(sptr))
+      ClrFlag(sptr, FLAG_FAKEHOST);
+    if (!FlagHas(&setflags, FLAG_SEE_IDLETIME) && IsSeeIdletime(sptr))
+      ClrFlag(sptr, FLAG_SEE_IDLETIME);
+    /*
+     * new umode; servers and privileged opers can set it, local users cannot;
+     * prevents users from /kick'ing or /mode -o'ing
+     */
+    if (!FlagHas(&setflags, FLAG_CHSERV) && IsChannelService(sptr) && !HasPriv(sptr, PRIV_UMODE_CHSERV))
+      ClearChannelService(sptr);
+    if (!FlagHas(&setflags, FLAG_NOCHAN) && IsNoChan(sptr) && !HasPriv(sptr, PRIV_UMODE_NOCHAN))
+      ClearNoChan(sptr);
+    if (!FlagHas(&setflags, FLAG_NOIDLE) && IsNoIdle(sptr) && !HasPriv(sptr, PRIV_UMODE_NOIDLE))
+      ClearNoIdle(sptr);
+    if (!FlagHas(&setflags, FLAG_XTRAOP) && IsXtraOp(sptr) && (!IsOper(sptr) || !HasPriv(sptr, PRIV_UMODE_XTRAOP)))
+      ClearXtraOp(sptr);
+    if (!FlagHas(&setflags, FLAG_NETSERV) && IsNetServ(sptr) && (!HasPriv(sptr, PRIV_UMODE_NETSERV) || !HasFlag(sptr, FLAG_SECURITY_SERV)))
+      ClearNetServ(sptr);
+    if (!FlagHas(&setflags, FLAG_HIDDENOPER) && IsHiddenOper(sptr) && !IsOper(sptr))
+      ClearHiddenOper(sptr);
+    if (!FlagHas(&setflags, FLAG_OVERRIDECC) && IsOverrideCC(sptr) && !HasPriv(sptr, PRIV_UMODE_OVERRIDECC))
+      ClearOverrideCC(sptr);
+    /* Opers are able to fake the webirc usermode only if FEAT_FAKE_WEBIRC is true. */
+    if (!FlagHas(&setflags, FLAG_WEBIRC) && IsWebIRC(sptr) && !(feature_bool(FEAT_FAKE_WEBIRC) && IsOper(sptr)))
+      ClearWebIRC(sptr);
+    /*
+     * only send wallops to opers
+     */
+    if (feature_bool(FEAT_WALLOPS_OPER_ONLY) && !IsAnOper(sptr) &&
+       !FlagHas(&setflags, FLAG_WALLOP))
+      ClearWallops(sptr);
+    if (feature_bool(FEAT_HIS_SNOTICES_OPER_ONLY) && MyConnect(sptr) &&
+        !IsAnOper(sptr) && !FlagHas(&setflags, FLAG_SERVNOTICE))
+    {
+      ClearServNotice(sptr);
+      set_snomask(sptr, 0, SNO_SET);
+    }
+    if (feature_bool(FEAT_HIS_DEBUG_OPER_ONLY) &&
+        !IsAnOper(sptr) && !FlagHas(&setflags, FLAG_DEBUG))
+      ClearDebug(sptr);
+  }
+  if (allow_modes != ALLOWMODES_WITHSECSERV) {
+    if (!FlagHas(&setflags, FLAG_SECURITY_SERV) && IsSecurityServ(sptr)) {
+      ClearSecurityServ(sptr);
+         sendto_opmask_butone(0, SNO_OLDSNO, "Someone tried to set mode +D to %s - Access denied",cli_name(sptr));
+         }
+  }
+  if (MyConnect(sptr))
+  {
+    if ((FlagHas(&setflags, FLAG_OPER) || FlagHas(&setflags, FLAG_LOCOP)) &&
+        !IsAnOper(sptr))
+      det_confs_butmask(sptr, CONF_CLIENT & ~CONF_OPERATOR);
+
+    if (SendServNotice(sptr))
+    {
+      if (tmpmask != cli_snomask(sptr))
+       set_snomask(sptr, tmpmask, SNO_SET);
+      if (cli_snomask(sptr) && snomask_given)
+       send_reply(sptr, RPL_SNOMASK, cli_snomask(sptr), cli_snomask(sptr));
+    }
+    else
+      set_snomask(sptr, 0, SNO_SET);
+  }
+  /*
+   * Compare new flags with old flags and send string which
+   * will cause servers to update correctly.
+   */
+  if (!FlagHas(&setflags, FLAG_ACCOUNT) && IsAccount(sptr)) {
+      int len = ACCOUNTLEN;
+      char *ts;
+      if ((ts = strchr(account, ':'))) {
+       len = (ts++) - account;
+       cli_user(sptr)->acc_create = atoi(ts);
+       Debug((DEBUG_DEBUG, "Received timestamped account in user mode; "
+             "account \"%s\", timestamp %Tu", account,
+             cli_user(sptr)->acc_create));
+      }
+      ircd_strncpy(cli_user(sptr)->account, account, len);
+  }
+  if (!FlagHas(&setflags, FLAG_FAKEHOST) && IsFakeHost(sptr)) {
+    ircd_strncpy(cli_user(sptr)->fakehost, fakehost, HOSTLEN);
+  }
+
+  if (IsRegistered(sptr)) {
+    if(do_host_hiding)
+      hide_hostmask(sptr, 0);
+
+    if (!FlagHas(&setflags, FLAG_OPER) && IsOper(sptr)) {
+      /* user now oper */
+      ++UserStats.opers;
+      client_set_privs(sptr, NULL); /* may set propagate privilege */
+      prop = 1;
+      if(MyConnect(sptr)) {
+        sendto_opmask_butone(0, SNO_OLDSNO, "%s (%s@%s) is now operator (%c)",
+                             cli_name(sptr), cli_user(sptr)->username,
+                             cli_sockhost(sptr), IsOper(sptr) ? 'O' : 'o');
+        log_write(LS_OPER, L_INFO, 0, "OPER (<OOM>) by (%#C)", sptr);
+        cli_handler(sptr) = OPER_HANDLER;
+        send_reply(sptr, RPL_YOUREOPER);
+      }
+    }
+    if (FlagHas(&setflags, FLAG_OPER) && !IsOper(sptr)) {
+      prop = 1;
+    }
+    /* remember propagate privilege setting */
+    if (HasPriv(sptr, PRIV_PROPAGATE)) {
+      prop = 1;
+    }
+    if (FlagHas(&setflags, FLAG_OPER) && !IsOper(sptr)) {
+      /* user no longer oper */
+      assert(UserStats.opers > 0);
+      --UserStats.opers;
+      client_set_privs(sptr, NULL); /* will clear propagate privilege */
+      client_set_uprivs(sptr, cli_confs(sptr)->value.aconf);
+    }
+    if (FlagHas(&setflags, FLAG_INVISIBLE) && !IsInvisible(sptr)) {
+      assert(UserStats.inv_clients > 0);
+      --UserStats.inv_clients;
+    }
+    if (!FlagHas(&setflags, FLAG_INVISIBLE) && IsInvisible(sptr)) {
+      ++UserStats.inv_clients;
+    }
+    assert(UserStats.opers <= UserStats.clients + UserStats.unknowns);
+    assert(UserStats.inv_clients <= UserStats.clients + UserStats.unknowns);
+    send_umode_out(cptr, sptr, &setflags, prop);
+  }
+
+  return 0;
+}
+
+/** Build a mode string to describe modes for \a cptr.
+ * @param[in] cptr Some user.
+ * @return Pointer to a static buffer.
+ */
+char *umode_str(struct Client *cptr)
+{
+  /* Maximum string size: "owidgrx\0" */
+  char *m = umodeBuf;
+  int i;
+  struct Flags c_flags = cli_flags(cptr);
+
+  if (!HasPriv(cptr, PRIV_PROPAGATE))
+    FlagClr(&c_flags, FLAG_OPER);
+
+  for (i = 0; i < USERMODELIST_SIZE; ++i)
+  {
+    if (FlagHas(&c_flags, userModeList[i].flag) &&
+        userModeList[i].flag >= FLAG_GLOBAL_UMODES)
+      *m++ = userModeList[i].c;
+  }
+
+  /* Append the arguments for the flags. They have to be appended
+   * in the right order. See the order of userModeList[].
+   */
+
+  if (IsAccount(cptr)) {
+    char* t = cli_user(cptr)->account;
+
+    *m++ = ' ';
+    while ((*m++ = *t++))
+      ; /* Empty loop */
+
+    /* If timestamped, append the timestamp directly to the accountname
+     * separated with a colon
+     */
+    if (cli_user(cptr)->acc_create) {
+      char nbuf[20];
+      Debug((DEBUG_DEBUG, "Sending timestamped account in user mode for "
+            "account \"%s\"; timestamp %Tu", cli_user(cptr)->account,
+            cli_user(cptr)->acc_create));
+      ircd_snprintf(0, t = nbuf, sizeof(nbuf), ":%Tu",
+                    cli_user(cptr)->acc_create);
+      m--; /* back up over previous nul-termination */
+      while ((*m++ = *t++))
+        ; /* Empty loop */
+    }
+
+    --m; /* back up over previous nul-termination */
+  }
+
+  if(IsFakeHost(cptr)) {
+        char* t = cli_user(cptr)->fakehost;
+        *m++ = ' ';
+        while((*m++ = *t++)) ; /* Empty loop */
+        --m; /* back up over previous nul-termination */
+  }
+
+  *m = '\0';
+
+  return umodeBuf;                /* Note: static buffer, gets
+                                   overwritten by send_umode() */
+}
+
+/** Send a mode change string for \a sptr to \a cptr.
+ * @param[in] cptr Destination of mode change message.
+ * @param[in] sptr User whose mode has changed.
+ * @param[in] old Pre-change set of modes for \a sptr.
+ * @param[in] sendset One of ALL_UMODES, SEND_UMODES_BUT_OPER,
+ * @param[in] serv_modes Set to 1 if you want to send ACCOUNT and FAKEHOST with this command.
+ * @return 1 if ":" is already used in the buffer, 0 otherwise. Always 0 if \a serv_modes is 0.
+ * SEND_UMODES, to select which changed user modes to send.
+ */
+int send_umode(struct Client *cptr, struct Client *sptr, struct Flags *old,
+                int sendset, int serv_modes)
+{
+  int i, ret = 0;
+  int flag;
+  char *m;
+  int what = MODE_NULL;
+  int add_fakehost = 0, add_account = 0;
+
+  /*
+   * Build a string in umodeBuf to represent the change in the user's
+   * mode between the new (cli_flags(sptr)) and 'old', but skipping
+   * the modes indicated by sendset.
+   */
+  m = umodeBuf;
+  *m = '\0';
+  for (i = 0; i < USERMODELIST_SIZE; ++i)
+  {
+    flag = userModeList[i].flag;
+    if (FlagHas(old, flag)
+        == HasFlag(sptr, flag))
+      continue;
+
+    /* Account is not shown to the user as umode. */
+    if(flag == FLAG_ACCOUNT) {
+      if(!serv_modes || FlagHas(old, flag)) continue;
+      add_account = 1;
+    }
+
+    if(flag == FLAG_FAKEHOST) {
+      /* Removing a fakehost is not possible. Ignore it. */
+      if(!serv_modes || FlagHas(old, flag)) continue;
+      add_fakehost = 1;
+    }
+
+    switch (sendset)
+    {
+    case ALL_UMODES:
+      break;
+    case SEND_UMODES_BUT_OPER:
+      if (flag == FLAG_OPER)
+        continue;
+      /* and fall through */
+    case SEND_UMODES:
+      if (flag < FLAG_GLOBAL_UMODES)
+        continue;
+      break;      
+    }
+    if (FlagHas(old, flag))
+    {
+      if (what == MODE_DEL)
+        *m++ = userModeList[i].c;
+      else
+      {
+        what = MODE_DEL;
+        *m++ = '-';
+        *m++ = userModeList[i].c;
+      }
+    }
+    else /* !FlagHas(old, flag) */
+    {
+      if (what == MODE_ADD)
+        *m++ = userModeList[i].c;
+      else
+      {
+        what = MODE_ADD;
+        *m++ = '+';
+        *m++ = userModeList[i].c;
+      }
+    }
+  }
+
+  if(add_account) {
+    char* t = cli_user(sptr)->account;
+
+    *m++ = ' ';
+    if(!add_fakehost) {
+      *m++ = ':';
+      ret = 1;
+    }
+    while ((*m++ = *t++)) /* Empty loop */ ;
+    if(cli_user(sptr)->acc_create) {
+      char nbuf[20];
+      ircd_snprintf(0, t = nbuf, sizeof(nbuf), ":%Tu", cli_user(sptr)->acc_create);
+      m--; /* back up over previous nul-termination */
+      while ((*m++ = *t++)) /* Empty loop */ ;
+    }
+    --m; /* back up over previous nul-termination */
+  }
+
+  if(add_fakehost) {
+    char* t = cli_user(sptr)->fakehost;
+
+    *m++ = ' ';
+    *m++ = ':';
+    ret = 1;
+    while((*m++ = *t++)) ; /* Empty loop */
+    --m; /* back up over previous nul-termination */
+  }
+
+  *m = '\0';
+  if (*umodeBuf && cptr)
+    sendcmdto_one(sptr, CMD_MODE, cptr, ret?"%s %s":"%s :%s", cli_name(sptr), umodeBuf);
+  return ret;
+}
+
+/**
+ * Check to see if this resembles a sno_mask.  It is if 1) there is
+ * at least one digit and 2) The first digit occurs before the first
+ * alphabetic character.
+ * @param[in] word Word to check for sno_mask-ness.
+ * @return Non-zero if \a word looks like a server notice mask; zero if not.
+ */
+int is_snomask(char *word)
+{
+  if (word)
+  {
+    for (; *word; word++)
+      if (IsDigit(*word))
+        return 1;
+      else if (IsAlpha(*word))
+        return 0;
+  }
+  return 0;
+}
+
+/** Update snomask \a oldmask according to \a arg and \a what.
+ * @param[in] oldmask Original user mask.
+ * @param[in] arg Update string (either a number or '+'/'-' followed by a number).
+ * @param[in] what MODE_ADD if adding the mask.
+ * @return New value of service notice mask.
+ */
+unsigned int umode_make_snomask(unsigned int oldmask, char *arg, int what)
+{
+  unsigned int sno_what;
+  unsigned int newmask;
+  if (*arg == '+')
+  {
+    arg++;
+    if (what == MODE_ADD)
+      sno_what = SNO_ADD;
+    else
+      sno_what = SNO_DEL;
+  }
+  else if (*arg == '-')
+  {
+    arg++;
+    if (what == MODE_ADD)
+      sno_what = SNO_DEL;
+    else
+      sno_what = SNO_ADD;
+  }
+  else
+    sno_what = (what == MODE_ADD) ? SNO_SET : SNO_DEL;
+  /* pity we don't have strtoul everywhere */
+  newmask = (unsigned int)atoi(arg);
+  if (sno_what == SNO_DEL)
+    newmask = oldmask & ~newmask;
+  else if (sno_what == SNO_ADD)
+    newmask |= oldmask;
+  return newmask;
+}
+
+/** Remove \a cptr from the singly linked list \a list.
+ * @param[in] cptr Client to remove from list.
+ * @param[in,out] list Pointer to head of list containing \a cptr.
+ */
+static void delfrom_list(struct Client *cptr, struct SLink **list)
+{
+  struct SLink* tmp;
+  struct SLink* prv = NULL;
+
+  for (tmp = *list; tmp; tmp = tmp->next) {
+    if (tmp->value.cptr == cptr) {
+      if (prv)
+        prv->next = tmp->next;
+      else
+        *list = tmp->next;
+      free_link(tmp);
+      break;
+    }
+    prv = tmp;
+  }
+}
+
+/** Set \a cptr's server notice mask, according to \a what.
+ * @param[in,out] cptr Client whose snomask is updating.
+ * @param[in] newmask Base value for new snomask.
+ * @param[in] what One of SNO_ADD, SNO_DEL, SNO_SET, to choose operation.
+ */
+void set_snomask(struct Client *cptr, unsigned int newmask, int what)
+{
+  unsigned int oldmask, diffmask;        /* unsigned please */
+  int i;
+  struct SLink *tmp;
+
+  oldmask = cli_snomask(cptr);
+
+  if (what == SNO_ADD)
+    newmask |= oldmask;
+  else if (what == SNO_DEL)
+    newmask = oldmask & ~newmask;
+  else if (what != SNO_SET)        /* absolute set, no math needed */
+    sendto_opmask_butone(0, SNO_OLDSNO, "setsnomask called with %d ?!", what);
+
+  newmask &= (IsAnOper(cptr) ? SNO_ALL : SNO_USER);
+
+  diffmask = oldmask ^ newmask;
+
+  for (i = 0; diffmask >> i; i++) {
+    if (((diffmask >> i) & 1))
+    {
+      if (((newmask >> i) & 1))
+      {
+        tmp = make_link();
+        tmp->next = opsarray[i];
+        tmp->value.cptr = cptr;
+        opsarray[i] = tmp;
+      }
+      else
+        /* not real portable :( */
+        delfrom_list(cptr, &opsarray[i]);
+    }
+  }
+  cli_snomask(cptr) = newmask;
+}
+
+/** Check whether \a sptr is allowed to send a message to \a acptr.
+ * If \a sptr is a remote user, it means some server has an outdated
+ * SILENCE list for \a acptr, so send the missing SILENCE mask(s) back
+ * in the direction of \a sptr.  Skip the check if \a sptr is a server.
+ * @param[in] sptr Client trying to send a message.
+ * @param[in] acptr Destination of message.
+ * @return Non-zero if \a sptr is SILENCEd by \a acptr, zero if not.
+ */
+int is_silenced(struct Client *sptr, struct Client *acptr)
+{
+  struct Ban *found;
+  struct User *user;
+  size_t buf_used, slen;
+  char buf[BUFSIZE];
+
+  if (IsServer(sptr) || !(user = cli_user(acptr))
+      || !(found = find_ban(sptr, user->silence)))
+    return 0;
+  assert(!(found->flags & BAN_EXCEPTION));
+  if (!MyConnect(sptr)) {
+    /* Buffer positive silence to send back. */
+    buf_used = strlen(found->banstr);
+    memcpy(buf, found->banstr, buf_used);
+    /* Add exceptions to buffer. */
+    for (found = user->silence; found; found = found->next) {
+      if (!(found->flags & BAN_EXCEPTION))
+        continue;
+      slen = strlen(found->banstr);
+      if (buf_used + slen + 4 > 400) {
+        buf[buf_used] = '\0';
+        sendcmdto_one(acptr, CMD_SILENCE, cli_from(sptr), "%C %s", sptr, buf);
+        buf_used = 0;
+      }
+      if (buf_used)
+        buf[buf_used++] = ',';
+      buf[buf_used++] = '+';
+      buf[buf_used++] = '~';
+      memcpy(buf + buf_used, found->banstr, slen);
+      buf_used += slen;
+    }
+    /* Flush silence buffer. */
+    if (buf_used) {
+      buf[buf_used] = '\0';
+      sendcmdto_one(acptr, CMD_SILENCE, cli_from(sptr), "%C %s", sptr, buf);
+      buf_used = 0;
+    }
+  }
+  return 1;
+}
+
+/** Send RPL_ISUPPORT lines to \a cptr.
+ * @param[in] cptr Client to send ISUPPORT to.
+ * @return Zero.
+ */
+int
+send_supported(struct Client *cptr)
+{
+  char featurebuf[512];
+
+  ircd_snprintf(0, featurebuf, sizeof(featurebuf), FEATURES1, FEATURESVALUES1);
+  send_reply(cptr, RPL_ISUPPORT, featurebuf);
+  ircd_snprintf(0, featurebuf, sizeof(featurebuf), FEATURES2, FEATURESVALUES2);
+  send_reply(cptr, RPL_ISUPPORT, featurebuf);
+
+  return 0; /* convenience return, if it's ever needed */
+}
+
+/* vim: shiftwidth=2 
+ */ 
diff --git a/ircd/send.c b/ircd/send.c
new file mode 100644 (file)
index 0000000..9be6651
--- /dev/null
@@ -0,0 +1,872 @@
+/*
+ * IRC - Internet Relay Chat, common/send.c
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ *                    University of Oulu, Computing Center
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+/** @file
+ * @brief Send messages to certain targets.
+ * @version $Id: send.c 1835 2007-10-30 01:14:50Z entrope $
+ */
+#include "config.h"
+
+#include "send.h"
+#include "channel.h"
+#include "class.h"
+#include "client.h"
+#include "ircd.h"
+#include "ircd_features.h"
+#include "ircd_log.h"
+#include "ircd_snprintf.h"
+#include "ircd_string.h"
+#include "list.h"
+#include "match.h"
+#include "msg.h"
+#include "hash.h"
+#include "numnicks.h"
+#include "parse.h"
+#include "s_bsd.h"
+#include "s_debug.h"
+#include "s_misc.h"
+#include "s_user.h"
+#include "struct.h"
+#include "sys.h"
+
+/* #include <assert.h> -- Now using assert in ircd_log.h */
+#include <stdio.h>
+#include <string.h>
+
+/** Last used marker value. */
+static int sentalong_marker;
+/** Array of users with the corresponding server notice mask bit set. */
+struct SLink *opsarray[32];     /* don't use highest bit unless you change
+                                  atoi to strtoul in sendto_op_mask() */
+/** Linked list of all connections with data queued to send. */
+static struct Connection *send_queues;
+char *GlobalForwards[256];
+
+/*
+ * dead_link
+ *
+ * An error has been detected. The link *must* be closed,
+ * but *cannot* call ExitClient (m_bye) from here.
+ * Instead, mark it with FLAG_DEADSOCKET. This should
+ * generate ExitClient from the main loop.
+ *
+ * If 'notice' is not NULL, it is assumed to be a format
+ * for a message to local opers. It can contain only one
+ * '%s', which will be replaced by the sockhost field of
+ * the failing link.
+ *
+ * Also, the notice is skipped for "uninteresting" cases,
+ * like Persons and yet unknown connections...
+ */
+/** Mark a client as dead, even if they are not the current message source.
+ * This is done by setting the DEADSOCKET flag on the user and letting the
+ * main loop perform the actual exit logic.
+ * @param[in,out] to Client being killed.
+ * @param[in] notice Message for local opers.
+ */
+static void dead_link(struct Client *to, char *notice)
+{
+  SetFlag(to, FLAG_DEADSOCKET);
+  /*
+   * If because of BUFFERPOOL problem then clean dbuf's now so that
+   * notices don't hurt operators below.
+   */
+  DBufClear(&(cli_recvQ(to)));
+  MsgQClear(&(cli_sendQ(to)));
+  client_drop_sendq(cli_connect(to));
+
+  /*
+   * Keep a copy of the last comment, for later use...
+   */
+  ircd_strncpy(cli_info(to), notice, REALLEN);
+
+  if (!IsUser(to) && !IsUnknown(to) && !HasFlag(to, FLAG_CLOSING))
+    sendto_opmask_butone(0, SNO_OLDSNO, "%s for %s", cli_info(to), cli_name(to));
+  Debug((DEBUG_ERROR, cli_info(to)));
+}
+
+/** Test whether we can send to a client.
+ * @param[in] to Client we want to send to.
+ * @return Non-zero if we can send to the client.
+ */
+static int can_send(struct Client* to)
+{
+  assert(0 != to);
+  return (IsDead(to) || IsMe(to) || -1 == cli_fd(to)) ? 0 : 1;
+}
+
+/** Close the connection with the highest sendq.
+ * This should be called when we need to free buffer memory.
+ * @param[in] servers_too If non-zero, consider killing servers, too.
+ */
+void
+kill_highest_sendq(int servers_too)
+{
+  int i;
+  unsigned int highest_sendq = 0;
+  struct Client *highest_client = 0;
+
+  for (i = HighestFd; i >= 0; i--)
+  {
+    if (!LocalClientArray[i] || (!servers_too && cli_serv(LocalClientArray[i])))
+      continue; /* skip servers */
+    
+    /* If this sendq is higher than one we last saw, remember it */
+    if (MsgQLength(&(cli_sendQ(LocalClientArray[i]))) > highest_sendq)
+    {
+      highest_client = LocalClientArray[i];
+      highest_sendq = MsgQLength(&(cli_sendQ(highest_client)));
+    }
+  }
+
+  if (highest_client)
+    dead_link(highest_client, "Buffer allocation error");
+}
+
+/*
+ * flush_connections
+ *
+ * Used to empty all output buffers for all connections. Should only
+ * be called once per scan of connections. There should be a select in
+ * here perhaps but that means either forcing a timeout or doing a poll.
+ * When flushing, all we do is empty the obuffer array for each local
+ * client and try to send it. if we cant send it, it goes into the sendQ
+ * -avalon
+ */
+/** Flush data queued for one or all connections.
+ * @param[in] cptr Client to flush (if NULL, do all).
+ */
+void flush_connections(struct Client* cptr)
+{
+  if (cptr) {
+    send_queued(cptr);
+  }
+  else {
+    struct Connection* con;
+    for (con = send_queues; con; con = con_next(con)) {
+      assert(0 < MsgQLength(&(con_sendQ(con))));
+      send_queued(con_client(con));
+    }
+  }
+}
+
+/*
+ * send_queued
+ *
+ * This function is called from the main select-loop (or whatever)
+ * when there is a chance that some output would be possible. This
+ * attempts to empty the send queue as far as possible...
+ */
+/** Attempt to send data queued for a client.
+ * @param[in] to Client to send data to.
+ */
+void send_queued(struct Client *to)
+{
+  assert(0 != to);
+  assert(0 != cli_local(to));
+
+  if (IsBlocked(to) || !can_send(to))
+    return;                     /* Don't bother */
+
+  while (MsgQLength(&(cli_sendQ(to))) > 0) {
+    unsigned int len;
+
+    if ((len = deliver_it(to, &(cli_sendQ(to))))) {
+      msgq_delete(&(cli_sendQ(to)), len);
+      cli_lastsq(to) = MsgQLength(&(cli_sendQ(to))) / 1024;
+      if (IsBlocked(to)) {
+       update_write(to);
+        return;
+      }
+    }
+    else {
+      if (IsDead(to)) {
+        char tmp[512];
+        sprintf(tmp,"Write error: %s",(strerror(cli_error(to))) ? (strerror(cli_error(to))) : "Unknown error" );
+        dead_link(to, tmp);
+      }
+      return;
+    }
+  }
+
+  /* Ok, sendq is now empty... */
+  client_drop_sendq(cli_connect(to));
+  update_write(to);
+}
+
+/** Try to send a buffer to a client, queueing it if needed.
+ * @param[in,out] to Client to send message to.
+ * @param[in] buf Message to send.
+ * @param[in] prio If non-zero, send as high priority.
+ */
+void send_buffer(struct Client* to, struct MsgBuf* buf, int prio)
+{
+  assert(0 != to);
+  assert(0 != buf);
+
+  if (cli_from(to))
+    to = cli_from(to);
+
+  if (!can_send(to))
+    /*
+     * This socket has already been marked as dead
+     */
+    return;
+
+  if (MsgQLength(&(cli_sendQ(to))) > get_sendq(to)) {
+    if (IsServer(to))
+      sendto_opmask_butone(0, SNO_OLDSNO, "Max SendQ limit exceeded for %C: "
+                          "%zu > %zu", to, MsgQLength(&(cli_sendQ(to))),
+                          get_sendq(to));
+    dead_link(to, "Max sendQ exceeded");
+    return;
+  }
+
+  Debug((DEBUG_SEND, "Sending [%p] to %s", buf, cli_name(to)));
+
+  msgq_add(&(cli_sendQ(to)), buf, prio);
+  client_add_sendq(cli_connect(to), &send_queues);
+  update_write(to);
+
+  /*
+   * Update statistics. The following is slightly incorrect
+   * because it counts messages even if queued, but bytes
+   * only really sent. Queued bytes get updated in SendQueued.
+   */
+  ++(cli_sendM(to));
+  ++(cli_sendM(&me));
+  /*
+   * This little bit is to stop the sendQ from growing too large when
+   * there is no need for it to. Thus we call send_queued() every time
+   * 2k has been added to the queue since the last non-fatal write.
+   * Also stops us from deliberately building a large sendQ and then
+   * trying to flood that link with data (possible during the net
+   * relinking done by servers with a large load).
+   */
+  if (MsgQLength(&(cli_sendQ(to))) / 1024 > cli_lastsq(to))
+    send_queued(to);
+}
+
+/*
+ * Send a msg to all ppl on servers/hosts that match a specified mask
+ * (used for enhanced PRIVMSGs)
+ *
+ *  addition -- Armin, 8jun90 (gruner@informatik.tu-muenchen.de)
+ */
+
+/** Check whether a client matches a target mask.
+ * @param[in] from Client trying to send a message (ignored).
+ * @param[in] one Client being considered as a target.
+ * @param[in] mask Mask for matching against.
+ * @param[in] what Type of match (either MATCH_HOST or MATCH_SERVER).
+ * @return Non-zero if \a one matches, zero if not.
+ */
+static int match_it(struct Client *from, struct Client *one, const char *mask, int what)
+{
+  switch (what)
+  {
+    case MATCH_HOST:
+      return (match(mask, cli_user(one)->host) == 0 ||
+        (HasHiddenHost(one) && match(mask, cli_user(one)->realhost) == 0));
+    case MATCH_SERVER:
+    default:
+      return (match(mask, cli_name(cli_user(one)->server)) == 0);
+  }
+}
+
+/** Send an unprefixed line to a client.
+ * @param[in] to Client receiving message.
+ * @param[in] pattern Format string of message.
+ */
+void sendrawto_one(struct Client *to, const char *pattern, ...)
+{
+  struct MsgBuf *mb;
+  va_list vl;
+
+  va_start(vl, pattern);
+  mb = msgq_vmake(to, pattern, vl);
+  va_end(vl);
+
+  send_buffer(to, mb, 0);
+
+  msgq_clean(mb);
+}
+
+/** Send a (prefixed) command to a single client.
+ * @param[in] from Client sending the command.
+ * @param[in] cmd Long name of command (used if \a to is a user).
+ * @param[in] tok Short name of command (used if \a to is a server).
+ * @param[in] to Destination of command.
+ * @param[in] pattern Format string for command arguments.
+ */
+void sendcmdto_one(struct Client *from, const char *cmd, const char *tok,
+                  struct Client *to, const char *pattern, ...)
+{
+  struct VarData vd;
+  struct MsgBuf *mb;
+
+  to = cli_from(to);
+
+  vd.vd_format = pattern; /* set up the struct VarData for %v */
+  va_start(vd.vd_args, pattern);
+
+  mb = msgq_make(to, "%:#C %s %v", from, IsServer(to) || IsMe(to) ? tok : cmd,
+                &vd);
+
+  va_end(vd.vd_args);
+
+  send_buffer(to, mb, 0);
+
+  msgq_clean(mb);
+}
+
+/**
+ * Send a (prefixed) command to a single client in the priority queue.
+ * @param[in] from Client sending the command.
+ * @param[in] cmd Long name of command (used if \a to is a user).
+ * @param[in] tok Short name of command (used if \a to is a server).
+ * @param[in] to Destination of command.
+ * @param[in] pattern Format string for command arguments.
+ */
+void sendcmdto_prio_one(struct Client *from, const char *cmd, const char *tok,
+                       struct Client *to, const char *pattern, ...)
+{
+  struct VarData vd;
+  struct MsgBuf *mb;
+
+  to = cli_from(to);
+
+  vd.vd_format = pattern; /* set up the struct VarData for %v */
+  va_start(vd.vd_args, pattern);
+
+  mb = msgq_make(to, "%:#C %s %v", from, IsServer(to) || IsMe(to) ? tok : cmd,
+                &vd);
+
+  va_end(vd.vd_args);
+
+  send_buffer(to, mb, 1);
+
+  msgq_clean(mb);
+}
+
+/**
+ * Send a (prefixed) command to all servers matching or not matching a
+ * flag but one.
+ * @param[in] from Client sending the command.
+ * @param[in] cmd Long name of command (ignored).
+ * @param[in] tok Short name of command.
+ * @param[in] one Client direction to skip (or NULL).
+ * @param[in] require Only send to servers with this Flag bit set.
+ * @param[in] forbid Do not send to servers with this Flag bit set.
+ * @param[in] pattern Format string for command arguments.
+ */
+void sendcmdto_flag_serv_butone(struct Client *from, const char *cmd,
+                                const char *tok, struct Client *one,
+                                int require, int forbid,
+                                const char *pattern, ...)
+{
+  struct VarData vd;
+  struct MsgBuf *mb;
+  struct DLink *lp;
+
+  vd.vd_format = pattern; /* set up the struct VarData for %v */
+  va_start(vd.vd_args, pattern);
+
+  /* use token */
+  mb = msgq_make(&me, "%C %s %v", from, tok, &vd);
+  va_end(vd.vd_args);
+
+  /* send it to our downlinks */
+  for (lp = cli_serv(&me)->down; lp; lp = lp->next) {
+    if (one && lp->value.cptr == cli_from(one))
+      continue;
+    if ((require < FLAG_LAST_FLAG) && !HasFlag(lp->value.cptr, require))
+      continue;
+    if ((forbid < FLAG_LAST_FLAG) && HasFlag(lp->value.cptr, forbid))
+      continue;
+    send_buffer(lp->value.cptr, mb, 0);
+  }
+
+  msgq_clean(mb);
+}
+
+/**
+ * Send a (prefixed) command to all servers but one.
+ * @param[in] from Client sending the command.
+ * @param[in] cmd Long name of command (ignored).
+ * @param[in] tok Short name of command.
+ * @param[in] one Client direction to skip (or NULL).
+ * @param[in] pattern Format string for command arguments.
+ */
+void sendcmdto_serv_butone(struct Client *from, const char *cmd,
+                          const char *tok, struct Client *one,
+                          const char *pattern, ...)
+{
+  struct VarData vd;
+  struct MsgBuf *mb;
+  struct DLink *lp;
+
+  vd.vd_format = pattern; /* set up the struct VarData for %v */
+  va_start(vd.vd_args, pattern);
+
+  /* use token */
+  mb = msgq_make(&me, "%C %s %v", from, tok, &vd);
+  va_end(vd.vd_args);
+
+  /* send it to our downlinks */
+  for (lp = cli_serv(&me)->down; lp; lp = lp->next) {
+    if (one && lp->value.cptr == cli_from(one))
+      continue;
+    send_buffer(lp->value.cptr, mb, 0);
+  }
+
+  msgq_clean(mb);
+}
+
+/** Safely increment the sentalong marker.
+ * This increments the sentalong marker.  Since new connections will
+ * have con_sentalong() == 0, and to avoid confusion when the counter
+ * wraps, we reset all sentalong markers to zero when the sentalong
+ * marker hits zero.
+ * @param[in,out] one Client to mark with new sentalong marker (if any).
+ */
+static void
+bump_sentalong(struct Client *one)
+{
+  if (!++sentalong_marker)
+  {
+    int ii;
+    for (ii = 0; ii < HighestFd; ++ii)
+      if (LocalClientArray[ii])
+        cli_sentalong(LocalClientArray[ii]) = 0;
+    ++sentalong_marker;
+  }
+  if (one)
+    cli_sentalong(one) = sentalong_marker;
+}
+
+/** Send a (prefixed) command to all channels that \a from is on.
+ * @param[in] from Client originating the command.
+ * @param[in] cmd Long name of command.
+ * @param[in] tok Short name of command.
+ * @param[in] one Client direction to skip (or NULL).
+ * @param[in] pattern Format string for command arguments.
+ */
+void sendcmdto_common_channels_butone(struct Client *from, const char *cmd,
+                                     const char *tok, struct Client *one,
+                                     const char *pattern, ...)
+{
+  struct VarData vd;
+  struct MsgBuf *mb;
+  struct Membership *chan;
+  struct Membership *member;
+
+  assert(0 != from);
+  assert(0 != cli_from(from));
+  assert(0 != pattern);
+  assert(!IsServer(from) && !IsMe(from));
+
+  vd.vd_format = pattern; /* set up the struct VarData for %v */
+
+  va_start(vd.vd_args, pattern);
+
+  /* build the buffer */
+  mb = msgq_make(0, "%:#C %s %v", from, cmd, &vd);
+  va_end(vd.vd_args);
+
+  bump_sentalong(from);
+  /*
+   * loop through from's channels, and the members on their channels
+   */
+  for (chan = cli_user(from)->channel; chan; chan = chan->next_channel) {
+    if (IsZombie(chan) || IsDelayedJoin(chan))
+      continue;
+    for (member = chan->channel->members; member;
+        member = member->next_member)
+      if (MyConnect(member->user)
+          && -1 < cli_fd(cli_from(member->user))
+          && member->user != one
+          && cli_sentalong(member->user) != sentalong_marker) {
+       cli_sentalong(member->user) = sentalong_marker;
+       send_buffer(member->user, mb, 0);
+      }
+  }
+
+  if (MyConnect(from) && from != one)
+    send_buffer(from, mb, 0);
+
+  msgq_clean(mb);
+}
+
+/** Send a (prefixed) command to all local users on a channel.
+ * @param[in] from Client originating the command.
+ * @param[in] cmd Long name of command.
+ * @param[in] tok Short name of command (ignored).
+ * @param[in] to Destination channel.
+ * @param[in] one Client direction to skip (or NULL).
+ * @param[in] skip Bitmask of SKIP_DEAF, SKIP_NONOPS, SKIP_NONVOICES indicating which clients to skip.
+ * @param[in] pattern Format string for command arguments.
+ */
+void sendcmdto_channel_butserv_butone(struct Client *from, const char *cmd,
+                                     const char *tok, struct Channel *to,
+                                     struct Client *one, unsigned int skip,
+                                      const char *pattern, ...)
+{
+  struct VarData vd;
+  struct MsgBuf *mb;
+  struct Membership *member;
+
+  vd.vd_format = pattern; /* set up the struct VarData for %v */
+  va_start(vd.vd_args, pattern);
+
+  /* build the buffer */
+  mb = msgq_make(0, "%:#C %s %v", from, cmd, &vd);
+  va_end(vd.vd_args);
+
+  /* send the buffer to each local channel member */
+  for (member = to->members; member; member = member->next_member) {
+    if (!MyConnect(member->user)
+        || member->user == one 
+        || IsZombie(member)
+        || (skip & SKIP_DEAF && IsDeaf(member->user))
+        || (skip & SKIP_NONOPS && !IsChanOp(member))
+        || (skip & SKIP_NONVOICES && !IsChanOp(member) && !HasVoice(member)))
+        continue;
+      send_buffer(member->user, mb, 0);
+  }
+
+  msgq_clean(mb);
+}
+
+/** Send a (prefixed) command to all servers with users on \a to.
+ * Skip \a from and \a one plus those indicated in \a skip.
+ * @param[in] from Client originating the command.
+ * @param[in] cmd Long name of command (ignored).
+ * @param[in] tok Short name of command.
+ * @param[in] to Destination channel.
+ * @param[in] one Client direction to skip (or NULL).
+ * @param[in] skip Bitmask of SKIP_NONOPS and SKIP_NONVOICES indicating which clients to skip.
+ * @param[in] pattern Format string for command arguments.
+ */
+void sendcmdto_channel_servers_butone(struct Client *from, const char *cmd,
+                                      const char *tok, struct Channel *to,
+                                      struct Client *one, unsigned int skip,
+                                      const char *pattern, ...)
+{
+  struct VarData vd;
+  struct MsgBuf *serv_mb;
+  struct Membership *member;
+
+  /* build the buffer */
+  vd.vd_format = pattern;
+  va_start(vd.vd_args, pattern);
+  serv_mb = msgq_make(&me, "%:#C %s %v", from, tok, &vd);
+  va_end(vd.vd_args);
+
+  /* send the buffer to each server */
+  bump_sentalong(one);
+  cli_sentalong(from) = sentalong_marker;
+  for (member = to->members; member; member = member->next_member) {
+    if (MyConnect(member->user)
+        || IsZombie(member)
+        || cli_fd(cli_from(member->user)) < 0
+        || cli_sentalong(member->user) == sentalong_marker
+        || (skip & SKIP_NONOPS && !IsChanOp(member))
+        || (skip & SKIP_NONVOICES && !IsChanOp(member) && !HasVoice(member)))
+      continue;
+    cli_sentalong(member->user) = sentalong_marker;
+    send_buffer(member->user, serv_mb, 0);
+  }
+  msgq_clean(serv_mb);
+}
+
+
+/** Send a (prefixed) command to all users on this channel, except for
+ * \a one and those matching \a skip.
+ * @warning \a pattern must not contain %v.
+ * @param[in] from Client originating the command.
+ * @param[in] cmd Long name of command.
+ * @param[in] tok Short name of command.
+ * @param[in] to Destination channel.
+ * @param[in] one Client direction to skip (or NULL).
+ * @param[in] skip Bitmask of SKIP_NONOPS, SKIP_NONVOICES, SKIP_DEAF, SKIP_BURST.
+ * @param[in] pattern Format string for command arguments.
+ */
+void sendcmdto_channel_butone(struct Client *from, const char *cmd,
+                             const char *tok, struct Channel *to,
+                             struct Client *one, unsigned int skip,
+                             unsigned char prefix, const char *pattern, ...)
+{
+  struct Membership *member;
+  struct VarData vd;
+  struct MsgBuf *user_mb;
+  struct MsgBuf *serv_mb;
+  struct Client *service;
+
+  vd.vd_format = pattern;
+
+  /* Build buffer to send to users */
+  va_start(vd.vd_args, pattern);
+  user_mb = msgq_make(0, skip & (SKIP_NONOPS | SKIP_NONVOICES) ? "%:#C %s @%v" : "%:#C %s %v",
+                      from, skip & (SKIP_NONOPS | SKIP_NONVOICES) ? MSG_NOTICE : cmd, &vd);
+  va_end(vd.vd_args);
+
+  /* Build buffer to send to servers */
+  va_start(vd.vd_args, pattern);
+  serv_mb = msgq_make(&me, "%C %s %v", from, tok, &vd);
+  va_end(vd.vd_args);
+
+  /* send buffer along! */
+  bump_sentalong(one);
+  for (member = to->members; member; member = member->next_member) {
+    /* skip one, zombies, and deaf users... */
+    if (IsZombie(member) ||
+        (skip & SKIP_DEAF && IsDeaf(member->user)) ||
+        (skip & SKIP_NONOPS && !IsChanOp(member)) ||
+        (skip & SKIP_NONVOICES && !IsChanOp(member) && !HasVoice(member)) ||
+        (skip & SKIP_BURST && IsBurstOrBurstAck(cli_from(member->user))) ||
+        cli_fd(cli_from(member->user)) < 0 ||
+        cli_sentalong(member->user) == sentalong_marker)
+      continue;
+    cli_sentalong(member->user) = sentalong_marker;
+
+    if (MyConnect(member->user)) /* pick right buffer to send */
+      send_buffer(member->user, user_mb, 0);
+    else
+      send_buffer(member->user, serv_mb, 0);
+  }
+
+  /* Consult service forwarding table. */
+  if(GlobalForwards[prefix]
+      && (service = FindServer(GlobalForwards[prefix]))
+      && cli_sentalong(service) != sentalong_marker) {
+      cli_sentalong(service) = sentalong_marker;
+      send_buffer(service, serv_mb, 0);
+  }
+  
+  if(GlobalForwards['*']
+      && (service = FindServer(GlobalForwards['*']))
+      && cli_sentalong(service) != sentalong_marker) {
+      cli_sentalong(service) = sentalong_marker;
+      send_buffer(service, serv_mb, 0);
+  }
+
+  msgq_clean(user_mb);
+  msgq_clean(serv_mb);
+}
+
+/** Send a (prefixed) WALL of type \a type to all users except \a one.
+ * @warning \a pattern must not contain %v.
+ * @param[in] from Source of the command.
+ * @param[in] type One of WALL_DESYNCH, WALL_WALLOPS or WALL_WALLUSERS.
+ * @param[in] one Client direction to skip (or NULL).
+ * @param[in] pattern Format string for command arguments.
+ */
+void sendwallto_group_butone(struct Client *from, int type, struct Client *one,
+                            const char *pattern, ...)
+{
+  struct VarData vd;
+  struct Client *cptr;
+  struct MsgBuf *mb;
+  struct DLink *lp;
+  char *prefix=NULL;
+  char *tok=NULL;
+  int his_wallops;
+  int i;
+
+  vd.vd_format = pattern;
+
+  /* Build buffer to send to users */
+  va_start(vd.vd_args, pattern);
+  switch (type) {
+       case WALL_DESYNCH:
+               prefix="";
+               tok=TOK_DESYNCH;
+               break;
+       case WALL_WALLOPS:
+               prefix="* ";
+               tok=TOK_WALLOPS;
+               break;
+       case WALL_WALLUSERS:
+               prefix="$ ";
+               tok=TOK_WALLUSERS;
+               break;
+       default:
+               assert(0);
+  }
+  mb = msgq_make(0, "%:#C " MSG_WALLOPS " :%s%v", from, prefix,&vd);
+  va_end(vd.vd_args);
+
+  /* send buffer along! */
+  his_wallops = feature_bool(FEAT_HIS_WALLOPS);
+  for (i = 0; i <= HighestFd; i++)
+  {
+    if (!(cptr = LocalClientArray[i]) ||
+       (cli_fd(cli_from(cptr)) < 0) ||
+       (type == WALL_DESYNCH && !SendDebug(cptr)) ||
+       (type == WALL_WALLOPS &&
+         (!SendWallops(cptr) || (his_wallops && !IsAnOper(cptr)))) ||
+        (type == WALL_WALLUSERS && !SendWallops(cptr)))
+      continue; /* skip it */
+    send_buffer(cptr, mb, 1);
+  }
+
+  msgq_clean(mb);
+
+  /* Build buffer to send to servers */
+  va_start(vd.vd_args, pattern);
+  mb = msgq_make(&me, "%C %s :%v", from, tok, &vd);
+  va_end(vd.vd_args);
+
+  /* send buffer along! */
+  for (lp = cli_serv(&me)->down; lp; lp = lp->next) {
+    if (one && lp->value.cptr == cli_from(one))
+      continue;
+    send_buffer(lp->value.cptr, mb, 1);
+  }
+
+  msgq_clean(mb);
+}
+
+/** Send a (prefixed) command to all users matching \a to as \a who.
+ * @warning \a pattern must not contain %v.
+ * @param[in] from Source of the command.
+ * @param[in] cmd Long name of command.
+ * @param[in] tok Short name of command.
+ * @param[in] to Destination host/server mask.
+ * @param[in] one Client direction to skip (or NULL).
+ * @param[in] who Type of match for \a to (either MATCH_HOST or MATCH_SERVER).
+ * @param[in] pattern Format string for command arguments.
+ */
+void sendcmdto_match_butone(struct Client *from, const char *cmd,
+                           const char *tok, const char *to,
+                           struct Client *one, unsigned int who,
+                           const char *pattern, ...)
+{
+  struct VarData vd;
+  struct Client *cptr;
+  struct MsgBuf *user_mb;
+  struct MsgBuf *serv_mb;
+
+  vd.vd_format = pattern;
+
+  /* Build buffer to send to users */
+  va_start(vd.vd_args, pattern);
+  user_mb = msgq_make(0, "%:#C %s %v", from, cmd, &vd);
+  va_end(vd.vd_args);
+
+  /* Build buffer to send to servers */
+  va_start(vd.vd_args, pattern);
+  serv_mb = msgq_make(&me, "%C %s %v", from, tok, &vd);
+  va_end(vd.vd_args);
+
+  /* send buffer along */
+  bump_sentalong(one);
+  for (cptr = GlobalClientList; cptr; cptr = cli_next(cptr)) {
+    if (!IsRegistered(cptr) || IsServer(cptr) || cli_fd(cli_from(cptr)) < 0 ||
+        cli_sentalong(cptr) == sentalong_marker ||
+        !match_it(from, cptr, to, who))
+      continue; /* skip it */
+    cli_sentalong(cptr) = sentalong_marker;
+
+    if (MyConnect(cptr)) /* send right buffer */
+      send_buffer(cptr, user_mb, 0);
+    else
+      send_buffer(cptr, serv_mb, 0);
+  }
+
+  msgq_clean(user_mb);
+  msgq_clean(serv_mb);
+}
+
+/** Send a server notice to all users subscribing to the indicated \a
+ * mask except for \a one.
+ * @param[in] one Client direction to skip (or NULL).
+ * @param[in] mask One of the SNO_* constants.
+ * @param[in] pattern Format string for server notice.
+ */
+void sendto_opmask_butone(struct Client *one, unsigned int mask,
+                         const char *pattern, ...)
+{
+  va_list vl;
+
+  va_start(vl, pattern);
+  vsendto_opmask_butone(one, mask, pattern, vl);
+  va_end(vl);
+}
+
+/** Send a server notice to all users subscribing to the indicated \a
+ * mask except for \a one, rate-limited to once per 30 seconds.
+ * @param[in] one Client direction to skip (or NULL).
+ * @param[in] mask One of the SNO_* constants.
+ * @param[in,out] rate Pointer to the last time the message was sent.
+ * @param[in] pattern Format string for server notice.
+ */
+void sendto_opmask_butone_ratelimited(struct Client *one, unsigned int mask,
+                                     time_t *rate, const char *pattern, ...)
+{
+  va_list vl;
+
+  if ((CurrentTime - *rate) < 30)
+    return;
+  else
+    *rate = CurrentTime;
+
+  va_start(vl, pattern);
+  vsendto_opmask_butone(one, mask, pattern, vl);
+  va_end(vl);
+}
+
+
+/** Send a server notice to all users subscribing to the indicated \a
+ * mask except for \a one.
+ * @param[in] one Client direction to skip (or NULL).
+ * @param[in] mask One of the SNO_* constants.
+ * @param[in] pattern Format string for server notice.
+ * @param[in] vl Argument list for format string.
+ */
+void vsendto_opmask_butone(struct Client *one, unsigned int mask,
+                          const char *pattern, va_list vl)
+{
+  struct VarData vd;
+  struct MsgBuf *mb;
+  int i = 0; /* so that 1 points to opsarray[0] */
+  struct SLink *opslist;
+
+  while ((mask >>= 1))
+    i++;
+
+  if (!(opslist = opsarray[i]))
+    return;
+
+  /*
+   * build string; I don't want to bother with client nicknames, so I hope
+   * this is ok...
+   */
+  vd.vd_format = pattern;
+  va_copy(vd.vd_args, vl);
+  mb = msgq_make(0, ":%s " MSG_NOTICE " * :*** Notice -- %v", cli_name(&me),
+                &vd);
+
+  for (; opslist; opslist = opslist->next)
+    if (opslist->value.cptr != one)
+      send_buffer(opslist->value.cptr, mb, 0);
+
+  msgq_clean(mb);
+}
diff --git a/ircd/ssl.c b/ircd/ssl.c
new file mode 100644 (file)
index 0000000..49e861f
--- /dev/null
@@ -0,0 +1,1326 @@
+/*
+ * IRC - Internet Relay Chat, ircd/ssl.c
+ * Written by David Herrmann.
+ */
+
+
+/* SSL module.
+ * This SSL module is created to be as generic as possible.
+ * That is, it is easy to add new backends. We currently support
+ * GnuTLS and OpenSSL.
+ *
+ * The module is built up to encrypt all kinds of network connections.
+ * You have to create your socket yourself and accept() or connect() it.
+ * The new connected socket has to be passed to this module which then
+ * initiates a secure connection. While initiating this connection the
+ * socket is kept in a separate queue inside this module. When the
+ * connection has been fully established, the client is passed back to
+ * the add_connection() function which then passes the client to the
+ * authentication module. You can handle the client equally to a normal
+ * unencrypted connection, however, the send()/recv() functions have
+ * to be changed to the functions provided by this module.
+ *
+ * The first part of this file defines the backend functions. Only one
+ * backend can be enabled at one time. Please add your own backends there.
+ *
+ * 2009/05/19 --gix
+ */
+
+
+#include "config.h"
+#include "ircd.h"
+#include "ircd_defs.h"
+#include "ircd_events.h"
+#include "ircd_snprintf.h"
+#include "ircd_osdep.h"
+#include "ircd_alloc.h"
+#include "ircd_log.h"
+#include "msgq.h"
+#include "s_debug.h"
+#include "s_bsd.h"
+#include "s_misc.h"
+#include "client.h"
+#include "listener.h"
+#include "send.h"
+#include "ssl.h"
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+
+
+/* Backend declarations.
+ * Please add your backend here. I recommend to leave GnuTLS as the first choice
+ * because it is tested most and works perfectly. You can change the backend with
+ * the configure script at compile time.
+ *
+ * Each backend has to declare the following functions:
+ * - ssl_be_init(): This is called when the SSL library should be initialized.
+ * - ssl_be_deinit(): This is called when the SSL library should be deinitialized.
+ * - ssl_be_cred_new(): This should create a new credentials structure.
+ * - ssl_be_cred_free(): This should free a previously allocated credentials structure.
+ * - ssl_be_session_new(): This should create a new session.
+ * - ssl_be_session_connect(): This connects a session with an FD.
+ * - ssl_be_session_shutdown(): This should shutdown the Write-Endpoint of a session.
+ * - ssl_be_session_free(): This should free a session.
+ * - ssl_be_handshake(): This should start/continue the protocol handshake.
+ * - ssl_be_send(): This should send data over the connection.
+ * - ssl_be_recv(): This should receive data from the connection.
+ * - ssl_be_cipherstr(): This should return a string representing the used cipher.
+ * - ssl_be_fingerprint(): Validates the peer's socket and returns the fingerprint on success.
+ *
+ * You should declare the backend specific functions at the end of this files. At this
+ * point, every backend has to define the ssl_be_cred_t and ssl_be_session_t structures which
+ * represent the credentials and session values used by the backend.
+ *
+ * Please use the namespace "ssl_be_" in your backend only! All other names may collide
+ * with other names.
+ * Furthermore look into the dummy to see which checks are already done by the main module
+ * and what you do not have to do in your backend.
+ */
+
+
+#if defined(HAVE_GNUTLS)
+    /* GnuTLS backend.
+     * GnuTLS is licensed under the LGPL and developed by the GNU project.
+     * This backend is recommended and tested by the developers of this module.
+     */
+    #include <gnutls/gnutls.h>
+    typedef struct {
+        gnutls_certificate_credentials_t cred;
+        gnutls_dh_params_t dhparams;
+        gnutls_priority_t prio;
+    } ssl_be_cred_t;
+    typedef gnutls_session_t ssl_be_session_t;
+#elif defined(HAVE_OPENSSL)
+    /* OpenSSL backend.
+     * OpenSSL is developed by independant people and a de-facto standard in the
+     * industry. However, the source is *bad* and it has had many bugs in the
+     * past. We do not recommend this module!
+     */
+    /* On some systems, these headers also include the OpenSSL md5 header
+     * which itself defines MD5_CTX. This is already defined in ircd_md5.h,
+     * hence, we prevent this inclusion here.
+     * This fix is really *BAD* but since OpenSSL does not use "namespaces"/
+     * "prefixes" there is currently no other solution.
+     */
+    #define HEADER_MD5_H
+    #include <openssl/ssl.h>
+    #include <openssl/err.h>
+    #include <openssl/rand.h>
+    typedef SSL_CTX* ssl_be_cred_t;
+    typedef SSL* ssl_be_session_t;
+    static signed int ssl_be_verify(signed int preverify_ok, X509_STORE_CTX *ctx);
+#else
+    /* Dummy backend.
+     * No backend available. We simply declare fake structures here and handle
+     * the connections unencrypted.
+     */
+    typedef void* ssl_be_cred_t;
+    typedef void* ssl_be_session_t;
+#endif
+
+
+/* SSL credentials (cred).
+ * An SSL credential is a specific certificate which can be used in many SSL
+ * sessions. However, we want to allow to change the certificate at runtime,
+ * therefore, we allow several credentials at one time. A new credential is
+ * created on /rehash when the certificate changed and then the old creds are
+ * marked for removal. New clients are connected with the new credential so we
+ * can remove the old creds when there are no more connected clients with this
+ * credential.
+ * A cred can either be for accepting clients or for connecting yourself as
+ * client. We support both, that is, server<->server encryption is also supported.
+ * The global creds are stored separated in two single linked lists. If the lists
+ * are empty, then no credential has been loaded yet and a new one will be created
+ * when a client connects.
+ * Thus, only the first credential in this list should be used for new connections,
+ * all other credentials are marked for removal.
+ */
+struct ssl_cred_t;
+struct ssl_cred_t {
+    struct ssl_cred_t *next;
+    unsigned int ref;
+    unsigned int mode;
+    ssl_be_cred_t be;
+};
+struct ssl_cred_t *ssl_cli_credlist = NULL;
+struct ssl_cred_t *ssl_srv_credlist = NULL;
+
+
+/* SSL sessions.
+ * A session contains all data that is needed by the SSL backend. We also link
+ * the session to the used credentials to be able to modify the cred when we
+ * modify the session.
+ * \fingerprint is NULL when the peer's certificate is not trusted. If it is
+ * trusted, then \fingerprint points to a string containing the fingerprint of
+ * the peer's certificate.
+ */
+struct ssl_session_t;
+struct ssl_session_t {
+    struct ssl_cred_t *cred;
+    ssl_be_session_t be;
+    char *fingerprint;
+};
+
+
+/* Represents an SSL connection whose handshake is currently pending.
+ * If a client connects, it is accepted and then put into the handshake queue.
+ * If the handshake timeouts he is rejected, otherwise he is put into the
+ * usual user-queue and the auth module continues.
+ * This structure is only used in the handshake-queue of accepted SSL clients.
+ *
+ * ssl_conn_t is the pending outgoing connection. The handshake is performed
+ * in this state and then returned to the main module when done. This is handled
+ * separately to the client connections.
+ */
+struct ssl_pending_t {
+    ssl_session_t *session;
+    struct Socket socket;
+    struct Timer timeout;
+    signed int fd;
+    struct Listener *listener;
+};
+struct ssl_conn_t {
+    ssl_session_t *session;
+    struct Timer timeout;
+    struct Client *cptr;
+    void *olddata;
+};
+
+
+/* Backend functions.
+ * See the comment near the top of this file for information on these functions.
+ */
+unsigned int ssl_be_init();
+void ssl_be_deinit();
+unsigned int ssl_be_cred_new(unsigned int mode, char *cert, char **trusts, ssl_be_cred_t *cred);
+void ssl_be_cred_free(ssl_be_cred_t *cred);
+unsigned int ssl_be_session_new(unsigned int mode, ssl_be_cred_t *cred, ssl_be_session_t *session);
+unsigned int ssl_be_session_connect(ssl_be_session_t *session, signed int fd);
+void ssl_be_session_shutdown(ssl_be_session_t *session);
+void ssl_be_session_free(ssl_be_session_t *session);
+#define SSL_NEED_WR 0
+#define SSL_NEED_RD 1
+#define SSL_NEED_RDWR 2
+#define SSL_FAILURE 3
+#define SSL_SUCCESS 4
+unsigned int ssl_be_handshake(unsigned int mode, ssl_be_session_t *session);
+const char *ssl_be_cipherstr(ssl_be_session_t *session);
+const char *ssl_be_fingerprint(ssl_be_session_t *session);
+IOResult ssl_be_send(signed int fd, ssl_be_session_t *ssl, const char *buf, unsigned int *count_out);
+IOResult ssl_be_recv(signed int fd, ssl_be_session_t *ssl, char *buf, unsigned int *count_out);
+
+
+/* Path to the certificate to use. */
+char *ssl_cert = NULL;
+char **ssl_trusts = NULL;
+void ssl_setcert(const char *cert) {
+    MyFree(ssl_cert);
+    ssl_cert = strdup(cert);
+}
+void ssl_clearcert() {
+    MyFree(ssl_cert);
+    ssl_cert = NULL;
+}
+void ssl_addtrust(const char *trust) {
+    unsigned int i;
+    char **tmp;
+    if(ssl_trusts) {
+        i = 0;
+        while(ssl_trusts[i]) ++i;
+        tmp = MyMalloc(sizeof(char*) * (i + 2));
+        i = 0;
+        while(ssl_trusts[i]) {
+            tmp[i] = ssl_trusts[i];
+            ++i;
+        }
+        tmp[i] = strdup(trust);
+        tmp[i + 1] = NULL;
+        MyFree(ssl_trusts);
+        ssl_trusts = tmp;
+    }
+    else {
+        tmp = MyMalloc(sizeof(char*) * 2);
+        tmp[0] = strdup(trust);
+        tmp[1] = NULL;
+        ssl_trusts = tmp;
+    }
+}
+void ssl_cleartrusts() {
+    unsigned int i;
+    if(ssl_trusts) {
+        i = 0;
+        while(ssl_trusts[i]) {
+            MyFree(ssl_trusts[i]);
+            ++i;
+        }
+        MyFree(ssl_trusts);
+        ssl_trusts = NULL;
+    }
+}
+
+
+/* This handles SSL messages.
+ * It writes the message to the logfile and prints it on the screen if debugmode is
+ * enabled.
+ */
+#define SSL_NOTICE 0
+#define SSL_ERROR 1
+#define SSL_DEBUG 2
+static void ssl_msg(unsigned int type, const char *msg, ...) {
+    va_list list;
+
+    va_start(list, msg);
+#ifdef DEBUGMODE
+    #define SSL_DEBUGMSG(x, y, z) vdebug((x), (y), (z))
+#else
+    #define SSL_DEBUGMSG(x, y, z)
+#endif
+    switch(type) {
+        case SSL_NOTICE:
+            log_vwrite(LS_SYSTEM, L_NOTICE, 0, msg, list);
+            SSL_DEBUGMSG(DEBUG_NOTICE, msg, list);
+            break;
+        case SSL_ERROR:
+            log_vwrite(LS_SYSTEM, L_CRIT, 0, msg, list);
+            SSL_DEBUGMSG(DEBUG_FATAL, msg, list);
+            break;
+        case SSL_DEBUG:
+            SSL_DEBUGMSG(DEBUG_DEBUG, msg, list);
+            break;
+    }
+    va_end(list);
+}
+
+
+/* Initializes or Deinitializes the SSL module. */
+static unsigned int ssl_loaded = 0;
+void ssl_init() {
+    if(ssl_loaded) {
+        ssl_msg(SSL_ERROR, "SSL: ssl_init(): called twice");
+        return;
+    }
+    if(ssl_be_init()) {
+        ssl_loaded = 1;
+        ssl_msg(SSL_NOTICE, "SSL: ssl_init(): done");
+    }
+    else ssl_msg(SSL_ERROR, "SSL: ssl_be_deinit(): failed");
+}
+void ssl_deinit() {
+    if(!ssl_loaded) {
+        ssl_msg(SSL_ERROR, "SSL: ssl_deinit(): not initialized");
+        return;
+    }
+
+    /* Check whether there are active SSL connections.
+     * That is, the credentials-list must either be empty or contain only
+     * one credential with ZERO references which then is deleted.
+     */
+    if((ssl_srv_credlist && (ssl_srv_credlist->next || ssl_srv_credlist->ref)) ||
+       (ssl_cli_credlist && (ssl_cli_credlist->next || ssl_cli_credlist->ref))) {
+        ssl_msg(SSL_ERROR, "SSL: ssl_deinit(): still active sessions");
+        return;
+    }
+    if(ssl_srv_credlist) ssl_cred_free(ssl_srv_credlist);
+    if(ssl_cli_credlist) ssl_cred_free(ssl_cli_credlist);
+
+    ssl_be_deinit();
+    ssl_clearcert();
+    ssl_cleartrusts();
+
+    ssl_msg(SSL_NOTICE, "SSL: ssl_deinit(): done");
+    ssl_loaded = 0;
+}
+
+
+/* Creates/Frees a credential. */
+ssl_cred_t *ssl_cred_new(unsigned int mode, char *cert, char **trusts) {
+    ssl_cred_t *cred;
+
+    cred = MyMalloc(sizeof(ssl_cred_t));
+    memset(cred, 0, sizeof(ssl_cred_t));
+
+    if(!ssl_be_cred_new(mode, cert, trusts, &cred->be)) {
+        ssl_msg(SSL_ERROR, "SSL: ssl_be_cred_new(): failed.");
+        MyFree(cred);
+        return NULL;
+    }
+
+    if(mode == SSL_CLIENT) {
+        if(ssl_cli_credlist && ssl_cli_credlist->ref == 0) ssl_cred_free(ssl_cli_credlist);
+        cred->next = ssl_cli_credlist;
+        ssl_cli_credlist = cred;
+    }
+    else {
+        if(ssl_srv_credlist && ssl_srv_credlist->ref == 0) ssl_cred_free(ssl_srv_credlist);
+        cred->next = ssl_srv_credlist;
+        ssl_srv_credlist = cred;
+    }
+    cred->mode = mode;
+    cred->ref = 0;
+    ssl_msg(SSL_NOTICE, "SSL: ssl_cred_new(%u, '%s'): done", mode, cert);
+    return cred;
+}
+void ssl_cred_free(ssl_cred_t *cred) {
+    ssl_cred_t *iter;
+
+    if(cred->ref) {
+        ssl_msg(SSL_ERROR, "SSL: ssl_cred_free(%u, %u): still active sessions", cred->mode, cred->ref);
+        return;
+    }
+
+    if(cred->mode == SSL_CLIENT) {
+        iter = ssl_cli_credlist;
+        if(iter == cred) {
+            ssl_cli_credlist = iter->next;
+            goto free_cred;
+        }
+        while(iter) {
+            if(iter->next == cred) {
+                iter->next = cred->next;
+                goto free_cred;
+            }
+        }
+        ssl_msg(SSL_ERROR, "SSL: ssl_cred_free(): invalid cred");
+        return;
+    }
+    else {
+        iter = ssl_srv_credlist;
+        if(iter == cred) {
+            ssl_srv_credlist = iter->next;
+            goto free_cred;
+        }
+        while(iter) {
+            if(iter->next == cred) {
+                iter->next = cred->next;
+                goto free_cred;
+            }
+        }
+        ssl_msg(SSL_ERROR, "SSL: ssl_cred_free(): invalid cred");
+        return;
+    }
+
+    free_cred:
+    ssl_be_cred_free(&cred->be);
+    ssl_msg(SSL_NOTICE, "SSL: ssl_cred_free(%u): done", cred->mode);
+    MyFree(cred);
+}
+
+
+/* Manipulates an SSL session. */
+ssl_session_t *ssl_session_new(unsigned int mode) {
+    ssl_session_t *ssl;
+    char **trusts, *fallback[1] = { NULL };
+
+    /* If no SSL certificate is set, we stop.
+     * We also clear \ssl_cert when allocating the certificate fails.
+     * This prevents the ircd from reallocating the credentials everytime
+     * a client connects although the allocation is guaranteed to fail.
+     */
+    if(!ssl_cert) return NULL;
+    if(ssl_trusts) trusts = ssl_trusts;
+    else trusts = fallback;
+
+    ssl = MyMalloc(sizeof(ssl_session_t));
+    memset(ssl, 0, sizeof(ssl_session_t));
+    ssl->fingerprint = NULL;
+
+    if(mode == SSL_CLIENT) {
+        if(ssl_cli_credlist) ssl->cred = ssl_cli_credlist;
+        else if(!(ssl->cred = ssl_cred_new(SSL_CLIENT, ssl_cert, trusts))) {
+            MyFree(ssl_cert);
+            ssl_cert = NULL;
+            MyFree(ssl);
+            ssl_msg(SSL_ERROR, "SSL: ssl_session_new(%u): failed", mode);
+            return NULL;
+        }
+    }
+    else {
+        if(ssl_srv_credlist) ssl->cred = ssl_srv_credlist;
+        else if(!(ssl->cred = ssl_cred_new(SSL_SERVER, ssl_cert, trusts))) {
+            MyFree(ssl_cert);
+            ssl_cert = NULL;
+            MyFree(ssl);
+            ssl_msg(SSL_ERROR, "SSL: ssl_session_new(%u): failed", mode);
+            return NULL;
+        }
+    }
+
+    if(!ssl_be_session_new(mode, &ssl->cred->be, &ssl->be)) {
+        /* Keep credentials. They may be used later. */
+        MyFree(ssl);
+        ssl_msg(SSL_ERROR, "SSL: ssl_session_new(%u): failed", mode);
+        return NULL;
+    }
+
+    ++ssl->cred->ref;
+    ssl_msg(SSL_DEBUG, "SSL: ssl_session_new(%u): done", mode);
+    return ssl;
+}
+void ssl_session_shutdown(ssl_session_t *ssl) {
+    /* We do not care for the return value here. This might be implemented
+     * in future. This makes ssl_shutdown() totally useless but this is only
+     * a placeholder for future implementations.
+     */
+    ssl_be_session_shutdown(&ssl->be);
+}
+void ssl_session_free(ssl_session_t *ssl) {
+    ssl_be_session_free(&ssl->be);
+
+    /* Check whether to free the credentials. */
+    if(--ssl->cred->ref == 0) {
+        if(ssl_cli_credlist != ssl->cred && ssl_srv_credlist != ssl->cred) {
+            ssl_cred_free(ssl->cred);
+        }
+    }
+
+    ssl_msg(SSL_DEBUG, "SSL: ssl_session_free(%u): done", ssl->cred->mode);
+    MyFree(ssl->fingerprint);
+    MyFree(ssl);
+}
+
+
+/* This handles a new client connection. It puts the client into the SSL queue and
+ * performs the SSL handshake. It either disconnects the client or passes the client
+ * to add_connection() after the handshake has been performed.
+ *
+ * We use two callbacks. One for the timeout and one for the socket. To prevent that
+ * both callbacks remove the ssl_pending_t structure or that they remove it too early
+ * we remove the structure only when the socket has been set to -1. This security check
+ * is needed, you should *NEVER* remove it.
+ */
+static void ssl_socket_callback(struct Event* ev) {
+    struct ssl_pending_t *pend;
+    unsigned int ret;
+
+    pend = s_data(ev_socket(ev));
+    switch(ev_type(ev)) {
+        case ET_DESTROY:
+            if(pend->fd == -1) MyFree(pend);
+            return;
+        case ET_ERROR:
+        case ET_EOF:
+            ssl_session_shutdown(pend->session);
+            close(pend->fd);
+            ssl_session_free(pend->session);
+            socket_del(&pend->socket);
+            timer_del(&pend->timeout);
+            /* Set fd to -1 to make ET_DESTROY free "pend". */
+            pend->fd = -1;
+            return;
+        case ET_READ:
+        case ET_WRITE:
+            /* Continue Handshake */
+            ret = ssl_be_handshake(pend->session->cred->mode, &pend->session->be);
+            if(ret == SSL_SUCCESS) {
+                pend->session->fingerprint = strdup(ssl_be_fingerprint(&pend->session->be));
+                timer_del(&pend->timeout);
+                socket_del(&pend->socket);
+                add_connection(pend->listener, pend->fd, pend->session);
+                /* Set fd to -1 to make ET_DESTROY free "pend". */
+                pend->fd = -1;
+                return;
+            }
+            else if(ret == SSL_NEED_RD) {
+                socket_events(&pend->socket, SOCK_ACTION_SET | SOCK_EVENT_READABLE);
+                return;
+            }
+            else if(ret == SSL_NEED_WR || ret == SSL_NEED_RDWR) {
+                socket_events(&pend->socket, SOCK_ACTION_SET | SOCK_EVENT_READABLE | SOCK_EVENT_WRITABLE);
+                return;
+            }
+            else /* SSL_FAILURE */ {
+                ssl_session_shutdown(pend->session);
+                close(pend->fd);
+                ssl_session_free(pend->session);
+                socket_del(&pend->socket);
+                timer_del(&pend->timeout);
+                /* Set fd to -1 to make ET_DESTROY free "pend". */
+                pend->fd = -1;
+                return;
+            }
+        default:
+            return;
+    }
+}
+static void ssl_timer_callback(struct Event* ev) {
+    struct ssl_pending_t *pend;
+
+    pend = t_data(ev_timer(ev));
+    switch(ev_type(ev)) {
+        case ET_DESTROY:
+            /* Decrease refcount here because this is guaranteed to be called when the
+             * connection gets destructed in any way.
+             */
+            --pend->listener->ref_count;
+            /* Destruct \pend if required. */
+            if(pend->fd == -1) MyFree(pend);
+            return;
+        case ET_EXPIRE:
+            ssl_session_shutdown(pend->session);
+            close(pend->fd);
+            ssl_session_free(pend->session);
+            socket_del(&pend->socket);
+            timer_del(&pend->timeout);
+            /* Set fd to -1 to make ET_DESTROY free "pend". */
+            pend->fd = -1;
+            return;
+        default:
+            return;
+    }
+}
+void ssl_accept(struct Listener *listener, signed int fd) {
+    unsigned int ret;
+    struct ssl_pending_t *pend;
+
+    if(!os_set_nonblocking(fd)) {
+        close(fd);
+        return;
+    }
+    os_disable_options(fd);
+
+    pend = MyMalloc(sizeof(struct ssl_pending_t));
+    pend->listener = listener;
+    pend->fd = fd;
+    pend->session = ssl_session_new(SSL_SERVER);
+
+    if(!pend->session) {
+        MyFree(pend);
+        close(fd);
+        ssl_msg(SSL_ERROR, "SSL: ssl_accept(%d): failed", fd);
+        return;
+    }
+
+    if(!socket_add(&pend->socket, ssl_socket_callback, (void*)pend, SS_CONNECTED, SOCK_EVENT_READABLE, fd)) {
+        ssl_session_shutdown(pend->session);
+        close(fd);
+        ssl_session_free(pend->session);
+        MyFree(pend);
+        ssl_msg(SSL_ERROR, "SSL: ssl_accept(%d): failed", fd);
+        return;
+    }
+
+    if(!ssl_be_session_connect(&pend->session->be, fd)) {
+        socket_del(&pend->socket);
+        ssl_session_shutdown(pend->session);
+        close(fd);
+        ssl_session_free(pend->session);
+        MyFree(pend);
+        ssl_msg(SSL_ERROR, "SSL: ssl_accept(%d): failed", fd);
+        return;
+    }
+
+    ret = ssl_be_handshake(pend->session->cred->mode, &pend->session->be);
+    if(ret == SSL_SUCCESS) {
+        pend->session->fingerprint = strdup(ssl_be_fingerprint(&pend->session->be));
+        socket_del(&pend->socket);
+        add_connection(pend->listener, pend->fd, pend->session);
+        MyFree(pend);
+        return;
+    }
+    else if(ret == SSL_NEED_RD || ret == SSL_NEED_WR || ret == SSL_NEED_RDWR) {
+        if(ret != SSL_NEED_RD) {
+            socket_events(&pend->socket, SOCK_ACTION_SET | SOCK_EVENT_READABLE | SOCK_EVENT_WRITABLE);
+        }
+        timer_init(&pend->timeout);
+        timer_add(&pend->timeout, ssl_timer_callback, (void*)pend, TT_RELATIVE, 20);
+        ++listener->ref_count;
+        return;
+    }
+    else /* SSL_FAILURE */ {
+        socket_del(&pend->socket);
+        ssl_session_shutdown(pend->session);
+        close(fd);
+        ssl_session_free(pend->session);
+        MyFree(pend);
+        ssl_msg(SSL_DEBUG, "SSL: ssl_accept(%d): failed", fd);
+        return;
+    }
+}
+static void ssl_csocket_callback(struct Event* ev) {
+    struct ssl_conn_t *conn;
+    unsigned int ret;
+
+    conn = s_data(ev_socket(ev));
+    switch(ev_type(ev)) {
+        case ET_DESTROY:
+            return;
+        case ET_ERROR:
+        case ET_EOF:
+            cli_socket(conn->cptr).s_header.gh_call = client_sock_callback;
+            s_data(&(cli_socket(conn->cptr))) = conn->olddata;
+            ssl_session_free(conn->session);
+            cli_socket(conn->cptr).ssl = NULL;
+            exit_client_msg(conn->cptr, conn->cptr, &me, "SSL connection timedout.");
+            sendto_opmask_butone(0, SNO_OLDSNO, "Connection failed to %s: SSL timeout.", cli_name(conn->cptr));
+            conn->cptr = NULL;
+            timer_del(&conn->timeout);
+            return;
+        case ET_READ:
+        case ET_WRITE:
+            /* Continue Handshake */
+            ret = ssl_be_handshake(conn->session->cred->mode, &conn->session->be);
+            if(ret == SSL_SUCCESS) {
+                cli_socket(conn->cptr).s_header.gh_call = client_sock_callback;
+                s_data(&(cli_socket(conn->cptr))) = conn->olddata;
+                conn->session->fingerprint = strdup(ssl_be_fingerprint(&conn->session->be));
+                if(completed_connection(conn->cptr) == 0) {
+                    ssl_session_free(conn->session);
+                    cli_socket(conn->cptr).ssl = NULL;
+                    exit_client_msg(conn->cptr, conn->cptr, &me, "SSL handshake rejected.");
+                }
+                conn->cptr = NULL;
+                timer_del(&conn->timeout);
+                return;
+            }
+            else if(ret == SSL_NEED_RD) {
+                socket_events(&cli_socket(conn->cptr), SOCK_ACTION_SET | SOCK_EVENT_READABLE);
+                return;
+            }
+            else if(ret == SSL_NEED_WR || ret == SSL_NEED_RDWR) {
+                socket_events(&cli_socket(conn->cptr), SOCK_ACTION_SET | SOCK_EVENT_READABLE | SOCK_EVENT_WRITABLE);
+                return;
+            }
+            else /* SSL_FAILURE */ {
+                cli_socket(conn->cptr).s_header.gh_call = client_sock_callback;
+                s_data(&(cli_socket(conn->cptr))) = conn->olddata;
+                ssl_session_free(conn->session);
+                cli_socket(conn->cptr).ssl = NULL;
+                exit_client_msg(conn->cptr, conn->cptr, &me, "SSL connection timedout.");
+                sendto_opmask_butone(0, SNO_OLDSNO, "Connection failed to %s: SSL timeout.", cli_name(conn->cptr));
+                conn->cptr = NULL;
+                timer_del(&conn->timeout);
+                return;
+            }
+        default:
+            return;
+    }
+}
+static void ssl_ctimer_callback(struct Event* ev) {
+    struct ssl_conn_t *conn;
+
+    conn = t_data(ev_timer(ev));
+    switch(ev_type(ev)) {
+        case ET_DESTROY:
+            if(conn->cptr == NULL) MyFree(conn);
+            return;
+        case ET_EXPIRE:
+            cli_socket(conn->cptr).s_header.gh_call = client_sock_callback;
+            s_data(&(cli_socket(conn->cptr))) = conn->olddata;
+            ssl_session_free(conn->session);
+            cli_socket(conn->cptr).ssl = NULL;
+            exit_client_msg(conn->cptr, conn->cptr, &me, "SSL connection timedout.");
+            sendto_opmask_butone(0, SNO_OLDSNO, "Connection failed to %s: SSL timeout.", cli_name(conn->cptr));
+            conn->cptr = NULL;
+            timer_del(&conn->timeout);
+            return;
+        default:
+            return;
+    }
+}
+signed int ssl_connect(struct Client *cptr) {
+    struct ssl_conn_t *conn;
+    unsigned int ret;
+    signed int tmp;
+
+    conn = MyMalloc(sizeof(struct ssl_conn_t));
+    memset(conn, 0, sizeof(struct ssl_conn_t));
+
+    conn->cptr = cptr;
+    conn->session = ssl_session_new(SSL_CLIENT);
+    cli_socket(cptr).ssl = conn->session;
+
+    if(!conn->session) {
+        cli_socket(cptr).ssl = NULL;
+        MyFree(conn);
+        ssl_msg(SSL_ERROR, "SSL: ssl_connect(): failed");
+        sendto_opmask_butone(0, SNO_OLDSNO, "Connection failed to %s: SSL session-creation failed.", cli_name(cptr));
+        return 0;
+    }
+
+    if(!ssl_be_session_connect(&conn->session->be, s_fd(&(cli_socket(cptr))))) {
+        cli_socket(cptr).ssl = NULL;
+        ssl_session_free(conn->session);
+        MyFree(conn);
+        ssl_msg(SSL_ERROR, "SSL: ssl_connect(): failed");
+        sendto_opmask_butone(0, SNO_OLDSNO, "Connection failed to %s: SSL fd-connect failed.", cli_name(cptr));
+        return 0;
+    }
+
+    ret = ssl_be_handshake(conn->session->cred->mode, &conn->session->be);
+    if(ret == SSL_SUCCESS) {
+        conn->session->fingerprint = strdup(ssl_be_fingerprint(&conn->session->be));
+        tmp = completed_connection(cptr);
+        MyFree(conn);
+        return tmp;
+    }
+    else if(ret == SSL_NEED_RD || ret == SSL_NEED_WR || ret == SSL_NEED_RDWR) {
+        if(ret == SSL_NEED_RD) {
+            socket_events(&cli_socket(cptr), SOCK_ACTION_SET | SOCK_EVENT_READABLE);
+        }
+        else {
+            socket_events(&cli_socket(cptr), SOCK_ACTION_SET | SOCK_EVENT_READABLE | SOCK_EVENT_WRITABLE);
+        }
+        /* Change callback temporarily to avoid ET_DESTROY on the old callback.
+         * We will change this back before ET_DESTROY is called.
+         */
+        cli_socket(cptr).s_header.gh_call = ssl_csocket_callback;
+        conn->olddata = s_data(&(cli_socket(cptr)));
+        s_data(&(cli_socket(cptr))) = conn;
+        timer_init(&conn->timeout);
+        timer_add(&conn->timeout, ssl_ctimer_callback, (void*)conn, TT_RELATIVE, 20);
+        return 1;
+    }
+    else /* SSL_FAILURE */ {
+        cli_socket(cptr).ssl = NULL;
+        ssl_session_free(conn->session);
+        MyFree(conn);
+        ssl_msg(SSL_ERROR, "SSL: ssl_connect(): failed");
+        sendto_opmask_butone(0, SNO_OLDSNO, "Connection failed to %s: SSL handshake failed.", cli_name(cptr));
+        return 0;
+    }
+    return 0;
+}
+
+
+/* Basic IO on SSL sockets. */
+void ssl_close(signed int fd, ssl_session_t *ssl, const char *buf, unsigned int len) {
+    if(!ssl) {
+        write(fd, buf, len);
+        close(fd);
+    }
+    else {
+        ssl_be_send(fd, &ssl->be, buf, &len);
+        ssl_session_shutdown(ssl);
+        close(fd);
+        ssl_session_free(ssl);
+    }
+}
+signed int ssl_send(signed int fd, ssl_session_t *ssl, const char *buf, unsigned int len) {
+    if(!ssl) {
+        return write(fd, buf, len);
+    }
+    else {
+        ssl_be_send(fd, &ssl->be, buf, &len);
+        return len;
+    }
+}
+IOResult ssl_recv(signed int fd, ssl_session_t *ssl, char *buf, unsigned int len, unsigned int *count_out) {
+    if(!ssl) {
+        return os_recv_nonb(fd, buf, len, count_out);
+    }
+    *count_out = len;
+    return ssl_be_recv(fd, &ssl->be, buf, count_out);
+}
+IOResult ssl_sendv(signed int fd, ssl_session_t *ssl, struct MsgQ *buf, unsigned int *count_in, unsigned int *count_out) {
+    #ifndef IOV_MAX
+        #define IOV_MAX 16
+    #endif /* IOV_MAX */
+    signed int count;
+    unsigned int k, tmp;
+    struct iovec iov[IOV_MAX];
+    IOResult ret = IO_BLOCKED, res;
+
+    if(!ssl) {
+        return os_sendv_nonb(fd, buf, count_in, count_out);
+    }
+
+    *count_in = 0;
+    *count_out = 0;
+    count = msgq_mapiov(buf, iov, IOV_MAX, count_in);
+
+    for(k = 0; k < count; ++k) {
+        tmp = iov[k].iov_len;
+        res = ssl_be_send(fd, &ssl->be, iov[k].iov_base, &tmp);
+        if(res == IO_FAILURE) return IO_FAILURE;
+        else if(tmp == 0) return ret;
+        else {
+            *count_out += tmp;
+            ret = IO_SUCCESS;
+        }
+    }
+    return ret;
+}
+const char *ssl_cipherstr(ssl_session_t *ssl) {
+    return ssl_be_cipherstr(&ssl->be);
+}
+
+
+
+
+/*******************************************************************************/
+/*******************************************************************************/
+/*******************************************************************************/
+/*******************************************************************************/
+/*******************************************************************************/
+/**********************            GnuTLS backend              *****************/
+/*******************************************************************************/
+/*******************************************************************************/
+/*******************************************************************************/
+/*******************************************************************************/
+/*******************************************************************************/
+
+
+
+
+#ifdef HAVE_GNUTLS
+    unsigned int ssl_be_init() {
+        signed int ret;
+        if((ret = gnutls_global_init()) != GNUTLS_E_SUCCESS) {
+            ssl_msg(SSL_ERROR, "SSL: gnutls_global_init(): failed (%d)", ret);
+            return 0;
+        }
+        else return 1;
+    }
+    void ssl_be_deinit() {
+        gnutls_global_deinit();
+    }
+    unsigned int ssl_be_cred_new(unsigned int mode, char *cert, char **trusts, ssl_be_cred_t *cred) {
+        signed int ret;
+        unsigned int i;
+        if((ret = gnutls_dh_params_init(&cred->dhparams)) != GNUTLS_E_SUCCESS) {
+            ssl_msg(SSL_ERROR, "SSL: gnutls_dh_params_init(): failed (%d)", ret);
+            return 0;
+        }
+        if((ret = gnutls_dh_params_generate2(cred->dhparams, SSL_DH_BITS)) != GNUTLS_E_SUCCESS) {
+            gnutls_dh_params_deinit(cred->dhparams);
+            ssl_msg(SSL_ERROR, "SSL: gnutls_dh_params_generate2(): failed (%d)", ret);
+            return 0;
+        }
+        if((ret = gnutls_certificate_allocate_credentials(&cred->cred)) != GNUTLS_E_SUCCESS) {
+            gnutls_dh_params_deinit(cred->dhparams);
+            ssl_msg(SSL_ERROR, "SSL: gnutls_certificate_allocate_credentials(): failed (%d)", ret);
+            return 0;
+        }
+        i = 0;
+        while(trusts[i]) {
+            if((ret = gnutls_certificate_set_x509_trust_file(cred->cred, trusts[i], GNUTLS_X509_FMT_PEM)) != GNUTLS_E_SUCCESS) {
+                ssl_msg(SSL_NOTICE, "SSL: gnutls_certificate_set_x509_trust_file('%s'): failed (%d)", trusts[i], ret);
+                /* ignore errors here */
+            }
+            ++i;
+        }
+        if((ret = gnutls_certificate_set_x509_key_file(cred->cred, cert, cert, GNUTLS_X509_FMT_PEM)) != GNUTLS_E_SUCCESS) {
+            gnutls_certificate_free_credentials(cred->cred);
+            gnutls_dh_params_deinit(cred->dhparams);
+            ssl_msg(SSL_NOTICE, "SSL: gnutls_certificate_set_x509_key_file('%s'): failed (%d)", cert, ret);
+            return 0;
+        }
+        gnutls_certificate_set_dh_params(cred->cred, cred->dhparams);
+        gnutls_priority_init(&cred->prio, "NORMAL", NULL);
+        return 1;
+    }
+    void ssl_be_cred_free(ssl_be_cred_t *cred) {
+        gnutls_certificate_free_credentials(cred->cred);
+        gnutls_priority_deinit(cred->prio);
+        gnutls_dh_params_deinit(cred->dhparams);
+    }
+    unsigned int ssl_be_session_new(unsigned int mode, ssl_be_cred_t *cred, ssl_be_session_t *session) {
+        signed int ret;
+        if(mode == SSL_CLIENT) {
+            if((ret = gnutls_init(session, GNUTLS_CLIENT)) != GNUTLS_E_SUCCESS) {
+                ssl_msg(SSL_ERROR, "SSL: gnutls_init(): failed (%d)", ret);
+                return 0;
+            }
+            gnutls_priority_set(*session, cred->prio);
+            /*if((ret = gnutls_priority_set_direct(*session, "NORMAL", NULL)) != GNUTLS_E_SUCCESS) {
+                gnutls_deinit(*session);
+                ssl_msg(SSL_ERROR, "SSL: gnutls_priority_set_direct(): failed (%d)", ret);
+                return 0;
+            }*/
+            if((ret = gnutls_credentials_set(*session, GNUTLS_CRD_CERTIFICATE, cred->cred)) != GNUTLS_E_SUCCESS) {
+                gnutls_deinit(*session);
+                ssl_msg(SSL_ERROR, "SSL: gnutls_credentials_set(): failed (%d)", ret);
+                return 0;
+            }
+            gnutls_dh_set_prime_bits(*session, SSL_DH_RBITS);
+        }
+        else {
+            if((ret = gnutls_init(session, GNUTLS_SERVER)) != GNUTLS_E_SUCCESS) {
+                ssl_msg(SSL_ERROR, "SSL: gnutls_init(): failed (%d)", ret);
+                return 0;
+            }
+            gnutls_priority_set(*session, cred->prio);
+            /*if((ret = gnutls_priority_set_direct(*session, "NORMAL", NULL)) != GNUTLS_E_SUCCESS) {
+                gnutls_deinit(*session);
+                ssl_msg(SSL_ERROR, "SSL: gnutls_priority_set_direct(): failed (%d)", ret);
+                return 0;
+            }*/
+            if((ret = gnutls_credentials_set(*session, GNUTLS_CRD_CERTIFICATE, cred->cred)) != GNUTLS_E_SUCCESS) {
+                gnutls_deinit(*session);
+                ssl_msg(SSL_ERROR, "SSL: gnutls_credentials_set(): failed (%d)", ret);
+                return 0;
+            }
+            gnutls_certificate_server_set_request(*session, GNUTLS_CERT_REQUEST);
+        }
+        return 1;
+    }
+    unsigned int ssl_be_session_connect(ssl_be_session_t *session, signed int fd) {
+        gnutls_transport_set_ptr(*session, (gnutls_transport_ptr_t)fd);
+        return 1;
+    }
+    void ssl_be_session_shutdown(ssl_be_session_t *session) {
+        gnutls_bye(*session, GNUTLS_SHUT_WR);
+    }
+    void ssl_be_session_free(ssl_be_session_t *session) {
+        gnutls_deinit(*session);
+    }
+    unsigned int ssl_be_handshake(unsigned int mode, ssl_be_session_t *session) {
+        signed int ret;
+        ret = gnutls_handshake(*session);
+        if(ret < 0) {
+            if(ret == GNUTLS_E_AGAIN || ret == GNUTLS_E_INTERRUPTED) {
+                if(gnutls_record_get_direction(*session) == 0) return SSL_NEED_RD;
+                else return SSL_NEED_WR;
+            }
+            else {
+                ssl_msg(SSL_DEBUG, "SSL: gnutls_handshake(): failed (%d)", ret);
+                return SSL_FAILURE;
+            }
+        }
+        else return SSL_SUCCESS;
+    }
+    const char *ssl_be_cipherstr(ssl_be_session_t *session) {
+        static char buf[401];
+        const char *kx_name, *cipher_name, *mac_name;
+        unsigned int len, i;
+        char *dest;
+
+        kx_name = gnutls_kx_get_name(gnutls_kx_get(*session));
+        cipher_name = gnutls_cipher_get_name(gnutls_cipher_get(*session));
+        mac_name = gnutls_mac_get_name(gnutls_mac_get(*session));
+
+        if(!kx_name || !cipher_name || !mac_name) {
+            ssl_msg(SSL_ERROR, "SSL: gnutls_[kx,cipher,mac]_get_name(): failed");
+            return "<invalid>";
+        }
+
+        len = strlen(kx_name) + strlen(cipher_name) + strlen(mac_name);
+        if(len > 395) {
+            ssl_msg(SSL_ERROR, "SSL: gnutls_[kx,cipher,mac]_get_name(): too long");
+            return "<invalid>";
+        }
+        else {
+            dest = buf;
+            i = 0;
+            while((*dest++ = kx_name[i++])) /* empty */ ;
+            *(dest - 1) = '-';
+            i = 0;
+            while((*dest++ = cipher_name[i++])) /* empty */ ;
+            *(dest - 1) = '-';
+            i = 0;
+            while((*dest++ = mac_name[i++])) /* empty */ ;
+            return buf;
+        }
+    }
+    const char *ssl_be_fingerprint(ssl_be_session_t *session) {
+        return "<invalid>";
+    }
+    IOResult ssl_be_send(signed int fd, ssl_be_session_t *ssl, const char *buf, unsigned int *count_out) {
+        signed int res;
+        res = gnutls_record_send(*ssl, buf, *count_out);
+        *count_out = 0;
+        if(res == 0) return IO_FAILURE;
+        else if(res < 0) {
+            if(res != GNUTLS_E_AGAIN && res != GNUTLS_E_INTERRUPTED) return IO_FAILURE;
+            else return IO_BLOCKED;
+        }
+        else {
+            *count_out = res;
+            return IO_SUCCESS;
+        }
+    }
+    IOResult ssl_be_recv(signed int fd, ssl_be_session_t *ssl, char *buf, unsigned int *count_out) {
+        signed int res;
+        res = gnutls_record_recv(*ssl, buf, *count_out);
+        *count_out = 0;
+        if(res == 0) return IO_FAILURE;
+        else if(res < 0) {
+            if(res == GNUTLS_E_AGAIN || res == GNUTLS_E_INTERRUPTED) return IO_BLOCKED;
+            else return IO_FAILURE;
+        }
+        else {
+            *count_out = res;
+            return IO_SUCCESS;
+        }
+    }
+
+
+
+
+/*******************************************************************************/
+/*******************************************************************************/
+/*******************************************************************************/
+/*******************************************************************************/
+/*******************************************************************************/
+/**********************            OpenSSL backend             *****************/
+/*******************************************************************************/
+/*******************************************************************************/
+/*******************************************************************************/
+/*******************************************************************************/
+/*******************************************************************************/
+
+
+
+
+#elif defined(HAVE_OPENSSL)
+    unsigned int ssl_be_init() {
+        SSL_library_init();
+        /* Load error strings; Returns void. */
+        SSL_load_error_strings();
+        /* Seed the random number generator. We do not care for errors here. */
+        RAND_load_file("/dev/urandom", 4096);
+        return 1;
+    }
+    void ssl_be_deinit() {
+        ERR_free_strings();
+    }
+    unsigned int ssl_be_cred_new(unsigned int mode, char *cert, char **trusts, ssl_be_cred_t *cred) {
+        if(mode == SSL_CLIENT) {
+            *cred = SSL_CTX_new(SSLv23_client_method());
+            if(!*cred) {
+                ssl_msg(SSL_ERROR, "SSL: SSL_CTX_new(): failed");
+                return 0;
+            }
+            if(*trusts) {
+                if(*(trusts + 1)) ssl_msg(SSL_NOTICE, "SSL: (OpenSSL) skipping further CA files");
+                if(!SSL_CTX_load_verify_locations(*cred, *trusts, NULL)) {
+                    ssl_msg(SSL_NOTICE, "SSL: SSL_CTX_load_verify_locations('%s'): failed", *trusts);
+                    /* ignore errors here */
+                }
+                else SSL_CTX_set_client_CA_list(*cred, SSL_load_client_CA_file(*trusts));
+            }
+            SSL_CTX_set_mode(*cred, SSL_MODE_ENABLE_PARTIAL_WRITE | SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
+            if(!SSL_CTX_use_certificate_file(*cred, cert, SSL_FILETYPE_PEM)) {
+                SSL_CTX_free(*cred);
+                ssl_msg(SSL_NOTICE, "SSL: SSL_CTX_use_certificate_file('%s'): failed", cert);
+                return 0;
+            }
+            if(!SSL_CTX_use_PrivateKey_file(*cred, cert, SSL_FILETYPE_PEM)) {
+                SSL_CTX_free(*cred);
+                ssl_msg(SSL_NOTICE, "SSL: SSL_CTX_use_PrivateKey_file('%s'): failed", cert);
+                return 0;
+            }
+            SSL_CTX_set_verify(*cred, SSL_VERIFY_PEER | SSL_VERIFY_CLIENT_ONCE, ssl_be_verify);
+        }
+        else {
+            *cred = SSL_CTX_new(SSLv23_server_method());
+            if(!*cred) {
+                ssl_msg(SSL_ERROR, "SSL: SSL_CTX_new(): failed");
+                return 0;
+            }
+            SSL_CTX_set_mode(*cred, SSL_MODE_ENABLE_PARTIAL_WRITE | SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
+            if(!SSL_CTX_use_certificate_file(*cred, cert, SSL_FILETYPE_PEM)) {
+                SSL_CTX_free(*cred);
+                ssl_msg(SSL_NOTICE, "SSL: SSL_CTX_use_certificate_file('%s'): failed", cert);
+                return 0;
+            }
+            if(!SSL_CTX_use_PrivateKey_file(*cred, cert, SSL_FILETYPE_PEM)) {
+                SSL_CTX_free(*cred);
+                ssl_msg(SSL_NOTICE, "SSL: SSL_CTX_use_PrivateKey_file('%s'): failed", cert);
+                return 0;
+            }
+        }
+        return 1;
+    }
+    void ssl_be_cred_free(ssl_be_cred_t *cred) {
+        SSL_CTX_free(*cred);
+    }
+    unsigned int ssl_be_session_new(unsigned int mode, ssl_be_cred_t *cred, ssl_be_session_t *session) {
+        *session = SSL_new(*cred);
+        if(!*session) {
+            ssl_msg(SSL_ERROR, "SSL: SSL_new(%u): failed", mode);
+            return 0;
+        }
+        return 1;
+    }
+    unsigned int ssl_be_session_connect(ssl_be_session_t *session, signed int fd) {
+        SSL_set_fd(*session, fd);
+        return 1;
+    }
+    void ssl_be_session_shutdown(ssl_be_session_t *session) {
+        SSL_shutdown(*session);
+    }
+    void ssl_be_session_free(ssl_be_session_t *session) {
+        SSL_free(*session);
+    }
+    unsigned int ssl_be_handshake(unsigned int mode, ssl_be_session_t *session) {
+        signed int ret;
+        if(mode == SSL_CLIENT) ret = SSL_connect(*session);
+        else ret = SSL_accept(*session);
+        if(ret <= 0) {
+            ret = SSL_get_error(*session, ret);
+            if(ret == SSL_ERROR_WANT_READ || ret == SSL_ERROR_WANT_WRITE) {
+                if(ret == SSL_ERROR_WANT_READ) return SSL_NEED_RD;
+                else return SSL_NEED_WR;
+            }
+            else {
+                ssl_msg(SSL_DEBUG, "SSL: gnutls_handshake(): failed (%d)", ret);
+                return SSL_FAILURE;
+            }
+        }
+        else return SSL_SUCCESS;
+    }
+    const char *ssl_be_cipherstr(ssl_be_session_t *session) {
+        static char buf[400];
+        char buf2[128];
+        int bits;
+        SSL_CIPHER *c;
+
+        buf[0] = '\0';
+        strcpy(buf, SSL_get_version(*session));
+        strcat(buf, "-");
+        strcat(buf, SSL_get_cipher(*session));
+        c = SSL_get_current_cipher(*session);
+        SSL_CIPHER_get_bits(c, &bits);
+        strcat(buf, "-");
+        ircd_snprintf(0, buf2, sizeof(buf2), "%d", bits);
+        strcat(buf, buf2);
+        strcat(buf, "bits");
+        return buf;
+    }
+    const char *ssl_be_fingerprint(ssl_be_session_t *session) {
+        return "<invalid>";
+    }
+    IOResult ssl_be_send(signed int fd, ssl_be_session_t *ssl, const char *buf, unsigned int *count_out) {
+        signed int res, merrno;
+
+#ifdef SSL_EAGAIN_DEBUG
+        signed int back, back_c;
+        char buffer[4097];
+#endif
+
+        res = SSL_write(*ssl, buf, *count_out);
+        merrno = errno;
+
+#ifdef SSL_EAGAIN_DEBUG
+        back_c = *count_out;
+#endif
+
+        *count_out = 0;
+        if(res == 0) return IO_FAILURE;
+        else if(res < 0) {
+#ifdef SSL_EAGAIN_DEBUG
+            back = res;
+#endif
+            res = SSL_get_error(*ssl, res);
+            /* HACK HACK HACK!
+             * OpenSSL sucks! This hack still returns IO_BLOCKED on special SYSCALL failures.
+             * The ircd system is built that the user will be killed automatically when this
+             * happens too often so we can safely return this here, however, the OpenSSL devs
+             * should *REALLY* fix this. They're already noticed.
+             * --gix
+             */
+            if(res != SSL_ERROR_WANT_READ && res != SSL_ERROR_WANT_WRITE && res != SSL_ERROR_WANT_X509_LOOKUP) {
+                if(merrno == EAGAIN || merrno == EINTR || merrno == EWOULDBLOCK || merrno == EBUSY) {
+#ifdef SSL_EAGAIN_DEBUG
+                    snprintf(buffer, (back_c > 4096)?4096:back_c, "%s", buf);
+                    buffer[4096] = 0;
+                    ssl_msg(SSL_NOTICE, "OpenSSL: EAGAIN debug information: fd (%d) err (%d) serr (%d) "
+                                        "derr1 (%lu) derr2 (%lu) back (%d) len (%u) buf (%s)",
+                                        fd, merrno, res, ERR_peek_error(), ERR_peek_last_error(), back, back_c, buffer);
+#endif
+                    return IO_BLOCKED;
+                }
+                return IO_FAILURE;
+            }
+            else return IO_BLOCKED;
+        }
+        else {
+            *count_out = res;
+            return IO_SUCCESS;
+        }
+    }
+    IOResult ssl_be_recv(signed int fd, ssl_be_session_t *ssl, char *buf, unsigned int *count_out) {
+        signed int res, merrno;
+        res = SSL_read(*ssl, buf, *count_out);
+        merrno = errno;
+        *count_out = 0;
+        if(res == 0) return IO_FAILURE;
+        else if(res < 0) {
+            res = SSL_get_error(*ssl, res);
+            if(res == SSL_ERROR_WANT_READ || res == SSL_ERROR_WANT_WRITE || res == SSL_ERROR_WANT_X509_LOOKUP) return IO_BLOCKED;
+            /* HACK HACK HACK!
+             * OpenSSL sucks! This hack still returns IO_BLOCKED on special SYSCALL failures.
+             * The ircd system is built that the user will be killed automatically when this
+             * happens too often so we can safely return this here, however, the OpenSSL devs
+             * should *REALLY* fix this. They're already noticed.
+             * --gix
+             */
+            else if(merrno == EAGAIN || merrno == EINTR || merrno == EWOULDBLOCK || merrno == EBUSY) return IO_BLOCKED;
+            else return IO_FAILURE;
+        }
+        else {
+            *count_out = res;
+            return IO_SUCCESS;
+        }
+    }
+    static signed int ssl_be_verify(signed int preverify_ok, X509_STORE_CTX *ctx) {
+        return 1;
+    }
+
+
+
+
+/*******************************************************************************/
+/*******************************************************************************/
+/*******************************************************************************/
+/*******************************************************************************/
+/*******************************************************************************/
+/**********************             Dummy backend              *****************/
+/*******************************************************************************/
+/*******************************************************************************/
+/*******************************************************************************/
+/*******************************************************************************/
+/*******************************************************************************/
+
+
+
+
+#else
+    unsigned int ssl_be_init() {
+        return 1;
+    }
+    void ssl_be_deinit() {
+        return;
+    }
+    unsigned int ssl_be_cred_new(unsigned int mode, char *cert, char **trusts, ssl_be_cred_t *cred) {
+        *cred = NULL;
+        return 1;
+    }
+    void ssl_be_cred_free(ssl_be_cred_t *cred) {
+        return;
+    }
+    unsigned int ssl_be_session_new(unsigned int mode, ssl_be_cred_t *cred, ssl_be_session_t *session) {
+        *session = NULL;
+        return 1;
+    }
+    unsigned int ssl_be_session_connect(ssl_be_session_t *session, signed int fd) {
+        return 1;
+    }
+    void ssl_be_session_shutdown(ssl_be_session_t *session) {
+        return;
+    }
+    void ssl_be_session_free(ssl_be_session_t *session) {
+        return;
+    }
+    unsigned int ssl_be_handshake(unsigned int mode, ssl_be_session_t *session) {
+        return SSL_FAILURE;
+    }
+    const char *ssl_be_cipherstr(ssl_be_session_t *session) {
+        return "PLAINTEXT";
+    }
+    const char *ssl_be_fingerprint(ssl_be_session_t *session) {
+        return "<invalid>";
+    }
+    IOResult ssl_be_send(signed int fd, ssl_be_session_t *ssl, const char *buf, unsigned int *count_out) {
+        return IO_FAILURE;
+    }
+    IOResult ssl_be_recv(signed int fd, ssl_be_session_t *ssl, char *buf, unsigned int *count_out) {
+        return IO_FAILURE;
+    }
+#endif
+
diff --git a/ircd/table_gen.c b/ircd/table_gen.c
new file mode 100644 (file)
index 0000000..6fe5cd5
--- /dev/null
@@ -0,0 +1,349 @@
+/*
+ * IRC - Internet Relay Chat, include/common.c
+ * Copyright (C) 1998 Andrea Cocito
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/*
+ * TABLE GENERATOR
+ * The following part of code is NOT included in the actual server's
+ * or library source, it's just used to build the above tables
+ *
+ * This should rebuild the actual tables and automatically place them
+ * into this source file, note that this part of code is for developers
+ * only, it's supposed to work on both signed and unsigned chars but I
+ * actually tested it only on signed-char architectures, the code and
+ * macros actually used by the server instead DO work and have been tested
+ * on platforms where0 char is both signed or unsigned, this is true as long
+ * as the <limits.h> macros are set properly and without any need to rebuild
+ * the tables (which as said an admin should NEVER do, tables need to be rebuilt
+ * only when one wants to really change the results or when one has to
+ * compile on architectures where a char is NOT eight bits [?!], yes
+ * it all is supposed to work in that case too... but I can't test it
+ * because I've not found a machine in the world where this happens).
+ *
+ * NEVER -f[un]signed-char on gcc since that does NOT fix the named macros
+ * and you end up in a non-ANSI environment where CHAR_MIN and CHAR_MAX
+ * are _not_ the real limits of a default 'char' type. This is true for
+ * both admins and coders.
+ *
+ */
+#include "config.h"
+
+#include "ircd_chattr.h"
+#include <stdlib.h>
+#include <stdio.h>
+#include <ctype.h>
+
+
+static void zeroTables(void);
+static void markString(int macro, const char *s);
+static void unMarkString(int macro, const char *s);
+static void markRange(int macro, char from, char to);
+static void moveMacro(int from, int to);
+static void setLowHi(const char firstlow, const char lastlow,
+    const char firsthi);
+
+char NTL_tolower_tab[1 + CHAR_MAX - CHAR_MIN]; /* 256 bytes */
+char NTL_toupper_tab[1 + CHAR_MAX - CHAR_MIN]; /* 256 bytes */
+int NTL_char_attrib[1 + CHAR_MAX - CHAR_MIN];  /* 256 ints = 0.5 to 2 kilobytes */
+
+/*
+ * makeTables() 
+ * Where we make the tables, edit ONLY this to change the tables.
+ */
+
+static void makeTables(void)
+{
+
+  /* Start from a known status */
+  zeroTables();
+
+  /* Make the very elementary sets */
+  markRange(NTL_LOWER, 'a', 'z');
+  markString(NTL_LOWER, "{|}~");
+
+  markRange(NTL_UPPER, 'A', 'Z');
+  markString(NTL_UPPER, "[\\]^");
+
+  markRange(NTL_DIGIT, '0', '9');
+
+  markRange(NTL_CNTRL, '\000', '\037');
+
+  markString(NTL_PUNCT, "!\"#$%&'()*+,-./:;<=>?@_`");
+
+  markString(NTL_SPACE, "\011\012\013\014\015\040");
+
+  /* Make the derived sets, 
+   * WARNING: The order of these calls is important, some depend on 
+   * the results of the previous ones ! */
+
+  moveMacro(NTL_LOWER | NTL_UPPER, NTL_ALPHA);
+  moveMacro(NTL_ALPHA | NTL_DIGIT, NTL_ALNUM);
+  moveMacro(NTL_ALNUM | NTL_PUNCT, NTL_GRAPH);
+
+  moveMacro(NTL_GRAPH, NTL_PRINT);
+  markString(NTL_PRINT, " ");
+
+  markRange(NTL_IRCCH, '\041', (char) UCHAR_MAX);
+  unMarkString(NTL_IRCCH, "\054\240");
+
+  markRange(NTL_IRCCL, '\300', '\326');
+  markRange(NTL_IRCCL, '\330', '\336');
+
+  moveMacro(NTL_ALNUM, NTL_IRCHN);
+  markString(NTL_IRCHN, "-_.");        /* Some DNS might allow '_' per RFC 1033 ! */
+
+  moveMacro(NTL_DIGIT, NTL_IRCIP);
+  markString(NTL_IRCIP, ".");
+
+  moveMacro(NTL_DIGIT, NTL_IRCIP6);
+  markString(NTL_IRCIP6, ":.ABCDEFabcdef");
+
+  moveMacro(NTL_DIGIT | NTL_ALPHA, NTL_IRCNK);
+  markString(NTL_IRCNK, "-_`");
+
+  moveMacro(NTL_ALNUM, NTL_IRCUI);
+  markRange(NTL_IRCUI, '\xe0', '\xf6');
+  markRange(NTL_IRCUI, '\xf8', '\xfe');
+  markRange(NTL_IRCUI, '\xc0', '\xd6');
+  markRange(NTL_IRCUI, '\xd8', '\xde');
+  markString(NTL_IRCUI, ".-_^'`~");
+  markString(NTL_EOL, "\n\r");
+  markString(NTL_CHPFX, "#&");
+  markString(NTL_KTIME, " ,-0123456789");
+
+  /* And finally let's take care of the toLower/toUpper stuff */
+
+  setLowHi('a', 'z', 'A');
+  setLowHi('\xe0', '\xf6', '\xc0');
+  setLowHi('\xf8', '\xfe', '\xd8');
+  setLowHi('{', '~', '[');
+}
+
+/* 
+ * main()
+ * This is the main program to be executed for -DMAKETABLES
+ */
+
+static void dumphw(int *p, int beg);
+static void dumphb(char *p, int beg);
+
+int main(void)
+{
+  int i;
+
+  /* Make the tables */
+  makeTables();
+
+  /* Dump them as ANSI C source to be included below */
+  printf("/*\n * Automatically Generated Tables - DO NOT EDIT\n */\n");
+  printf("#include <limits.h>\n");
+
+  /* NTL_tolower_tab */
+  printf("const char ToLowerTab_8859_1[] = {\n");
+  printf("#if (CHAR_MIN<0)\n");
+  i = (int)((char)SCHAR_MIN);
+  dumphb(NTL_tolower_tab, i);
+  printf("                ,\n");
+  printf("#endif /* (CHAR_MIN<0) */\n");
+  i = 0;
+  dumphb(NTL_tolower_tab, i);
+  printf("#if (!(CHAR_MIN<0))\n");
+  printf("                ,\n");
+  i = (int)((char)SCHAR_MIN);
+  dumphb(NTL_tolower_tab, i);
+  printf("#endif /* (!(CHAR_MIN<0)) */\n");
+  printf("  };\n\n");
+
+  /* NTL_toupper_tab */
+  printf("const char ToUpperTab_8859_1[] = {\n");
+  printf("#if (CHAR_MIN<0)\n");
+  i = (int)((char)SCHAR_MIN);
+  dumphb(NTL_toupper_tab, i);
+  printf("                ,\n");
+  printf("#endif /* (CHAR_MIN<0) */\n");
+  i = 0;
+  dumphb(NTL_toupper_tab, i);
+  printf("#if (!(CHAR_MIN<0))\n");
+  printf("                ,\n");
+  i = (int)((char)SCHAR_MIN);
+  dumphb(NTL_toupper_tab, i);
+  printf("#endif /* (!(CHAR_MIN<0)) */\n");
+  printf("  };\n\n");
+
+  /* NTL_char_attrib */
+  printf("const unsigned int IRCD_CharAttrTab[] = {\n");
+  printf("#if (CHAR_MIN<0)\n");
+  i = (int)((char)SCHAR_MIN);
+  dumphw(NTL_char_attrib, i);
+  printf("                ,\n");
+  printf("#endif /* (CHAR_MIN<0) */\n");
+  i = 0;
+  dumphw(NTL_char_attrib, i);
+  printf("#if (!(CHAR_MIN<0))\n");
+  printf("                ,\n");
+  i = (int)((char)SCHAR_MIN);
+  dumphw(NTL_char_attrib, i);
+  printf("#endif /* (!(CHAR_MIN<0)) */\n");
+  printf("  };\n\n");
+
+  return 0;
+
+}
+
+/* A few utility functions for makeTables() */
+
+static void zeroTables(void)
+{
+  int i;
+  for (i = CHAR_MIN; i <= CHAR_MAX; i++)
+  {
+    NTL_tolower_tab[i - CHAR_MIN] = (char)i;   /* Unchanged */
+    NTL_toupper_tab[i - CHAR_MIN] = (char)i;   /* Unchanged */
+    NTL_char_attrib[i - CHAR_MIN] = 0x0000;    /* Nothing */
+  }
+}
+
+static void markString(int macro, const char *s)
+{
+  while (*s)
+    NTL_char_attrib[*(s++) - CHAR_MIN] |= macro;
+}
+
+static void unMarkString(int macro, const char *s)
+{
+  while (*s)
+    NTL_char_attrib[*(s++) - CHAR_MIN] &= ~macro;
+}
+
+static void markRange(int macro, char from, char to)
+{
+  int i;
+  for (i = CHAR_MIN; i <= CHAR_MAX; i++)
+    if (((unsigned char)i >= (unsigned char)from)
+       && ((unsigned char)i <= (unsigned char)to))
+      NTL_char_attrib[(char)i - CHAR_MIN] |= macro;
+}
+
+static void moveMacro(int from, int to)
+{
+  int i;
+  for (i = CHAR_MIN; i <= CHAR_MAX; i++)
+    if (NTL_char_attrib[i - CHAR_MIN] & from)
+      NTL_char_attrib[i - CHAR_MIN] |= to;
+}
+
+static void setLowHi(const char firstlow, const char lastlow,
+    const char firsthi)
+{
+  int i, j;
+  for (i = CHAR_MIN; i <= CHAR_MAX; i++)
+    if (((unsigned char)i >= (unsigned char)firstlow)
+       && ((unsigned char)i <= (unsigned char)lastlow))
+    {
+      j = ((int)((char)(i + (int)(firsthi - firstlow))));
+      NTL_tolower_tab[((char)j) - CHAR_MIN] = (char)i;
+      NTL_toupper_tab[((char)i) - CHAR_MIN] = (char)j;
+    }
+}
+
+/* These are used in main() to actually dump the tables, each function
+   dumps half table as hex/char constants... */
+
+#define ROWSIZE 8
+
+static void dumphb(char *tbl, int beg)
+{
+  int i, j, k;
+  char *p = &tbl[beg - CHAR_MIN];
+  unsigned char c;
+  for (i = 0; i <= SCHAR_MAX; i += ROWSIZE)
+  {
+    k = i + ROWSIZE - 1;
+    if (k > SCHAR_MAX)
+      k = SCHAR_MAX;
+
+    c = (unsigned char)(beg + i);
+    printf("/*");
+    if ((c > 0) && (c < SCHAR_MAX) && (isprint(c)) && (c != '\\')
+       && (c != '\''))
+      printf(" '%c'", c);
+    else
+      printf(" x%02x", ((int)c));
+
+    c = (unsigned char)(beg + k);
+    printf("-");
+    if ((c > 0) && (c < SCHAR_MAX) && (isprint(c)) && (c != '\\')
+       && (c != '\''))
+      printf("'%c'", c);
+    else
+      printf("x%02x", ((int)c));
+    printf(" */");
+
+    for (j = i; j <= k; j++)
+    {
+      c = p[j];
+      if ((c > 0) && (c < SCHAR_MAX) && (isprint(c)) && (c != '\\')
+         && (c != '\''))
+       printf("    '%c'", c);
+      else
+       printf(" '\\x%02x'", ((int)c));
+      if (j < SCHAR_MAX)
+       printf(",");
+    }
+    printf("\n");
+  }
+}
+
+static void dumphw(int *tbl, int beg)
+{
+  int i, j, k;
+  int *p = &tbl[beg - CHAR_MIN];
+  unsigned char c;
+  for (i = 0; i <= SCHAR_MAX; i += ROWSIZE)
+  {
+    k = i + ROWSIZE - 1;
+    if (k > SCHAR_MAX)
+      k = SCHAR_MAX;
+
+    c = (unsigned char)(beg + i);
+    printf("/*");
+    if ((c > 0) && (c < SCHAR_MAX) && (isprint(c)) && (c != '\\')
+       && (c != '\''))
+      printf(" '%c'", c);
+    else
+      printf(" x%02x", ((int)c));
+
+    c = (unsigned char)(beg + k);
+    printf("-");
+    if ((c > 0) && (c < SCHAR_MAX) && (isprint(c)) && (c != '\\')
+       && (c != '\''))
+      printf("'%c'", c);
+    else
+      printf("x%02x", ((int)c));
+    printf(" */");
+
+    for (j = i; j <= k; j++)
+    {
+      printf(" 0x%04x", p[j] & 0xffffffff);
+      if (j < SCHAR_MAX)
+       printf(",");
+    }
+    printf("\n");
+  }
+}
+
diff --git a/ircd/test/Makefile b/ircd/test/Makefile
new file mode 100644 (file)
index 0000000..05aa544
--- /dev/null
@@ -0,0 +1,81 @@
+top_srcdir = ../..
+srcdir = .
+
+CPPFLAGS = -I${top_srcdir}/include -I../..
+CFLAGS   = -g -Wall
+LDFLAGS  =
+CC = gcc
+
+TESTPROGS = \
+       ircd_chattr_t \
+       ircd_in_addr_t \
+       ircd_match_t \
+       ircd_string_t
+
+DEP_SRC = \
+       ircd_chattr_t.c \
+       ircd_in_addr_t.c \
+       ircd_match_t.c \
+       ircd_string_t.c \
+       test_stub.c
+
+all: ${TESTPROGS}
+
+build: ${TESTPROGS}
+
+depend: ${DEP_SRC}
+       @cd ${srcdir} && \
+       if [ -f Makefile.in.bak ]; then \
+         echo "make depend: First remove ircd/Makefile.in.bak"; \
+       else \
+         mv Makefile.in Makefile.in.bak && \
+         grep -A1 -B10000 '^# DO NOT DELETE THIS LINE' Makefile.in.bak > Makefile.in && \
+         ${CC} ${CFLAGS} -MM ${CPPFLAGS} ${DEP_SRC} >> Makefile.in; \
+       fi
+
+install:
+
+IRCD_CHATTR_T_OBJS = ircd_chattr_t.o test_stub.o ../ircd_string.o
+ircd_chattr_t: $(IRCD_CHATTR_T_OBJS)
+       ${CC} -o $@ $(LDFLAGS) $(IRCD_CHATTR_T_OBJS)
+
+IRCD_IN_ADDR_T_OBJS = ircd_in_addr_t.o test_stub.o ../ircd_alloc.o ../ircd_string.o ../match.o ../numnicks.o
+ircd_in_addr_t: $(IRCD_IN_ADDR_T_OBJS)
+       ${CC} -o $@ $(LDFLAGS) $(IRCD_IN_ADDR_T_OBJS)
+
+IRCD_MATCH_T_OBJS = ircd_match_t.o test_stub.o ../ircd_string.o ../match.o
+ircd_match_t: $(IRCD_MATCH_T_OBJS)
+       ${CC} -o $@ $(LDFLAGS) $(IRCD_MATCH_T_OBJS)
+
+IRCD_STRING_T_OBJS = ircd_string_t.o test_stub.o ../ircd_string.o
+ircd_string_t: $(IRCD_STRING_T_OBJS)
+       ${CC} -o $@ $(LDFLAGS) $(IRCD_STRING_T_OBJS)
+
+.c.o:
+       ${CC} ${CFLAGS} ${CPPFLAGS} -c $< -o $@
+
+.PHONY: distclean clean
+
+distclean: clean
+       rm -f Makefile
+
+clean:
+       rm -f core *.o *.log ${TESTPROGS}
+
+# DO NOT DELETE THIS LINE (or the blank line after it) -- make depend depends on them.
+
+ircd_chattr_t.o: ircd_chattr_t.c ../../include/ircd_chattr.h
+ircd_in_addr_t.o: ircd_in_addr_t.c ../../include/ircd_log.h \
+  ../../include/ircd_string.h ../../include/ircd_chattr.h \
+  ../../include/numnicks.h ../../include/client.h \
+  ../../include/ircd_defs.h ../../include/dbuf.h ../../include/msgq.h \
+  ../../include/ircd_events.h ../../config.h ../../include/ircd_handler.h \
+  ../../include/res.h ../../include/capab.h ../../include/res.h
+ircd_match_t.o: ircd_match_t.c ../../include/ircd_log.h \
+  ../../include/match.h ../../include/res.h ../../config.h
+ircd_string_t.o: ircd_string_t.c ../../include/ircd_string.h \
+  ../../include/ircd_chattr.h
+test_stub.o: test_stub.c ../../include/client.h ../../include/ircd_defs.h \
+  ../../include/dbuf.h ../../include/msgq.h ../../include/ircd_events.h \
+  ../../config.h ../../include/ircd_handler.h ../../include/res.h \
+  ../../include/capab.h ../../include/ircd_log.h ../../include/s_debug.h
diff --git a/ircd/test/Makefile.in b/ircd/test/Makefile.in
new file mode 100644 (file)
index 0000000..e0ea0ac
--- /dev/null
@@ -0,0 +1,81 @@
+top_srcdir = @top_srcdir@
+srcdir = @srcdir@
+VPATH = @srcdir@
+CPPFLAGS = -I${top_srcdir}/include -I../..
+CFLAGS   = -g -Wall
+LDFLAGS  =
+CC = @CC@
+
+TESTPROGS = \
+       ircd_chattr_t \
+       ircd_in_addr_t \
+       ircd_match_t \
+       ircd_string_t
+
+DEP_SRC = \
+       ircd_chattr_t.c \
+       ircd_in_addr_t.c \
+       ircd_match_t.c \
+       ircd_string_t.c \
+       test_stub.c
+
+all: ${TESTPROGS}
+
+build: ${TESTPROGS}
+
+depend: ${DEP_SRC}
+       @cd ${srcdir} && \
+       if [ -f Makefile.in.bak ]; then \
+         echo "make depend: First remove ircd/Makefile.in.bak"; \
+       else \
+         mv Makefile.in Makefile.in.bak && \
+         grep -A1 -B10000 '^# DO NOT DELETE THIS LINE' Makefile.in.bak > Makefile.in && \
+         ${CC} ${CFLAGS} -MM ${CPPFLAGS} ${DEP_SRC} >> Makefile.in; \
+       fi
+
+install:
+
+IRCD_CHATTR_T_OBJS = ircd_chattr_t.o test_stub.o ../ircd_string.o
+ircd_chattr_t: $(IRCD_CHATTR_T_OBJS)
+       ${CC} -o $@ $(LDFLAGS) $(IRCD_CHATTR_T_OBJS)
+
+IRCD_IN_ADDR_T_OBJS = ircd_in_addr_t.o test_stub.o ../ircd_alloc.o ../ircd_string.o ../match.o ../numnicks.o
+ircd_in_addr_t: $(IRCD_IN_ADDR_T_OBJS)
+       ${CC} -o $@ $(LDFLAGS) $(IRCD_IN_ADDR_T_OBJS)
+
+IRCD_MATCH_T_OBJS = ircd_match_t.o test_stub.o ../ircd_string.o ../match.o
+ircd_match_t: $(IRCD_MATCH_T_OBJS)
+       ${CC} -o $@ $(LDFLAGS) $(IRCD_MATCH_T_OBJS)
+
+IRCD_STRING_T_OBJS = ircd_string_t.o test_stub.o ../ircd_string.o
+ircd_string_t: $(IRCD_STRING_T_OBJS)
+       ${CC} -o $@ $(LDFLAGS) $(IRCD_STRING_T_OBJS)
+
+.c.o:
+       ${CC} ${CFLAGS} ${CPPFLAGS} -c $< -o $@
+
+.PHONY: distclean clean
+
+distclean: clean
+       rm -f Makefile
+
+clean:
+       rm -f core *.o *.log ${TESTPROGS}
+
+# DO NOT DELETE THIS LINE (or the blank line after it) -- make depend depends on them.
+
+ircd_chattr_t.o: ircd_chattr_t.c ../../include/ircd_chattr.h
+ircd_in_addr_t.o: ircd_in_addr_t.c ../../include/ircd_log.h \
+  ../../include/ircd_string.h ../../include/ircd_chattr.h \
+  ../../include/numnicks.h ../../include/client.h \
+  ../../include/ircd_defs.h ../../include/dbuf.h ../../include/msgq.h \
+  ../../include/ircd_events.h ../../config.h ../../include/ircd_handler.h \
+  ../../include/res.h ../../include/capab.h ../../include/res.h
+ircd_match_t.o: ircd_match_t.c ../../include/ircd_log.h \
+  ../../include/match.h ../../include/res.h ../../config.h
+ircd_string_t.o: ircd_string_t.c ../../include/ircd_string.h \
+  ../../include/ircd_chattr.h
+test_stub.o: test_stub.c ../../include/client.h ../../include/ircd_defs.h \
+  ../../include/dbuf.h ../../include/msgq.h ../../include/ircd_events.h \
+  ../../config.h ../../include/ircd_handler.h ../../include/res.h \
+  ../../include/capab.h ../../include/ircd_log.h ../../include/s_debug.h
diff --git a/ircd/test/channel-1.cmd b/ircd/test/channel-1.cmd
new file mode 100644 (file)
index 0000000..54efbb3
--- /dev/null
@@ -0,0 +1,74 @@
+define srv localhost
+
+connect cl1 Alex alex %srv%:7701 :Test client 1
+connect cl2 Bubb bubb %srv%:7711 :Test client 2
+:cl1 join #test
+:cl1 join #test2
+:cl1 mode #test +bb *!*@127.0.0.1 *!*@127.0.0.2
+:cl2 wait cl1
+:cl2 raw :away :I'm not here, go away.  I'm not here, go away.  I'm not here, go away.  I'm not here, go away.  I'm not here, go away.  I'm not here, go away.  I'm not here, go away.  I'm not here, go away.  I'm not here, go away.  I'm not here, go away.
+:cl2 raw :away :I'm not here, go away.
+:cl2 join #test,#test3,#test4,+local
+:cl1 wait cl2
+:cl1 join #test3
+:cl1 raw :invite Bubb
+:cl1 raw :invite #test
+:cl1 invite Bubb #non-existent-channel
+:cl1 invite Bubb #test3
+:cl1 invite Bubb #test4
+:cl1 invite Bubb #test
+:cl2 expect *cl1 invite #test
+:cl2 mode #test3 +o Alex
+:cl2 raw :invite
+:cl2 join #test
+:cl2 privmsg #test :Hello, *cl1.
+:cl2 notice #test :Hello, *cl1 (via notice).
+:cl2 notice @#test :Hello, *cl1 (via wallchops).
+:cl2 privmsg #test5 :Hello, *cl1.
+:cl2 nick Buba
+:cl2 mode #test +l 15
+:cl1 wait cl2
+:cl1 privmsg #test :Hello, *cl2.
+:cl1 raw :cprivmsg bubb #test :Hello, bubb.
+:cl1 raw :cnotice bubb #test :Hello, bubb.
+:cl1 mode #test -b+kv *!*@127.0.0.1 secret Bubb
+:cl1 mode #test +b foo!bar@baz
+:cl1 mode #test +b
+:cl1 mode #test :
+:cl1 mode #test
+:cl1 raw :names
+:cl1 raw :names #test
+:cl1 raw :names +local
+:cl1 raw :names +local test-2.*
+:cl1 raw :who #test %lfuh
+:cl2 wait cl1
+:cl2 raw :part
+:cl2 part #test
+:cl2 part #test5
+:cl1 wait cl2
+:cl2 join #test public
+:cl2 join #test secret
+:cl1 join 0
+:cl1 join #test2
+:cl2 wait cl1
+:cl2 join #test2
+:cl1 wait cl2
+:cl1 mode #test2 +smtinrDlAU 15 apples oranges
+:cl1 mode #test2
+:cl2 wait cl1
+:cl2 join #test2 apples
+:cl2 privmsg #test2 :Hello, oplevels.
+:cl2 mode #test2
+:cl2 mode #test2 -io+v Alex Alex
+:cl1 wait cl2
+:cl1 part #test2
+:cl1 join #test2
+:cl2 wait cl1
+:cl2 mode #test2 -D
+:cl2 mode #test +v Alex
+:cl1 raw :kick #test bubb
+:cl2 raw :squit test-1.*
+:cl2 sleep 1
+:cl2 raw :connect test-1.*
+:cl2 raw :away :
+:cl1 wait cl2
diff --git a/ircd/test/client-1.cmd b/ircd/test/client-1.cmd
new file mode 100644 (file)
index 0000000..1db7fd1
--- /dev/null
@@ -0,0 +1,25 @@
+define srv localhost
+
+connect cl1 Alex alex %srv%:7701 :Test client 1
+:cl1 oper oper1 oper1
+:cl1 oper oper1 oper1
+connect cl2 Bubb bubb %srv%:7711 :Test client 2
+:cl1 raw :time
+:cl2 oper oper3 oper4
+:cl1 raw :version
+:cl2 oper oldoper wrongpass
+:cl2 oper md5oper wrongpass
+:cl2 oper cryptoper wrongpass
+:cl2 oper oper2 oper2
+:cl2 raw :privs Alex Alex
+:cl1 wait cl2
+:cl1 raw :privs Bubb
+:cl1 nick A
+:cl1 nick Alexey
+:cl1 raw :privmsg :
+:cl1 raw :privmsg Alexey :
+:cl1 raw :privmsg Bubb :hello Bubb
+:cl1 raw :privmsg $*.net :Hello all *.net servers.
+:cl1 raw :notice $*.net :Hello all *.net servers.
+:cl1 raw :kill Bubb :goodbye Bubb
+:cl1 raw :whowas Alex,Bubb 5
diff --git a/ircd/test/commands-1.cmd b/ircd/test/commands-1.cmd
new file mode 100644 (file)
index 0000000..d97aaad
--- /dev/null
@@ -0,0 +1,43 @@
+define srv localhost:7701
+
+connect cl1 Alex alex %srv% :Test client 1
+connect cl2 Bubb bubb %srv% :Test client 2
+:cl1 raw :help
+:cl1 raw :admin
+:cl1 raw :admin test-2.*
+:cl1 raw :info
+:cl1 raw :wallops :HELLO OPERZ!!!
+:cl1 wait cl2
+:cl1 raw :ison alex,bubb,alex,bubb,alex,bubb
+:cl1 raw :who b*b
+:cl1 raw :burst the bubble
+:cl1 raw :server huh huh i'm a server
+:cl1 raw :links
+:cl1 raw :map
+:cl1 raw :nick
+:cl1 raw :nick ~
+:cl1 raw :nick -dude-
+:cl1 raw :nick alex
+:cl1 raw :nick Bubb
+:cl1 raw :ping alex test-1.*
+
+:cl1 oper oper1 oper1
+:cl1 raw :admin
+:cl1 raw :admin test-2.*
+:cl1 raw :asll
+:cl1 raw :asll test-2.*
+:cl1 raw :info
+:cl1 raw :info test-2.*
+:cl1 raw :who x b*b
+:cl1 raw :close
+:cl1 raw :map
+:cl1 raw :links
+:cl1 raw :links test-2.*
+:cl1 raw :lusers
+:cl1 raw :lusers test-2.*
+:cl1 raw :motd
+:cl1 raw :motd test-2.*
+:cl1 raw :ping alex test-2.*
+:cl1 raw :rping test-2.*
+
+:cl2 raw :quit
diff --git a/ircd/test/die.cmd b/ircd/test/die.cmd
new file mode 100644 (file)
index 0000000..1ef7d95
--- /dev/null
@@ -0,0 +1,5 @@
+connect cl1 Alex alex localhost:7701 :Test client 1
+:cl1 oper oper1 oper1
+:cl1 raw :restart brb
+:cl1 oper oper1 oper1
+:cl1 raw :die :testing over
diff --git a/ircd/test/feature-1.cmd b/ircd/test/feature-1.cmd
new file mode 100644 (file)
index 0000000..af93c52
--- /dev/null
@@ -0,0 +1,18 @@
+define srv localhost:7701
+
+connect cl1 Alex alex %srv% :Test client 1
+:cl1 oper oper1 oper1
+:cl1 raw :GET LOG
+:cl1 raw :RESET LOG
+:cl1 raw :GET RANDOM_SEED
+:cl1 raw :SET RANDOM_SEED
+:cl1 raw :SET RANDOM_SEED abcdefghijklmnop
+:cl1 raw :GET DEFAULT_LIST_PARAM
+:cl1 raw :SET DEFAULT_LIST_PARAM FALSE
+:cl1 raw :SET DEFAULT_LIST_PARAM TRUE
+:cl1 nick Alexey
+:cl1 nick Amdahl
+:cl1 nick Andy
+:cl1 nick Aon
+:cl1 nick Apple
+:cl1 raw :SET NICKNAMEHISTORYLENGTH 4
diff --git a/ircd/test/gline-1.cmd b/ircd/test/gline-1.cmd
new file mode 100644 (file)
index 0000000..89a1d4b
--- /dev/null
@@ -0,0 +1,29 @@
+define srv localhost:7701
+
+connect cl1 Alex alex %srv% :Test client 1
+:cl1 oper oper1 oper1
+:cl1 raw :gline !+$Rbubb 30 :Bubb is not welcome here
+:cl1 sleep 35
+:cl1 raw :gline !+127.2.* 3600 :Localclone?
+:cl1 sleep 5
+:cl1 raw :gline !+127.2.* 3600 :Localclone?
+:cl1 raw :gline !+127.2.*/15 3600 :Localclone?
+:cl1 raw :gline !+127.2.0.0/33 3600 :Localclone?
+:cl1 raw :gline !+127.2.0.0/15 3600 :Localclone?
+connect cl2 Bubb bubb %srv% :Test client 2
+:cl1 raw :gline
+:cl1 raw :gline $Rbubb
+:cl1 raw :gline -$Rbubb
+:cl1 wait cl2
+:cl1 raw :gline !+$Rbubb * 3600 :Bubb is not welcome here
+:cl1 sleep 5
+:cl1 raw :gline -$Rbubb
+:cl1 raw :gline +#warez 30 :Warez r bad mmkay
+:cl2 wait cl1
+:cl2 join #warez
+:cl1 sleep 35
+:cl1 raw :stats glines
+:cl1 raw :gline !+*@127.0.0.2 3600 :Localclone?
+:cl1 raw :gline !+127.1.* 3600 :Localclone?
+:cl1 raw :stats memory
+:cl2 raw :gline
diff --git a/ircd/test/ircd-t1-2.conf b/ircd/test/ircd-t1-2.conf
new file mode 100644 (file)
index 0000000..b48017f
--- /dev/null
@@ -0,0 +1,93 @@
+General {
+        name = "test-1.example.net";
+        vhost = "127.0.0.1";
+        vhost = "::1";
+        description = "Test Server 1";
+        numeric = 1;
+};
+
+Admin {
+        location = "Somewhere";
+        contact = "Someone";
+};
+
+Class {
+        name = "Server";
+        pingfreq = 180 seconds;
+        connectfreq = 300 seconds;
+        maxlinks = 1;
+        sendq = 9000000;
+};
+
+Class {
+        name = "others";
+        pingfreq = 180 seconds;
+        sendq = 160000;
+        maxlinks = 100;
+        usermode = "+oiwx";
+};
+
+Class {
+        name = "Opers";
+        pingfreq = 180 seconds;
+        sendq = 160000;
+        maxlinks = 10;
+        local = no;
+};
+
+Connect {
+        name = "bogus.example.net";
+        host = "example.net";
+        password = "bogus_example";
+        port = 7700;
+        class = "Server";
+        maxhops = 2;
+        hub = "*.example.net";
+        autoconnect = yes; # forces a DNS resolution attempt
+};
+
+CRule {
+        server = "bogus.example.net";
+        all = yes;
+        rule = "connected(*)";
+};
+
+CRule {
+        server = "bogus.example.net";
+        all = no;
+        rule = "directcon(*)";
+};
+
+UWorld {
+        name = "uworld.example.net";
+        name = "uworld2.example.net";
+};
+
+Jupe {
+        nick = "A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q";
+        nick = "R,S,T,U,V,W,X,Y,Z,{,|,},~,-,_,`";
+};
+
+Operator { name = "oper1"; host = "*@*"; password = "$PLAIN$oper1"; class = "Opers"; };
+Operator { name = "oper2"; host = "*@*"; password = "$PLAIN$oper2"; class = "Opers"; local = yes; };
+Operator { name = "oldoper"; host = "*@*"; password = "Xlfc26b4eYGWs"; class = "Opers"; };
+Operator { name = "md5oper"; host = "*@*"; password = "$SMD5$2O$4O.rSAmhE4Fg05MmG.047/"; class = "Opers"; };
+Operator { name = "cryptoper"; host = "*@*"; password = "$CRYPT$41ndrxPQu3B66"; class = "Opers"; };
+
+Kill { username = "sub7"; realname = "s*7*"; reason = "You are infected with a Trojan"; };
+Kill { realname = "Chloe"; reason = "drones"; };
+Kill { username = "sub7"; reason = "You are infected with a Trojan"; };
+
+Client { class = "others"; ip = "*"; };
+
+Port { server = yes; port = 7700; };
+Port { server = no;  port = 7702; };
+
+Quarantine {
+        "#shells" = "Thou shalt not support the h4><0rz";
+};
+
+Features {
+        "HIS_STATS_k" = "FALSE";
+        "PPATH" = "ircd-t1.pid";
+};
diff --git a/ircd/test/ircd-t1.conf b/ircd/test/ircd-t1.conf
new file mode 100644 (file)
index 0000000..66472b0
--- /dev/null
@@ -0,0 +1,107 @@
+General {
+        name = "test-1.example.net";
+        vhost = "127.0.0.1";
+        vhost = "::1";
+        description = "Test Server 1";
+        numeric = 1;
+};
+
+Admin {
+        location = "Somewhere";
+        contact = "Someone";
+};
+
+Class {
+        name = "Server";
+        pingfreq = 180 seconds;
+        connectfreq = 300 seconds;
+        maxlinks = 1;
+        sendq = 9000000;
+};
+
+Class {
+        name = "others";
+        pingfreq = 180 seconds;
+        sendq = 160000;
+        maxlinks = 100;
+        usermode = "+oiwx";
+};
+
+Class {
+        name = "Opers";
+        pingfreq = 180 seconds;
+        sendq = 160000;
+        maxlinks = 10;
+        local = no;
+};
+
+Connect {
+        name = "bogus.example.net";
+        host = "example.net";
+        password = "bogus_example";
+        port = 7700;
+        class = "Server";
+        maxhops = 2;
+        hub = "*.example.net";
+        autoconnect = yes; # forces a DNS resolution attempt
+};
+
+Connect {
+        name = "test-2.example.net";
+        host = "::1";
+        password = "bogus_example";
+        port = 7710;
+        class = "Server";
+        autoconnect = no;
+};
+
+CRule {
+        server = "bogus.example.net";
+        all = yes;
+        rule = "connected(*)";
+};
+
+CRule {
+        server = "bogus.example.net";
+        all = no;
+        rule = "directcon(*)";
+};
+
+UWorld {
+        name = "uworld.example.net";
+        name = "uworld2.example.net";
+};
+
+Jupe {
+        nick = "A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q";
+        nick = "R,S,T,U,V,W,X,Y,Z,{,|,},~,-,_,`";
+};
+
+Operator { name = "oper1"; host = "*@*"; password = "$PLAIN$oper1"; class = "Opers"; };
+Operator { name = "oper2"; host = "*@*"; password = "$PLAIN$oper2"; class = "Opers"; local = yes; };
+Operator { name = "oldoper"; host = "*@*"; password = "Xlfc26b4eYGWs"; class = "Opers"; };
+Operator { name = "md5oper"; host = "*@*"; password = "$SMD5$2O$4O.rSAmhE4Fg05MmG.047/"; class = "Opers"; };
+Operator { name = "cryptoper"; host = "*@*"; password = "$CRYPT$41ndrxPQu3B66"; class = "Opers"; };
+
+Kill { username = "sub7"; realname = "s*7*"; reason = "You are infected with a Trojan"; };
+Kill { realname = "Chloe"; reason = "drones"; };
+Kill { username = "sub7"; reason = "You are infected with a Trojan"; };
+
+Client { class = "others"; ip = "*"; };
+
+Port { server = yes; port = 7700; };
+Port { server = no;  port = 7701; };
+
+Quarantine {
+        "#shells" = "Thou shalt not support the h4><0rz";
+};
+
+Pseudo "X" {
+        name = "X";
+        nick = "X@channels.example.net";
+};
+
+Features {
+        "HIS_STATS_k" = "FALSE";
+        "PPATH" = "ircd-t1.pid";
+};
diff --git a/ircd/test/ircd-t2.conf b/ircd/test/ircd-t2.conf
new file mode 100644 (file)
index 0000000..f692fdd
--- /dev/null
@@ -0,0 +1,95 @@
+General {
+        name = "test-2.example.net";
+        vhost = "127.0.0.1";
+        vhost = "::1";
+        description = "Test Server 2";
+        numeric = 2;
+};
+
+Admin {
+        location = "Somewhere";
+        contact = "Someone";
+};
+
+Class {
+        name = "Server";
+        pingfreq = 180 seconds;
+        connectfreq = 300 seconds;
+        maxlinks = 1;
+        sendq = 9000000;
+};
+
+Class {
+        name = "others";
+        pingfreq = 180 seconds;
+        sendq = 160000;
+        maxlinks = 100;
+        usermode = "+oiwx";
+};
+
+Class {
+        name = "Opers";
+        pingfreq = 180 seconds;
+        sendq = 160000;
+        maxlinks = 10;
+        local = no;
+};
+
+Connect {
+        name = "test-1.example.net";
+        host = "::1";
+        password = "bogus_example";
+        port = 7700;
+        class = "Server";
+        maxhops = 2;
+        hub = "*.example.net";
+        autoconnect = yes;
+};
+
+CRule {
+        server = "bogus.example.net";
+        all = yes;
+        rule = "connected(*)";
+};
+
+CRule {
+        server = "bogus.example.net";
+        all = no;
+        rule = "directcon(*)";
+};
+
+UWorld {
+        name = "uworld.example.net";
+        name = "uworld2.example.net";
+};
+
+Jupe {
+        nick = "A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q";
+        nick = "R,S,T,U,V,W,X,Y,Z,{,|,},~,-,_,`";
+};
+
+Operator { name = "oper1"; host = "*@*"; password = "$PLAIN$oper1"; class = "Opers"; };
+Operator { name = "oper2"; host = "*@*"; password = "$PLAIN$oper2"; class = "Opers"; local = yes; };
+
+Kill { realname = "Chloe"; reason = "drones"; };
+Kill { username = "sub7"; reason = "You are infected with a Trojan"; };
+
+Client { class = "others"; ip = "*"; };
+
+Port { server = yes; port = 7710; };
+Port { server = no;  port = 7711; mask = "127.0.0.0/8"; };
+
+Quarantine {
+        "#shells" = "Thou shalt not support the h4><0rz";
+};
+
+Pseudo "X" {
+        name = "X";
+        nick = "X@channels.example.net";
+};
+
+Features {
+        "PPATH" = "ircd-t2.pid";
+        "LOG" = "SYSTEM" "FILE" "ircd-t2.log";
+        "LOG" = "SYSTEM" "LEVEL" "NOTICE";
+};
diff --git a/ircd/test/ircd_chattr.0.dat b/ircd/test/ircd_chattr.0.dat
new file mode 100644 (file)
index 0000000..a3f94e5
--- /dev/null
@@ -0,0 +1,16 @@
+IsAlnum:         0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^abcdefghijklmnopqrstuvwxyz{|}~
+IsAlpha:         ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^abcdefghijklmnopqrstuvwxyz{|}~
+IsDigit:         0123456789
+IsLower:         abcdefghijklmnopqrstuvwxyz{|}~
+IsSpace:         \t\n\v\f\r 
+IsUpper:         ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^
+IsCntrl:         \0\1\2\3\4\5\6\a\b\t\n\v\f\r\e\f\10\11\12\13\14\15\16\17\18\19\1a\1b\1c\1d\1e\1f
+IsChannelChar:   \0\1\2\3\4\5\6\b\t\n\v\f\r\e\f\10\11\12\13\14\15\16\17\18\19\1a\1b\1c\1d\1e\1f!"#$%&'()*+-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~\7f\80\81\82\83\84\85\86\87\88\89\8a\8b\8c\8d\8e\8f\90\91\92\93\94\95\96\97\98\99\9a\9b\9c\9d\9e\9f\a1\a2\a3\a4\a5\a6\a7\a8\a9\aa\ab\ac\ad\ae\af\b0\b1\b2\b3\b4\b5\b6\b7\b8\b9\ba\bb\bc\bd\be\bf\c0\c1\c2\c3\c4\c5\c6\c7\c8\c9\ca\cb\cc\cd\ce\cf\d0\d1\d2\d3\d4\d5\d6\d7\d8\d9\da\db\dc\dd\de\df\e0\e1\e2\e3\e4\e5\e6\e7\e8\e9\ea\eb\ec\ed\ee\ef\f0\f1\f2\f3\f4\f5\f6\f7\f8\f9\fa\fb\fc\fd\fe\ff
+IsChannelLower:  \c0\c1\c2\c3\c4\c5\c6\c7\c8\c9\ca\cb\cc\cd\ce\cf\d0\d1\d2\d3\d4\d5\d6\d8\d9\da\db\dc\dd\de
+IsChannelPrefix: #&
+IsNickChar:      -0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~
+IsUserChar:      '-.0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~\c0\c1\c2\c3\c4\c5\c6\c7\c8\c9\ca\cb\cc\cd\ce\cf\d0\d1\d2\d3\d4\d5\d6\d8\d9\da\db\dc\dd\de\e0\e1\e2\e3\e4\e5\e6\e7\e8\e9\ea\eb\ec\ed\ee\ef\f0\f1\f2\f3\f4\f5\f6\f8\f9\fa\fb\fc\fd\fe
+IsHostChar:      -.0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_abcdefghijklmnopqrstuvwxyz{|}~
+IsIPChar:        .0123456789
+IsEol:           \n\r
+IsKTimeChar:      ,-0123456789
diff --git a/ircd/test/ircd_chattr_t.c b/ircd/test/ircd_chattr_t.c
new file mode 100644 (file)
index 0000000..04051e2
--- /dev/null
@@ -0,0 +1,160 @@
+/*
+ * ircd_chattr_t.c - Test file for character attributes
+ */
+#include "ircd_chattr.h"
+/* #include <assert.h> -- not used here */
+#include <stdio.h>
+
+typedef int (*EvalFn)(char);
+
+int eval_alnum(char c)
+{
+  return (0 != IsAlnum(c));
+}
+
+int eval_alpha(char c)
+{
+  return (0 != IsAlpha(c));
+}
+
+int eval_digit(char c)
+{
+  return (0 != IsDigit(c));
+}
+
+int eval_lower(char c)
+{
+  return (0 != IsLower(c));
+}
+
+int eval_space(char c)
+{
+  return (0 != IsSpace(c));
+}
+
+int eval_upper(char c)
+{
+  return (0 != IsUpper(c));
+}
+
+int eval_cntrl(char c)
+{
+  return (0 != IsCntrl(c));
+}
+
+int eval_channel_char(char c)
+{
+  return (0 != IsChannelChar(c));
+}
+
+int eval_channel_lower(char c)
+{
+  return (0 != IsChannelLower(c));
+}
+
+int eval_channel_prefix(char c)
+{
+  return (0 != IsChannelPrefix(c));
+}
+
+int eval_nick_char(char c)
+{
+  return (0 != IsNickChar(c));
+}
+
+int eval_user_char(char c)
+{
+  return (0 != IsUserChar(c));
+}
+
+int eval_host_char(char c)
+{
+  return (0 != IsHostChar(c));
+}
+
+int eval_ip_char(char c)
+{
+  return (0 != IsIPChar(c));
+}
+
+int eval_eol(char c)
+{
+  return (0 != IsEol(c));
+}
+
+int eval_ktime_char(char c)
+{
+  return (0 != IsKTimeChar(c));
+}
+
+struct CharTest {
+  const char* name;
+  EvalFn      evaluator;
+} testList[] = {
+  { "IsAlnum:         ", eval_alnum },
+  { "IsAlpha:         ", eval_alpha },
+  { "IsDigit:         ", eval_digit },
+  { "IsLower:         ", eval_lower },
+  { "IsSpace:         ", eval_space },
+  { "IsUpper:         ", eval_upper },
+  { "IsCntrl:         ", eval_cntrl },
+  { "IsChannelChar:   ", eval_channel_char },
+  { "IsChannelLower:  ", eval_channel_lower },
+  { "IsChannelPrefix: ", eval_channel_prefix },
+  { "IsNickChar:      ", eval_nick_char },
+  { "IsUserChar:      ", eval_user_char },
+  { "IsHostChar:      ", eval_host_char },
+  { "IsIPChar:        ", eval_ip_char },
+  { "IsEol:           ", eval_eol },
+  { "IsKTimeChar:     ", eval_ktime_char }
+};
+
+#define TESTLIST_SIZE sizeof(testList) / sizeof(struct CharTest)
+
+void print_char(unsigned char c)
+{
+  if (c < 0x20) {
+    switch (c) {
+    case '\a': printf("\\a"); break;
+    case '\b': printf("\\b"); break;
+    case '\f': printf("\\f"); break;
+    case '\n': printf("\\n"); break;
+    case '\r': printf("\\r"); break;
+    case '\t': printf("\\t"); break;
+    case '\v': printf("\\v"); break;
+    default:
+      printf("\\%x", c); break;
+    }
+  }
+  else if (c < 0x7F) {
+    printf("%c", c);
+  }
+  else {
+    printf("\\%x", c);
+  }
+}
+
+void print_char_attr(struct CharTest* test)
+{
+  int i;
+
+  printf("%s", test->name);
+
+  for (i = 0; i < 256; ++i) {
+    if ((*test->evaluator)(i))
+      print_char(i);
+  }
+  printf("\n");
+}
+
+    
+int main(void)
+{
+  int i;
+
+  for (i = 0; i < TESTLIST_SIZE; ++i)
+    print_char_attr(&testList[i]);
+
+  return 0;
+}
+
diff --git a/ircd/test/ircd_in_addr_t.c b/ircd/test/ircd_in_addr_t.c
new file mode 100644 (file)
index 0000000..07f6cc9
--- /dev/null
@@ -0,0 +1,168 @@
+/* ircd_in_addr_t.c - Test file for IP address manipulation */
+
+#include "ircd_log.h"
+#include "ircd_string.h"
+#include "numnicks.h"
+#include "res.h"
+#include <stdio.h>
+#include <string.h>
+#include <netinet/in.h>
+
+/** Structure to describe a test for IP address parsing and unparsing. */
+struct address_test {
+    const char *text; /**< Textual address to parse. */
+    const char *canonical; /**< Canonical form of address. */
+    struct irc_in_addr expected; /**< Parsed address. */
+    const char *base64_v4; /**< v4-only compatible base64 encoding. */
+    const char *base64_v6; /**< v6-compatible base64 encoding. */
+    unsigned int is_valid : 1; /**< is address valid? */
+    unsigned int is_ipv4 : 1; /**< is address ipv4? */
+    unsigned int is_loopback : 1; /**< is address loopback? */
+};
+
+/** Array of addresses to test with. */
+static struct address_test test_addrs[] = {
+    { "::", "0::",
+      {{ 0, 0, 0, 0, 0, 0, 0, 0 }},
+      "AAAAAA", "_", 0, 0, 0 },
+    { "::1", "0::1",
+      {{ 0, 0, 0, 0, 0, 0, 0, 1 }},
+      "AAAAAA", "_AAB", 1, 0, 1 },
+    { "127.0.0.1", "127.0.0.1",
+      {{ 0, 0, 0, 0, 0, 0, 0x7f00, 1 }},
+      "B]AAAB", "B]AAAB", 1, 1, 1 },
+    { "::ffff:127.0.0.3", "127.0.0.3",
+      {{ 0, 0, 0, 0, 0, 0xffff, 0x7f00, 3 }},
+      "B]AAAD", "B]AAAD", 1, 1, 1 },
+    { "::127.0.0.1", "127.0.0.1",
+      {{ 0, 0, 0, 0, 0, 0, 0x7f00, 1 }},
+      "B]AAAB", "B]AAAB", 1, 1, 1 },
+    { "2002:7f00:3::1", "2002:7f00:3::1",
+      {{ 0x2002, 0x7f00, 3, 0, 0, 0, 0, 1 }},
+      "B]AAAD", "CACH8AAAD_AAB", 1, 0, 0 },
+    { "8352:0344:0:0:0:0:2001:1204", "8352:344::2001:1204",
+      {{ 0x8352, 0x344, 0, 0, 0, 0, 0x2001, 0x1204 }},
+      "AAAAAA", "INSANE_CABBIE", 1, 0, 0 },
+    { "1:2:3:4:5:6:7:8", "1:2:3:4:5:6:7:8",
+      {{ 1, 2, 3, 4, 5, 6, 7, 8 }},
+      "AAAAAA", "AABAACAADAAEAAFAAGAAHAAI", 1, 0, 0 },
+    { 0 },
+};
+
+/** Perform tests for a single IP address.
+ * @param[in] addr Address test structure.
+ */
+static void
+test_address(struct address_test *addr)
+{
+    struct irc_in_addr parsed;
+    unsigned int ii, len, val;
+    char unparsed[64], base64_v4[64], base64_v6[64];
+
+    /* Convert expected address to network order. */
+    for (ii = 0; ii < 8; ++ii)
+        addr->expected.in6_16[ii] = htons(addr->expected.in6_16[ii]);
+    /* Make sure the text form is parsed as expected. */
+    len = ircd_aton(&parsed, addr->text);
+    assert(len == strlen(addr->text));
+    assert(!irc_in_addr_cmp(&parsed, &addr->expected));
+    /* Make sure it converts back to ASCII. */
+    ircd_ntoa_r(unparsed, &parsed);
+    assert(!strcmp(unparsed, addr->canonical));
+    /* Check IP-to-base64 conversion. */
+    iptobase64(base64_v4, &parsed, sizeof(base64_v4), 0);
+    iptobase64(base64_v6, &parsed, sizeof(base64_v6), 1);
+    if (addr->base64_v4)
+        assert(!strcmp(base64_v4, addr->base64_v4));
+    if (addr->base64_v6)
+        assert(!strcmp(base64_v6, addr->base64_v6));
+    /* Check testable attributes. */
+    val = irc_in_addr_valid(&parsed);
+    assert(!!val == addr->is_valid);
+    val = irc_in_addr_is_ipv4(&parsed);
+    assert(!!val == addr->is_ipv4);
+    val = irc_in_addr_is_loopback(&parsed);
+    assert(!!val == addr->is_loopback);
+    /* Check base64-to-IP conversion. */
+    if (addr->is_ipv4) {
+        base64toip(addr->base64_v4, &parsed);
+        assert(!memcmp(parsed.in6_16+6, addr->expected.in6_16+6, 4));
+    } else {
+        base64toip(addr->base64_v6, &parsed);
+        assert(!memcmp(&parsed, &addr->expected, sizeof(parsed)));
+    }
+    /* Tests completed. */
+    printf("Passed: %s (%s/%s)\n", addr->text, base64_v4, base64_v6);
+}
+
+/** Structure to describe a test for IP mask parsing. */
+struct ipmask_test {
+    const char *text; /**< Textual IP mask to parse. */
+    struct irc_in_addr expected; /**< Canonical form of address. */
+    unsigned int is_ipmask : 1; /**< Parse as an ipmask? */
+    unsigned int is_parseable : 1; /**< Is address parseable? */
+    unsigned int exp_bits : 8; /**< Number of bits expected in netmask */
+};
+
+/** Array of ipmasks to test with. */
+static struct ipmask_test test_masks[] = {
+    { "::", {{ 0, 0, 0, 0, 0, 0, 0, 0 }}, 1, 1, 128 },
+    { "::/0", {{ 0, 0, 0, 0, 0, 0, 0, 0 }}, 1, 1, 0 },
+    { "::10.0.0.0", {{ 0, 0, 0, 0, 0, 0, 0xa00, 0 }}, 1, 1, 128 },
+    { "192.168/16", {{ 0, 0, 0, 0, 0, 0xffff, 0xc0a8, 0 }}, 1, 1, 112 },
+    { "192.*", {{ 0, 0, 0, 0, 0, 0xffff, 0xc000, 0 }}, 1, 1, 104 },
+    { "192.*/8", {{ 0, 0, 0, 0, 0, 0, 0, 0 }}, 1, 0, 0 },
+    { "192*", {{ 0, 0, 0, 0, 0, 0, 0, 0 }}, 1, 0, 0 },
+    { "192.168.0.0/16", {{ 0, 0, 0, 0, 0, 0, 0, 0 }}, 0, 0, 0 },
+    { "ab.*", {{ 0, 0, 0, 0, 0, 0, 0, 0 }}, 1, 0, 0 },
+    { "a*", {{ 0, 0, 0, 0, 0, 0, 0, 0 }}, 1, 0, 0 },
+    { "*", {{ 0, 0, 0, 0, 0, 0, 0, 0 }}, 1, 1, 0 },
+    { "a:b", {{ 0, 0, 0, 0, 0, 0, 0, 0 }}, 1, 0, 0 },
+    { "a::*", {{ 0, 0, 0, 0, 0, 0, 0, 0 }}, 1, 0, 0 },
+    { "a:*", {{ 0xa, 0, 0, 0, 0, 0, 0, 0 }}, 1, 1, 16 },
+    { "a:/16", {{ 0xa, 0, 0, 0, 0, 0, 0, 0 }}, 1, 1, 16 },
+    { 0 }
+};
+
+/** Perform tests for a single IP mask.
+ * @param[in] mask IP mask test structure.
+ */
+static void
+test_ipmask(struct ipmask_test *mask)
+{
+    struct irc_in_addr parsed;
+    unsigned int len, ii;
+    unsigned char bits = 0;
+
+    /* Convert expected address to network order. */
+    for (ii = 0; ii < 8; ++ii)
+        mask->expected.in6_16[ii] = htons(mask->expected.in6_16[ii]);
+    /* Try to parse; make sure its parseability and netmask length are
+     * as expected. */
+    len = ipmask_parse(mask->text, &parsed, mask->is_ipmask ? &bits : 0);
+    assert(!!len == mask->is_parseable);
+    if (!len) {
+        printf("X-Fail: %s\n", mask->text);
+        return;
+    }
+    if (mask->is_ipmask)
+        assert(bits == mask->exp_bits);
+    assert(!memcmp(&parsed, &mask->expected, sizeof(parsed)));
+    printf("Passed: %s (%s/%u)\n", mask->text, ircd_ntoa(&parsed), bits);
+}
+
+int
+main(int argc, char *argv[])
+{
+    unsigned int ii;
+
+    printf("Testing address parsing..\n");
+    for (ii = 0; test_addrs[ii].text; ++ii)
+        test_address(&test_addrs[ii]);
+
+    printf("\nTesting ipmask parsing..\n");
+    for (ii = 0; test_masks[ii].text; ++ii)
+        test_ipmask(&test_masks[ii]);
+
+    return 0;
+}
diff --git a/ircd/test/ircd_match_t.c b/ircd/test/ircd_match_t.c
new file mode 100644 (file)
index 0000000..da7a28f
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+ * ircd_match_t.c - test cases for irc glob matching
+ */
+
+#include "ircd_log.h"
+#include "match.h"
+#include <stdio.h>
+#include <string.h>
+
+struct match_test {
+  const char *glob;
+  const char *should_match;
+  const char *shouldnt_match;
+};
+
+const struct match_test match_tests[] = {
+  { "\\*",
+    "*\0",
+    "a\0*PeacefuL*\0" },
+  { "*a*",
+    "a\0pizza\0abe\0brack\0",
+    "b\0" },
+  { "?",
+    "*\0a\0?\0",
+    "*PeacefuL*\0pizza\0???\0" },
+  { "abc",
+    "abc\0",
+    "abcd\0cabc\0" },
+  { "*abc",
+    "abc\0fooabc\0ababc\0",
+    "abra\0abcd\0" },
+  { "\\?",
+    "?\0",
+    "a\0" },
+  { NULL, NULL, NULL }
+};
+
+void do_match_test(const struct match_test *test)
+{
+  const char *candidate;
+  unsigned int matched, not_matched;
+  int res;
+
+  for (candidate = test->should_match, matched = 0;
+       *candidate;
+       candidate += strlen(candidate) + 1, ++matched) {
+    res = match(test->glob, candidate);
+    if (res != 0) {
+      fprintf(stderr, "\"%s\" failed to match \"%s\".\n", test->glob, candidate);
+      assert(0);
+    }
+  }
+
+  for (candidate = test->shouldnt_match, not_matched = 0;
+       *candidate;
+       candidate += strlen(candidate) + 1, ++not_matched) {
+    res = match(test->glob, candidate);
+    if (res == 0) {
+      fprintf(stderr, "\"%s\" incorrectly matched \"%s\".\n", test->glob, candidate);
+      assert(0);
+    }
+  }
+
+  printf("Passed: %s (%u matches, %u non-matches)\n",
+         test->glob, matched, not_matched);
+}
+
+int main(int argc, char *argv[])
+{
+  const struct match_test *match;
+  for (match = match_tests; match->glob; ++match)
+    do_match_test(match);
+  return 0;
+}
diff --git a/ircd/test/ircd_string_t.c b/ircd/test/ircd_string_t.c
new file mode 100644 (file)
index 0000000..3c73aa8
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * ircd_string_t.c - string test program
+ */
+#include "ircd_string.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+int main(void)
+{
+  char* vector[20];
+  char* names;
+  int count;
+  int i;
+
+  names = strdup(",,,a,b,a,X,ne,blah,A,z,#foo,&Bar,foo,,crud,Foo,z,x,bzet,,");
+  printf("input: %s\n", names);
+  count = unique_name_vector(names, ',', vector, 20);
+  printf("count: %d\n", count);
+  printf("output:");
+  for (i = 0; i < count; ++i)
+    printf(" %s", vector[i]);
+  printf("\n");
+  free(names);
+
+  names = strdup("foo");
+  printf("input: %s\n", names);
+  count = unique_name_vector(names, ',', vector, 20);
+  printf("count: %d\n", count);
+  printf("output:");
+  for (i = 0; i < count; ++i)
+    printf(" %s", vector[i]);
+  printf("\n");
+  free(names);
+  
+  names = strdup("");
+  printf("input: %s\n", names);
+  count = unique_name_vector(names, ',', vector, 20);
+  printf("count: %d\n", count);
+  printf("output:");
+  for (i = 0; i < count; ++i)
+    printf(" %s", vector[i]);
+  printf("\n");
+  free(names);
+
+  names = strdup("a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z");
+  printf("input: %s\n", names);
+  count = unique_name_vector(names, ',', vector, 20);
+  printf("count: %d\n", count);
+  printf("output:");
+  for (i = 0; i < count; ++i)
+    printf(" %s", vector[i]);
+  printf("\n");
+  free(names);
+
+  return 0;
+}
+  
diff --git a/ircd/test/jupe-1.cmd b/ircd/test/jupe-1.cmd
new file mode 100644 (file)
index 0000000..52668bb
--- /dev/null
@@ -0,0 +1,8 @@
+define srv localhost:7701
+
+connect cl1 Alex alex %srv% :Test client 1
+:cl1 oper oper1 oper1
+:cl1 raw :jupe +irc-3.example.net 3600 :Server 3 not welcome here.
+:cl1 raw :jupe -irc-3.example.net 3600 :Server 3 not welcome here.
+:cl1 raw :jupe +irc-3.example.net * 3600 :Server 3 not welcome here.
+:cl1 raw :jupe -irc-3.example.net * 3600 :Server 3 not welcome here.
diff --git a/ircd/test/kill-block-1.cmd b/ircd/test/kill-block-1.cmd
new file mode 100644 (file)
index 0000000..d76962f
--- /dev/null
@@ -0,0 +1,6 @@
+define srv localhost:7701
+
+connect cl1 Alex sub7 %srv% :s7server
+connect cl2 Chloe chloe %srv% :Chloe
+cl1 sleep 30
+cl2 sleep 30
diff --git a/ircd/test/run-tests.sh b/ircd/test/run-tests.sh
new file mode 100644 (file)
index 0000000..d16cf04
--- /dev/null
@@ -0,0 +1,30 @@
+#! /bin/sh
+
+set -e
+srcdir=`dirname $0`
+ircdir=$1
+
+cp ${srcdir}/ircd-t1.conf ircd-t1.conf
+cp ${srcdir}/ircd-t2.conf ircd-t2.conf
+echo "Testing one-shot ircd invocations."
+${ircdir}/ircd -v
+${ircdir}/ircd -x 6 -k -d . -f ircd-t1.conf -c user@127.0.0.1
+echo "Starting ircd."
+${ircdir}/ircd -d . -f ircd-t1.conf
+${ircdir}/ircd -d . -f ircd-t2.conf
+sleep 10
+# stats-1 is out of alphabetical order to avoid triggering IPcheck.
+for script in channel-1 client-1 commands-1 feature-1 gline-1 stats-1 jupe-1 kill-block-1 ; do
+  echo "Running test $script."
+  ${srcdir}/test-driver.pl -D ${srcdir}/${script}.cmd 2> ${script}.log
+done
+echo "Sending signals to server."
+cp ${srcdir}/ircd-t1-2.conf ircd-t1.conf
+kill -HUP `cat ircd-t1.pid`
+sleep 1
+kill -INT `cat ircd-t1.pid`
+# A long sleep is necessary to make the server flush its IPcheck entries.
+sleep 610
+kill -TERM `cat ircd-t1.pid` `cat ircd-t2.pid`
+sleep 1
+${ircdir}/ircd -? || true
diff --git a/ircd/test/stats-1.cmd b/ircd/test/stats-1.cmd
new file mode 100644 (file)
index 0000000..ac89e93
--- /dev/null
@@ -0,0 +1,97 @@
+# Connect to server
+connect cl1 Alex alex localhost:7701 :Test client 1
+:cl1 oper oper1 oper1
+
+# Single letter stats commands
+:cl1 raw :stats a
+:cl1 raw :stats c
+:cl1 raw :stats d
+:cl1 raw :stats D
+:cl1 raw :stats e
+:cl1 raw :stats f
+:cl1 raw :stats g
+:cl1 raw :stats i
+:cl1 raw :stats j
+:cl1 raw :stats J
+:cl1 raw :stats k
+:cl1 raw :stats l
+:cl1 raw :stats L
+:cl1 raw :stats m
+:cl1 raw :stats o
+:cl1 raw :stats p
+:cl1 raw :stats q
+:cl1 raw :stats r
+:cl1 raw :stats R
+:cl1 raw :stats t
+:cl1 raw :stats T
+:cl1 raw :stats u
+:cl1 raw :stats U
+:cl1 raw :stats v
+:cl1 raw :stats V
+:cl1 raw :stats w
+:cl1 raw :stats x
+:cl1 raw :stats z
+:cl1 raw :stats *
+
+# Remote stats requests
+:cl1 raw :stats f test-2.*
+
+# Named stats commands
+:cl1 raw :stats nameservers
+:cl1 raw :stats connect
+:cl1 raw :stats maskrules
+:cl1 raw :stats crules
+:cl1 raw :stats engine
+:cl1 raw :stats features
+:cl1 raw :stats glines
+:cl1 raw :stats access
+:cl1 raw :stats histogram
+:cl1 raw :stats jupes
+:cl1 raw :stats klines
+:cl1 raw :stats links
+:cl1 raw :stats modules
+:cl1 raw :stats commands
+:cl1 raw :stats operators
+:cl1 raw :stats ports
+:cl1 raw :stats quarantines
+:cl1 raw :stats mappings
+:cl1 raw :stats usage
+:cl1 raw :stats motds
+:cl1 raw :stats locals
+:cl1 raw :stats uworld
+:cl1 raw :stats uptime
+:cl1 raw :stats vservers
+:cl1 raw :stats vserversmach
+:cl1 raw :stats userload
+:cl1 raw :stats memusage
+:cl1 raw :stats classes
+:cl1 raw :stats memory
+:cl1 raw :stats help
+:cl1 raw :hash
+:cl1 raw :rehash m
+:cl1 raw :rehash l
+:cl1 raw :rehash q
+:cl1 raw :rehash
+:cl1 nick Alexey
+
+# Varparam stats
+:cl1 raw :stats access * 127.0.0.1
+:cl1 raw :stats access * *
+:cl1 raw :stats klines * *
+:cl1 raw :stats klines * *@*
+:cl1 raw :stats links * *
+:cl1 raw :stats ports * 7700
+:cl1 raw :stats quarantines * #frou-frou
+:cl1 raw :stats vservers * *.example.net
+
+# Invalid or nonexistent stats requests
+:cl1 raw :stats y
+:cl1 raw :stats Ã¿
+:cl1 raw :stats mºD٣˧
+:cl1 raw :stats long_garbage_here_to_hopefully_trigger_the_core_reported_by_dan
+
+# Drop oper status and try a few others
+:cl1 mode Alex -o
+:cl1 raw :stats k
+:cl1 raw :stats k * *
+:cl1 raw :stats k * *@*
diff --git a/ircd/test/test-driver.pl b/ircd/test/test-driver.pl
new file mode 100644 (file)
index 0000000..7edcfea
--- /dev/null
@@ -0,0 +1,545 @@
+#! /usr/bin/perl -wT
+
+# If you edit this file, please check carefully that the garbage
+# collection isn't broken.  POE is sometimes too clever for our good
+# in finding references to sessions, and keeps running even after we
+# want to stop.
+# $Id: test-driver.pl,v 1.3 2005/05/31 00:26:19 entrope Exp $
+
+# This interprets a simple scripting language.  Lines starting with a
+# hash mark (#, aka octothorpe, pound sign, etc) are ignored.  The
+# special commands look like this, where angle brackets indicate a
+# metavariable:
+#  define <macro> <value>
+#  undef <macro>
+#  connect <name> <nick> <ident> <server> :<userinfo>
+#  sync <name1>,<name2>[,<name3>]*
+#  :<name> <command>[ <args]*
+# For the last line syntax, <command> may be an IRC or IRC-like
+# command.  Supported non-IRC commands are:
+#  :<name> expect <source|*name2> [...]
+#  :<name> raw <text>
+#  :<name> sleep <seconds>
+#  :<name> wait <name2>
+
+require 5.006;
+
+use bytes;
+use warnings;
+use strict;
+use vars;
+use constant DELAY => 2;
+use constant EXPECT_TIMEOUT => 15;
+use constant RECONNECT_TIMEOUT => 5;
+use constant THROTTLED_TIMEOUT => 90;
+
+use FileHandle;
+use POE;
+use POE::Component::IRC;
+
+# this defines commands that take "zero time" to execute
+# (specifically, those which do not send commands from the issuing
+# client to the server)
+our $zero_time = {
+                  expect => 1,
+                  sleep => 1,
+                  wait => 1,
+                 };
+
+# Create the main session and start POE.
+# All the empty anonymous subs are just to make POE:Session::ASSERT_STATES happy.
+POE::Session->create(inline_states =>
+                     {
+                      # POE kernel interaction
+                      _start => \&drv_start,
+                      _child => sub {},
+                      _stop => sub {
+                        my $heap = $_[HEAP];
+                        print "\nThat's all, folks!";
+                        print "(exiting at line $heap->{lineno}: $heap->{line})"
+                          if $heap->{line};
+                        print "\n";
+                      },
+                      _default => \&drv_default,
+                      # generic utilities or miscellaneous functions
+                      heartbeat => \&drv_heartbeat,
+                      timeout_expect => \&drv_timeout_expect,
+                      reconnect => \&drv_reconnect,
+                      enable_client => sub { $_[ARG0]->{ready} = 1; },
+                      disable_client => sub { $_[ARG0]->{ready} = 0; },
+                      die => sub { $_[KERNEL]->signal($_[SESSION], 'TERM'); },
+                      # client-based command issuers
+                      cmd_die => \&cmd_generic,
+                      cmd_expect => \&cmd_expect,
+                      cmd_invite => \&cmd_generic,
+                      cmd_join => \&cmd_generic,
+                      cmd_mode => \&cmd_generic,
+                      cmd_nick => \&cmd_generic,
+                      cmd_notice => \&cmd_message,
+                      cmd_oper => \&cmd_generic,
+                      cmd_part => \&cmd_generic,
+                      cmd_privmsg => \&cmd_message,
+                      cmd_quit => \&cmd_generic,
+                      cmd_raw => \&cmd_raw,
+                      cmd_sleep => \&cmd_sleep,
+                      cmd_wait => \&cmd_wait,
+                      # handlers for messages from IRC
+                      irc_001 => \&irc_connected, # Welcome to ...
+                      irc_snotice => sub {}, # notice from a server (anonymous/our uplink)
+                      irc_notice => \&irc_notice, # NOTICE to self or channel
+                      irc_msg => \&irc_msg, # PRIVMSG to self
+                      irc_public => \&irc_public, # PRIVMSG to channel
+                      irc_connected => sub {},
+                      irc_ctcp_action => sub {},
+                      irc_ctcp_ping => sub {},
+                      irc_ctcp_time => sub {},
+                      irc_ctcpreply_ping => sub {},
+                      irc_ctcpreply_time => sub {},
+                      irc_invite => \&irc_invite, # INVITE to channel
+                      irc_join => sub {},
+                      irc_kick => sub {},
+                      irc_kill => sub {},
+                      irc_mode => sub {},
+                      irc_nick => sub {},
+                      irc_part => sub {},
+                      irc_ping => sub {},
+                      irc_pong => sub {},
+                      irc_rpong => sub {},
+                      irc_quit => sub {},
+                      irc_topic => sub {},
+                      irc_plugin_add => sub {},
+                      irc_error => \&irc_error,
+                      irc_disconnected => \&irc_disconnected,
+                      irc_socketerr => \&irc_socketerr,
+                     },
+                     args => [@ARGV]);
+
+$| = 1;
+$poe_kernel->run();
+exit;
+
+# Core/bookkeeping test driver functions
+
+sub drv_start {
+  my ($kernel, $session, $heap) = @_[KERNEL, SESSION, HEAP];
+
+  # initialize heap
+  $heap->{clients} = {}; # session details, indexed by (short) session name
+  $heap->{sessions} = {}; # session details, indexed by session ref
+  $heap->{servers} = {}; # server addresses, indexed by short names
+  $heap->{macros} = {}; # macros
+
+  # Parse arguments
+  foreach my $arg (@_[ARG0..$#_]) {
+    if ($arg =~ /^-D$/) {
+      $heap->{irc_debug} = 1;
+    } elsif ($arg =~ /^-V$/) {
+      $heap->{verbose} = 1;
+    } elsif ($arg =~ /^-vhost=(.*)$/) {
+      $heap->{vhost} = $1;
+    } else {
+      die "Extra command-line argument $arg\n" if $heap->{script};
+      $heap->{script} = new FileHandle($arg, 'r')
+        or die "Unable to open $arg for reading: $!\n";
+    }
+  }
+  die "No test name specified\n" unless $heap->{script};
+
+  # hook in to POE
+  $kernel->alias_set('control');
+  $kernel->yield('heartbeat');
+}
+
+sub drv_heartbeat {
+  my ($kernel, $session, $heap) = @_[KERNEL, SESSION, HEAP];
+  my $script = $heap->{script};
+  my $used = {};
+  my $delay = DELAY;
+
+  while (1) {
+    my ($line, $lineno);
+    if ($heap->{line}) {
+      $line = delete $heap->{line};
+    } elsif (defined($line = <$script>)) {
+      $heap->{lineno} = $.;
+      print "." unless $heap->{irc_debug};
+    } else {
+      # close all connections
+      foreach my $client (values %{$heap->{clients}}) {
+        $kernel->call($client->{irc}, 'quit', "I fell off the end of my script");
+        $client->{quitting} = 1;
+      }
+      # unalias the control session
+      $kernel->alias_remove('control');
+      # die in a few seconds
+      $kernel->delay_set('die', 5);
+      return;
+    }
+
+    chomp $line;
+    # ignore comments and blank lines
+    next if $line =~ /^\#/ or $line !~ /\S/;
+
+    # expand any macros in the line
+    $line =~ s/(?<=[^\\])%(\S+?)%/$heap->{macros}->{$1}
+      or die "Use of undefined macro $1 at $heap->{lineno}\n"/eg;
+    # remove any \-escapes
+    $line =~ s/\\(.)/$1/g;
+    # figure out the type of line
+    if ($line =~ /^#/) {
+      # comment, silently ignore it
+    } elsif ($line =~ /^define (\S+) (.+)$/i) {
+      # define a new macro
+      $heap->{macros}->{$1} = $2;
+    } elsif ($line =~ /^undef (\S+)$/i) {
+      # remove the macro
+      delete $heap->{macros}->{$1};
+    } elsif ($line =~ /^connect (\S+) (\S+) (\S+) (\S+) :(.+)$/i) {
+      # connect a new session (named $1) to server $4
+      my ($name, $nick, $ident, $server, $userinfo, $port) = ($1, $2, $3, $4, $5, 6667);
+      $server = $heap->{servers}->{$server} || $server;
+      if ($server =~ /(.+):(\d+)/) {
+        $server = $1;
+        $port = $2;
+      }
+      die "Client with nick $nick already exists (line $heap->{lineno})" if $heap->{clients}->{$nick};
+      my $alias = "client_$name";
+      POE::Component::IRC->new($alias)
+          or die "Unable to create new user $nick (line $heap->{lineno}): $!";
+      my $client = { name => $name,
+                     nick => $nick,
+                     ready => 0,
+                     expect => [],
+                     expect_alarms => [],
+                     irc => $kernel->alias_resolve($alias),
+                     params => { Nick     => $nick,
+                                 Server   => $server,
+                                 Port     => $port,
+                                 Username => $ident,
+                                 Ircname  => $userinfo,
+                                 Debug    => $heap->{irc_debug},
+                               }
+                   };
+      $client->params->{LocalAddr} = $heap->{vhost}
+        if $heap->{vhost};
+      $heap->{clients}->{$client->{name}} = $client;
+      $heap->{sessions}->{$client->{irc}} = $client;
+      $kernel->call($client->{irc}, 'register', 'all');
+      $kernel->call($client->{irc}, 'connect', $client->{params});
+      $used->{$name} = 1;
+    } elsif ($line =~ /^sync (.+)$/i) {
+      # do multi-way synchronization between every session named in $1
+      my @synced = split(/,|\s/, $1);
+      # first, check that they exist and are ready
+      foreach my $clnt (@synced) {
+        die "Unknown session name $clnt (line $heap->{lineno})" unless $heap->{clients}->{$clnt};
+        goto REDO unless $heap->{clients}->{$clnt}->{ready};
+      }
+      # next we actually send the synchronization signals
+      foreach my $clnt (@synced) {
+        my $client = $heap->{clients}->{$clnt};
+        $client->{sync_wait} = [map { $_ eq $clnt ? () : $heap->{clients}->{$_}->{nick} } @synced];
+        $kernel->call($client->{irc}, 'notice', $client->{sync_wait}, 'SYNC');
+        $kernel->call($session, 'disable_client', $client);
+      }
+    } elsif ($line =~ /^:(\S+) (\S+)(.*)$/i) {
+      # generic command handler
+      my ($names, $cmd, $args) = ($1, lc($2), $3);
+      my (@avail, @unavail);
+      # figure out whether each listed client is available or not
+      foreach my $c (split ',', $names) {
+        my $client = $heap->{clients}->{$c};
+        if (not $client) {
+          print "ERROR: Unknown session name $c (line $heap->{lineno}; ignoring)\n";
+        } elsif (($used->{$c} and not $zero_time->{$cmd}) or not $client->{ready}) {
+          push @unavail, $c;
+        } else {
+          push @avail, $c;
+        }
+      }
+      # redo command with unavailable clients
+      if (@unavail) {
+        # This will break if the command can cause a redo for
+        # available clients.. this should be fixed sometime
+        $line = ':'.join(',', @unavail).' '.$cmd.$args;
+        $heap->{redo} = 1;
+      }
+      # do command with available clients
+      if (@avail) {
+        # split up the argument part of the line
+        $args =~ /^((?:(?: [^:])|[^ ])+)?(?: :(.+))?$/;
+        $args = [($1 ? split(' ', $1) : ()), ($2 ? $2 : ())];
+        # find the client and figure out if we need to wait
+        foreach my $c (@avail) {
+          my $client = $heap->{clients}->{$c};
+          die "Client $c used twice as source (line $heap->{lineno})" if $used->{c} and not $zero_time->{$cmd};
+          $kernel->call($session, 'cmd_'.$cmd, $client, $args);
+          $used->{$c} = 1 unless $zero_time->{$cmd};
+        }
+      }
+    } else {
+      die "Unrecognized input line $heap->{lineno}: $line";
+    }
+    if ($heap->{redo}) {
+    REDO:
+      delete $heap->{redo};
+      $heap->{line} = $line;
+      last;
+    }
+  }
+  # issue new heartbeat with appropriate delay
+  $kernel->delay_set('heartbeat', $delay);
+}
+
+sub drv_timeout_expect {
+  my ($kernel, $session, $client) = @_[KERNEL, SESSION, ARG0];
+  print "ERROR: Dropping timed-out expectation by $client->{name}: ".join(',', @{$client->{expect}->[0]})."\n";
+  $client->{expect_alarms}->[0] = undef;
+  unexpect($kernel, $session, $client);
+}
+
+sub drv_reconnect {
+  my ($kernel, $session, $client) = @_[KERNEL, SESSION, ARG0];
+  $kernel->call($client->{irc}, 'connect', $client->{params});
+}
+
+sub drv_default {
+  my ($kernel, $heap, $sender, $session, $state, $args) = @_[KERNEL, HEAP, SENDER, SESSION, ARG0, ARG1];
+  if ($state =~ /^irc_(\d\d\d)$/) {
+    my $client = $heap->{sessions}->{$sender};
+    if (@{$client->{expect}}
+        and $args->[0] eq $client->{expect}->[0]->[0]
+        and $client->{expect}->[0]->[1] eq "$1") {
+      my $expect = $client->{expect}->[0];
+      my $mismatch;
+      for (my $x=2; ($x<=$#$expect) and ($x<=$#$args) and not $mismatch; $x++) {
+        $mismatch = 1 unless $args->[$x] =~ /$expect->[$x]/i;
+      }
+      unexpect($kernel, $session, $client) unless $mismatch;
+    }
+    return undef;
+  }
+  print "ERROR: Unexpected event $state to test driver (from ".$sender->ID.")\n"
+    unless $state eq '_signal';
+  return undef;
+}
+
+# client-based command issuers
+
+sub cmd_message {
+  my ($kernel, $heap, $event, $client, $args) = @_[KERNEL, HEAP, STATE, ARG0, ARG1];
+  die "Missing arguments" unless $#$args >= 1;
+  # translate each target as appropriate (e.g. *sessionname)
+  my @targets = split(/,/, $args->[0]);
+  foreach my $target (@targets) {
+    if ($target =~ /^\*(.+)$/) {
+      my $other = $heap->{clients}->{$1} or die "Unknown session name $1 (line $heap->{lineno})\n";
+      $target = $other->{nick};
+    }
+  }
+  $kernel->call($client->{irc}, substr($event, 4), \@targets, $args->[1]);
+}
+
+sub cmd_generic {
+  my ($kernel, $heap, $event, $client, $args) = @_[KERNEL, HEAP, STATE, ARG0, ARG1];
+  $event =~ s/^cmd_//;
+  $kernel->call($client->{irc}, $event, @$args);
+}
+
+sub cmd_raw {
+  my ($kernel, $heap, $client, $args) = @_[KERNEL, HEAP, ARG0, ARG1];
+  die "Missing argument" unless $#$args >= 0;
+  $kernel->call($client->{irc}, 'sl', $args->[0]);
+}
+
+sub cmd_sleep {
+  my ($kernel, $session, $heap, $client, $args) = @_[KERNEL, SESSION, HEAP, ARG0, ARG1];
+  die "Missing argument" unless $#$args >= 0;
+  $kernel->call($session, 'disable_client', $client);
+  $kernel->delay_set('enable_client', $args->[0], $client);
+}
+
+sub cmd_wait {
+  my ($kernel, $session, $heap, $client, $args) = @_[KERNEL, SESSION, HEAP, ARG0, ARG1];
+  die "Missing argument" unless $#$args >= 0;
+  # if argument was comma-delimited, split it up (space-delimited is split by generic parser)
+  $args = [split(/,/, $args->[0])] if $args->[0] =~ /,/;
+  # make sure we only wait if all the other clients are ready
+  foreach my $other (@$args) {
+    if (not $heap->{clients}->{$other}->{ready}) {
+      $heap->{redo} = 1;
+      return;
+    }
+  }
+  # disable this client, make the others send SYNC to it
+  $kernel->call($session, 'disable_client', $client);
+  $client->{sync_wait} = [map { $heap->{clients}->{$_}->{nick} } @$args];
+  foreach my $other (@$args) {
+    die "Cannot wait on self" if $other eq $client->{name};
+    $kernel->call($heap->{clients}->{$other}->{irc}, 'notice', $client->{nick}, 'SYNC');
+  }
+}
+
+sub cmd_expect {
+  my ($kernel, $session, $heap, $client, $args) = @_[KERNEL, SESSION, HEAP, ARG0, ARG1];
+  die "Missing argument" unless $#$args >= 0;
+  push @{$client->{expect}}, $args;
+  push @{$client->{expect_alarms}}, $kernel->delay_set('timeout_expect', EXPECT_TIMEOUT, $client);
+  $kernel->call($session, 'disable_client', $client);
+}
+
+# handlers for messages from IRC
+
+sub unexpect {
+  my ($kernel, $session, $client) = @_;
+  shift @{$client->{expect}};
+  my $alarm_id = shift @{$client->{expect_alarms}};
+  $kernel->alarm_remove($alarm_id) if $alarm_id;
+  $kernel->call($session, 'enable_client', $client) unless @{$client->{expect}};
+}
+
+sub check_expect {
+  my ($kernel, $session, $heap, $poe_sender, $sender, $text) = @_[KERNEL, SESSION, HEAP, SENDER, ARG0, ARG1];
+  my $client = $heap->{sessions}->{$poe_sender};
+  my $expected = $client->{expect}->[0];
+
+  # check sender
+  if ($expected->[0] =~ /\*(.+)/) {
+    # we expect *sessionname, so look up session's current nick
+    my $exp = $1;
+    $sender =~ /^(.+)!/;
+    return 0 if lc($heap->{clients}->{$exp}->{nick}) ne lc($1);
+  } elsif ($expected->[0] =~ /^:?(.+!.+)/) {
+    # expect :nick!user@host, so compare whole thing
+    return 0 if lc($1) ne lc($sender);
+  } else {
+    # we only expect :nick, so compare that part
+    $sender =~ /^:?(.+)!/;
+    return 0 if lc($expected->[0]) ne lc($1);
+  }
+
+  # compare text
+  return 0 if lc($text) !~ /$expected->[2]/i;
+
+  # drop expectation of event
+  unexpect($kernel, $session, $client);
+}
+
+sub irc_connected {
+  my ($kernel, $session, $heap, $sender) = @_[KERNEL, SESSION, HEAP, SENDER];
+  my $client = $heap->{sessions}->{$sender};
+  print "Client $client->{name} connected to server $_[ARG0]\n" if $heap->{verbose};
+  $kernel->call($session, 'enable_client', $client);
+}
+
+sub irc_disconnected {
+  my ($kernel, $session, $heap, $sender, $server) = @_[KERNEL, SESSION, HEAP, SENDER, ARG0];
+  my $client = $heap->{sessions}->{$sender};
+  print "Client $client->{name} disconnected from server $_[ARG0]\n" if $heap->{verbose};
+  if ($client->{quitting}) {
+    $kernel->call($sender, 'unregister', 'all');
+    delete $heap->{sessions}->{$sender};
+    delete $heap->{clients}->{$client->{name}};
+  } else {
+    if ($client->{disconnect_expected}) {
+      delete $client->{disconnect_expected};
+    } else {
+      print "Got unexpected disconnect for $client->{name} (nick $client->{nick})\n";
+    }
+    $kernel->call($session, 'disable_client', $client);
+    $kernel->delay_set('reconnect', $client->{throttled} ? THROTTLED_TIMEOUT : RECONNECT_TIMEOUT, $client);
+    delete $client->{throttled};
+  }
+}
+
+sub irc_socketerr {
+  my ($kernel, $session, $heap, $sender, $msg) = @_[KERNEL, SESSION, HEAP, SENDER, ARG0];
+  my $client = $heap->{sessions}->{$sender};
+  print "Client $client->{name} (re-)connect error: $_[ARG0]\n";
+  if ($client->{quitting}) {
+    $kernel->call($sender, 'unregister', 'all');
+    delete $heap->{sessions}->{$sender};
+    delete $heap->{clients}->{$client->{name}};
+  } else {
+    if ($client->{disconnect_expected}) {
+      delete $client->{disconnect_expected};
+    } else {
+      print "Got unexpected disconnect for $client->{name} (nick $client->{nick})\n";
+    }
+    $kernel->call($session, 'disable_client', $client);
+    $kernel->delay_set('reconnect', $client->{throttled} ? THROTTLED_TIMEOUT : RECONNECT_TIMEOUT, $client);
+    delete $client->{throttled};
+  }
+}
+
+sub irc_notice {
+  my ($kernel, $session, $heap, $sender, $from, $to, $text) = @_[KERNEL, SESSION, HEAP, SENDER, ARG0, ARG1, ARG2];
+  my $client = $heap->{sessions}->{$sender};
+  if ($client->{sync_wait} and $text eq 'SYNC') {
+    $from =~ s/!.+$//;
+    my $x;
+    # find who sent it..
+    for ($x=0; $x<=$#{$client->{sync_wait}}; $x++) {
+      last if $from eq $client->{sync_wait}->[$x];
+    }
+    # exit if we don't expect them
+    if ($x>$#{$client->{sync_wait}}) {
+      print "Got unexpected SYNC from $from to $client->{name} ($client->{nick})\n";
+      return;
+    }
+    # remove from the list of people we're waiting for
+    splice @{$client->{sync_wait}}, $x, 1;
+    # re-enable client if we're done waiting
+    if ($#{$client->{sync_wait}} == -1) {
+      delete $client->{sync_wait};
+      $kernel->call($session, 'enable_client', $client);
+    }
+  } elsif (@{$client->{expect}}
+           and $client->{expect}->[0]->[1] =~ /notice/i) {
+    check_expect(@_[0..ARG0], $text);
+  }
+}
+
+sub irc_msg {
+  my ($kernel, $session, $heap, $sender, $from, $to, $text) = @_[KERNEL, SESSION, HEAP, SENDER, ARG0, ARG1, ARG2];
+  my $client = $heap->{sessions}->{$sender};
+  if (@{$client->{expect}}
+      and $client->{expect}->[0]->[1] =~ /msg/i) {
+    check_expect(@_[0..ARG0], $text);
+  }
+}
+
+sub irc_public {
+  my ($kernel, $session, $heap, $sender, $from, $to, $text) = @_[KERNEL, SESSION, HEAP, SENDER, ARG0, ARG1, ARG2];
+  my $client = $heap->{sessions}->{$sender};
+  if (@{$client->{expect}}
+      and $client->{expect}->[0]->[1] =~ /public/i
+      and grep($client->{expect}->[0]->[2], @$to)) {
+    splice @{$client->{expect}->[0]}, 2, 1;
+    check_expect(@_[0..ARG0], $text);
+  }
+}
+
+sub irc_invite {
+  my ($kernel, $session, $heap, $sender, $from, $to) = @_[KERNEL, SESSION, HEAP, SENDER, ARG0, ARG1, ARG2];
+  my $client = $heap->{sessions}->{$sender};
+  if (ref $client->{expect} eq 'ARRAY'
+      and $client->{expect}->[0]->[1] =~ /invite/i
+      and $to =~ /$client->{expect}->[0]->[2]/) {
+    check_expect(@_[0..ARG0], $to);
+  }
+}
+
+sub irc_error {
+  my ($kernel, $session, $heap, $sender, $what) = @_[KERNEL, SESSION, HEAP, SENDER, ARG0];
+  my $client = $heap->{sessions}->{$sender};
+  if (@{$client->{expect}}
+      and $client->{expect}->[0]->[1] =~ /error/i) {
+    splice @{$client->{expect}->[0]}, 2, 1;
+    unexpect($kernel, $session, $client);
+    $client->{disconnect_expected} = 1;
+  } else {
+    print "ERROR: From server to $client->{name}: $what\n";
+  }
+  $client->{throttled} = 1 if $what =~ /throttled/i;
+}
diff --git a/ircd/test/test_stub.c b/ircd/test/test_stub.c
new file mode 100644 (file)
index 0000000..e5fe4a4
--- /dev/null
@@ -0,0 +1,41 @@
+/* test_stub.c - support stubs for test programs */
+
+#include "client.h"
+#include "ircd_log.h"
+#include "s_debug.h"
+#include <stdarg.h>
+#include <stdio.h>
+
+struct Client me;
+int log_inassert;
+
+void
+log_write(enum LogSys subsys, enum LogLevel severity, unsigned int flags,
+          const char *fmt, ...)
+{
+    va_list args;
+
+    va_start(args, fmt);
+    vfprintf(stderr, fmt, args);
+    fputc('\n', stderr);
+    va_end(args);
+}
+
+void
+debug(int level, const char *form, ...)
+{
+    va_list args;
+
+    va_start(args, form);
+    vfprintf(stdout, form, args);
+    fputc('\n', stdout);
+    va_end(args);
+}
+
+int
+exit_client(struct Client *cptr, struct Client *victim, struct Client *killer,
+            const char *comment)
+{
+    Debug((DEBUG_LIST, "exit_client(%p, %p, %p, \"%s\")\n", cptr, victim, killer, comment));
+    return 0;
+}
diff --git a/ircd/umkpasswd.c b/ircd/umkpasswd.c
new file mode 100644 (file)
index 0000000..9bddcdb
--- /dev/null
@@ -0,0 +1,460 @@
+/*
+ * IRC - Internet Relay Chat, ircd/umkpasswd.c
+ * Copyright (C) 2002 hikari
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id: umkpasswd.c 1842 2007-11-17 13:48:15Z entrope $
+*/
+#include "config.h"
+#include <unistd.h>
+#include <ctype.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+/* #include <assert.h> -- Now using assert in ircd_log.h */
+
+/* ircu headers */
+#include "ircd_alloc.h"
+#include "ircd_log.h" /* for ircd's assert.h */
+#include "ircd_string.h"
+#include "umkpasswd.h"
+#include "s_debug.h"
+#include "ircd_md5.h"
+
+/* crypto mech headers */
+#include "ircd_crypt.h"
+#include "ircd_crypt_smd5.h"
+#include "ircd_crypt_native.h"
+#include "ircd_crypt_plain.h"
+
+/* bleah, evil globals */
+umkpasswd_conf_t* umkpasswd_conf;
+crypt_mechs_t* crypt_mechs_root;
+int log_inassert = 0;
+time_t CurrentTime;
+
+void sendto_opmask_butone(struct Client *one, unsigned int mask,
+                         const char *pattern, ...)
+{
+  /* only needed with memdebug, which also calls Debug() */
+}
+
+void copyright(void)
+{
+  fprintf(stderr, "umkpasswd - Copyright (c) 2002 hikari\n");
+return;
+}
+
+void show_help(void)
+{
+#ifdef DEBUGMODE
+ char *debughelp = "[-d <level>] ";
+#else
+ char *debughelp = "";
+#endif
+
+ copyright();
+ /*fprintf(stderr, "umkpasswd [-l] [[[-a]||[-u]] <username>] [-y <class>] %s[-c <file>] -m <mech> [password]\n\n", debughelp);*/
+ fprintf(stderr, "umkpasswd [-l] %s-m <mech> [password]\n\n", debughelp);
+ fprintf(stderr, "  -l            List mechanisms available.\n");
+#if 0
+ fprintf(stderr, "  -a <user>     Add user to conf file.\n");
+ fprintf(stderr, "  -u <user>     Update user's password field.\n");
+ fprintf(stderr, "  -y <class>    Class to place oper in.\n");
+#endif
+ fprintf(stderr, "  -m <mech>     Mechanism to use [MANDATORY].\n");
+#ifdef DEBUGMODE
+ fprintf(stderr, "  -d <level>    Debug level to run at.\n");
+#endif
+/*
+ fprintf(stderr, "  -c <file>     Conf file to use, default is DPATH/CPATH.\n\n");
+*/
+return;
+}
+
+/* our implementation of debug() */
+void debug(int level, const char *form, ...)
+{
+va_list vl;
+int err = errno;
+
+  if (level <= (umkpasswd_conf->debuglevel))
+  {
+    va_start(vl, form);
+    vfprintf(stderr, form, vl);
+    fprintf(stderr, "\n");
+    va_end(vl);
+  }
+  errno = err;
+}
+
+/* quick implementation of log_write() for assert() call */
+void log_write(enum LogSys subsys, enum LogLevel severity,
+              unsigned int flags, const char *fmt, ...)
+{
+  va_list vl;
+  va_start(vl, fmt);
+  vfprintf(stderr, fmt, vl);
+  fprintf(stderr, "\n");
+  va_end(vl);
+}
+
+/* quick and dirty salt generator */
+char *make_salt(const char *salts)
+{
+char *tmp = NULL;
+long int n = 0;
+
+ /* try and get around them running this time after time in quick succession */
+ sleep(1);
+ srandom((unsigned int)time(NULL));
+
+ if((tmp = calloc(3, sizeof(char))) != NULL)
+ {
+  /* can't optimize this much more than just doing it twice */
+  n = ((float)(strlen(salts))*random()/(RAND_MAX+1.0));
+  memcpy(tmp, (salts+n), 1);
+  sleep(2);
+  n = ((float)(strlen(salts))*random()/(RAND_MAX+1.0));
+  memcpy((tmp+1), (salts+n), 1);
+
+  Debug((DEBUG_DEBUG, "salts = %s", salts));
+  Debug((DEBUG_DEBUG, "strlen(salts) = %d", strlen(salts)));
+ }
+
+return tmp;
+}
+
+/* our implementation of ircd_crypt_register_mech() */
+int ircd_crypt_register_mech(crypt_mech_t* mechanism)
+{
+crypt_mechs_t* crypt_mech;
+
+ Debug((DEBUG_INFO, "ircd_crypt_register_mech: registering mechanism: %s", mechanism->shortname));
+
+ /* try to allocate some memory for the new mechanism */
+ if ((crypt_mech = (crypt_mechs_t*)MyMalloc(sizeof(crypt_mechs_t))) == NULL)
+ {
+  /* aww poot, we couldn't get any memory, scream a little then back out */
+  Debug((DEBUG_MALLOC, "ircd_crypt_register_mech: could not allocate memory for %s", mechanism->shortname));
+  return -1;
+ }
+
+ /* ok, we have memory, initialise it */
+ memset(crypt_mech, 0, sizeof(crypt_mechs_t));
+
+ /* assign the data */
+ crypt_mech->mech = mechanism;
+ crypt_mech->next = crypt_mech->prev = NULL;
+
+ /* first of all, is there anything there already? */
+ if(crypt_mechs_root->next == NULL)
+ {
+  /* nope, just add ourself */
+  crypt_mechs_root->next = crypt_mechs_root->prev = crypt_mech;
+ } else {
+  /* nice and simple, put ourself at the end */
+  crypt_mech->prev = crypt_mechs_root->prev;
+  crypt_mech->next = NULL;
+  crypt_mechs_root->prev = crypt_mech->prev->next = crypt_mech;
+ }
+
+ /* we're done */
+ Debug((DEBUG_INFO, "ircd_crypt_register_mech: registered mechanism: %s, crypt_function is at 0x%X.", crypt_mech->mech->shortname, &crypt_mech->mech->crypt_function));
+ Debug((DEBUG_INFO, "ircd_crypt_register_mech: %s: %s", crypt_mech->mech->shortname, crypt_mech->mech->description));
+
+return 0;
+}
+
+void sum(char* tmp)
+{
+char* str;
+FILE* file;
+MD5_CTX context;
+int len;
+unsigned char buffer[1024], digest[16], vstr[32];
+
+vstr[0] = '\0';
+ str = tmp + strlen(tmp);
+ while (str[-1] == '\r' || str[-1] == '\n') *--str = '\0';
+ if (NULL == (file = fopen(tmp, "r")))
+ {
+  fprintf(stderr, "unable to open %s: %s", tmp, strerror(errno));
+  exit(0);
+ }
+ MD5Init(&context);
+ while ((fgets((char*)buffer, sizeof(buffer), file)) != NULL)
+ {
+  MD5Update(&context, buffer, strlen((char*)buffer));
+  str = strstr((char*)buffer, "$Id: ");
+  if (str != NULL)
+  {
+   for (str += 5; !isspace(*str); ++str) {}
+   while (isspace(*++str)) {}
+   for (len = 0; !isspace(str[len]); ++len) vstr[len] = str[len];
+   vstr[len] = '\0';
+   break;
+  }
+ }
+ while ((len = fread (buffer, 1, sizeof(buffer), file)))
+  MD5Update(&context, buffer, len);
+ MD5Final(digest, &context);
+ fclose(file);
+
+ str = strrchr(tmp, '/');
+ printf("    \"[ %s: ", str ? (str + 1) : tmp);
+ for (len = 0; len < 16; len++)
+  printf ("%02x", digest[len]);
+ printf(" %s ]\",\n", vstr);
+}
+
+/* dump the loaded mechs list */
+void show_mechs(void)
+{
+crypt_mechs_t* mechs;
+
+ copyright();
+ printf("\nAvailable mechanisms:\n");
+
+ if(crypt_mechs_root == NULL)
+  return;
+
+ mechs = crypt_mechs_root->next;
+
+ for(;;)
+ {
+  if(mechs == NULL)
+   return;
+
+  printf(" %s\t\t%s\n", mechs->mech->mechname, mechs->mech->description);
+
+  mechs = mechs->next;
+ }
+}
+
+/* load in the mech "modules" */
+void load_mechs(void)
+{
+ /* we need these loaded by hand for now */
+
+ ircd_register_crypt_native();
+ ircd_register_crypt_smd5();
+ ircd_register_crypt_plain(); /* yes I know it's slightly pointless */
+
+return;
+}
+
+crypt_mechs_t* hunt_mech(const char* mechname)
+{
+crypt_mechs_t* mech;
+
+ assert(NULL != mechname);
+
+ if(crypt_mechs_root == NULL)
+  return NULL;
+
+ mech = crypt_mechs_root->next;
+
+ for(;;)
+ {
+  if(mech == NULL)
+   return NULL;
+
+  if(0 == (ircd_strcmp(mech->mech->mechname, mechname)))
+   return mech;
+
+  mech = mech->next;
+ }
+}
+
+char* crypt_pass(const char* pw, const char* mech)
+{
+crypt_mechs_t* crypt_mech;
+char* salt, *untagged, *tagged;
+
+ assert(NULL != pw);
+ assert(NULL != mech);
+
+ Debug((DEBUG_DEBUG, "pw = %s\n", pw));
+ Debug((DEBUG_DEBUG, "mech = %s\n", mech));
+
+ if (NULL == (crypt_mech = hunt_mech(mech)))
+ {
+  printf("Unable to find mechanism %s\n", mech);
+  return NULL;
+ }
+
+ salt = make_salt(default_salts);
+
+ untagged = (char *)CryptFunc(crypt_mech->mech)(pw, salt);
+ tagged = (char *)MyMalloc(strlen(untagged)+CryptTokSize(crypt_mech->mech)+1);
+ memset(tagged, 0, strlen(untagged)+CryptTokSize(crypt_mech->mech)+1);
+ strncpy(tagged, CryptTok(crypt_mech->mech), CryptTokSize(crypt_mech->mech));
+ strncpy(tagged+CryptTokSize(crypt_mech->mech), untagged, strlen(untagged));
+
+return tagged;
+}
+
+char* parse_arguments(int argc, char **argv)
+{
+int len = 0, c = 0;
+const char* options = "a:d:lm:u:y:5";
+
+ umkpasswd_conf = (umkpasswd_conf_t*)MyMalloc(sizeof(umkpasswd_conf_t));
+
+ umkpasswd_conf->flags = 0;
+ umkpasswd_conf->debuglevel = 0;
+ umkpasswd_conf->operclass = 0;
+ umkpasswd_conf->user = NULL;
+ umkpasswd_conf->mech = NULL;
+
+
+ len = strlen(DPATH) + strlen(CPATH) + 2;
+ umkpasswd_conf->conf = (char *)MyMalloc(len*sizeof(char));
+ memset(umkpasswd_conf->conf, 0, len*sizeof(char));
+ ircd_strncpy(umkpasswd_conf->conf, DPATH, strlen(DPATH));
+ *((umkpasswd_conf->conf) + strlen(DPATH)) = '/';
+ ircd_strncpy((umkpasswd_conf->conf) + strlen(DPATH) + 1, CPATH, strlen(CPATH));
+
+ len = 0;
+
+ while ((EOF != (c = getopt(argc, argv, options))) && !len)
+ {
+  switch (c)
+  {
+   case '5':
+   {
+    char t1[1024];
+    while (fgets(t1, sizeof(t1), stdin)) sum(t1);
+   }
+   exit(0);
+
+   case 'y':
+    umkpasswd_conf->operclass = atoi(optarg);
+    if (umkpasswd_conf->operclass < 0)
+     umkpasswd_conf->operclass = 0;
+   break;
+
+   case 'u':
+    if(umkpasswd_conf->flags & ACT_ADDOPER)
+    {
+     fprintf(stderr, "-a and -u are mutually exclusive.  Use either or neither.\n");
+     abort(); /* b0rk b0rk b0rk */
+    }
+
+    umkpasswd_conf->flags |= ACT_UPDOPER;
+    umkpasswd_conf->user = optarg;
+   break;
+
+   case 'm':
+    umkpasswd_conf->mech = optarg;
+   break;
+
+   case 'l':
+    load_mechs();
+    show_mechs();
+    exit(0);
+   break;
+
+   case 'd':
+    umkpasswd_conf->debuglevel = atoi(optarg);
+    if (umkpasswd_conf->debuglevel < 0)
+     umkpasswd_conf->debuglevel = 0;
+   break;
+
+   case 'c':
+    umkpasswd_conf->conf = optarg;
+   break;
+
+   case 'a':
+    if(umkpasswd_conf->flags & ACT_UPDOPER) 
+    {
+     fprintf(stderr, "-a and -u are mutually exclusive.  Use either or neither.\n");
+     abort(); /* b0rk b0rk b0rk */
+    }
+
+    umkpasswd_conf->flags |= ACT_ADDOPER;
+    umkpasswd_conf->user = optarg;
+   break;
+
+   default:
+    /* unknown option - spit out syntax and b0rk */
+    show_help();
+    exit(1);
+   break;
+  }
+ }
+
+ Debug((DEBUG_DEBUG, "flags = %d", umkpasswd_conf->flags));
+ Debug((DEBUG_DEBUG, "operclass = %d", umkpasswd_conf->operclass));
+ Debug((DEBUG_DEBUG, "debug = %d", umkpasswd_conf->debuglevel));
+
+ if (NULL != umkpasswd_conf->mech)
+  Debug((DEBUG_DEBUG, "mech = %s", umkpasswd_conf->mech));
+ else
+  Debug((DEBUG_DEBUG, "mech is unset"));
+
+ if (NULL != umkpasswd_conf->conf)
+  Debug((DEBUG_DEBUG, "conf = %s", umkpasswd_conf->conf));
+ else
+  Debug((DEBUG_DEBUG, "conf is unset"));
+
+ if (NULL != umkpasswd_conf->user)
+  Debug((DEBUG_DEBUG, "user = %s", umkpasswd_conf->user));
+ else
+  Debug((DEBUG_DEBUG, "user is unset"));
+
+/* anything left over should be password */
+return argv[optind];
+}
+
+int main(int argc, char **argv)
+{
+char* pw, *crypted_pw;
+
+ crypt_mechs_root = (crypt_mechs_t*)MyMalloc(sizeof(crypt_mechs_t));
+ crypt_mechs_root->mech = NULL;
+ crypt_mechs_root->next = crypt_mechs_root->prev = NULL;
+
+ if (argc < 2)
+ {
+  show_help();
+  exit(0);
+ }
+
+ pw = parse_arguments(argc, argv);
+ load_mechs();
+
+ if (NULL == umkpasswd_conf->mech)
+ {
+  fprintf(stderr, "No mechanism specified.\n");
+  abort();
+ }
+
+ if (NULL == pw)
+ {
+  pw = getpass("Password: ");
+ }
+ crypted_pw = crypt_pass(pw, umkpasswd_conf->mech);
+
+ printf("Crypted Pass: %s\n", crypted_pw);
+ memset(pw, 0, strlen(pw));
+
+return 0;
+}
diff --git a/ircd/uping.c b/ircd/uping.c
new file mode 100644 (file)
index 0000000..fed1fae
--- /dev/null
@@ -0,0 +1,484 @@
+/*
+ * IRC - Internet Relay Chat, ircd/uping.c
+ * Copyright (C) 1994 Carlo Wood ( Run @ undernet.org )
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+/** @file
+ * @brief UDP ping implementation.
+ * @version $Id: uping.c 1626 2006-03-14 03:45:52Z entrope $
+ */
+#include "config.h"
+
+#include "uping.h"
+#include "client.h"
+#include "ircd.h"
+#include "ircd_alloc.h"
+#include "ircd_events.h"
+#include "ircd_log.h"
+#include "ircd_osdep.h"
+#include "ircd_string.h"
+#include "match.h"
+#include "msg.h"
+#include "numeric.h"
+#include "numnicks.h"
+#include "s_bsd.h"    /* VirtualHost */
+#include "s_conf.h"
+#include "s_debug.h"
+#include "s_misc.h"
+#include "s_user.h"
+#include "send.h"
+#include "sys.h"
+
+/* #include <assert.h> -- Now using assert in ircd_log.h */
+#include <errno.h>
+#include <netdb.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <unistd.h>
+
+#define UPINGTIMEOUT 60   /**< Timeout waiting for ping responses */
+
+static struct UPing* pingList = 0; /**< Linked list of UPing structs */
+static struct Socket upingSock_v4; /**< Socket struct for IPv4 upings */
+static struct Socket upingSock_v6; /**< Socket struct for IPv6 upings */
+
+/** Start iteration of uping list.
+ * @return Start of uping list.
+ */
+struct UPing* uping_begin(void)
+{
+  return pingList;
+}
+
+/** Removes \a p from uping list.
+ * @param[in,out] p UPing to remove from list.
+ */
+static void uping_erase(struct UPing* p)
+{
+  struct UPing* it;
+  struct UPing* last = 0;
+
+  assert(0 != p);
+
+  for (it = pingList; it; last = it, it = it->next) {
+    if (p == it) {
+      if (last)
+        last->next = p->next;
+      else
+        pingList = p->next;
+      break;
+    }
+  }
+}
+
+/** Callback for uping listener socket.
+ * Reads a uping from the socket and respond, but not more than 10
+ * times per second.
+ * @param[in] ev I/O event for uping socket.
+ */
+static void uping_echo_callback(struct Event* ev)
+{
+  struct Socket      *sock;
+  struct irc_sockaddr from;
+  unsigned int       len = 0;
+  static time_t      last = 0;
+  static int         counter = 0;
+  char               buf[BUFSIZE + 1];
+
+  assert(ev_type(ev) == ET_READ || ev_type(ev) == ET_ERROR);
+  sock = ev_socket(ev);
+  assert(sock == &upingSock_v4 || sock == &upingSock_v6);
+
+  Debug((DEBUG_DEBUG, "UPING: uping_echo"));
+
+  if (IO_SUCCESS != os_recvfrom_nonb(s_fd(sock), buf, BUFSIZE, &len, &from))
+    return;
+  /*
+   * count em even if we're getting flooded so we can tell we're getting
+   * flooded.
+   */
+  ++ServerStats->uping_recv;
+  if (len < 19)
+    return;
+  else if (CurrentTime != last) {
+    counter = 0;
+    last = CurrentTime;
+  } else if (++counter > 10)
+    return;
+  os_sendto_nonb(s_fd(sock), buf, len, NULL, 0, &from);
+}
+
+/** Initialize a UDP socket for upings.
+ * @returns 0 on success, -1 on error.
+ */
+int uping_init(void)
+{
+  struct irc_sockaddr from;
+  int fd;
+
+  memcpy(&from, &VirtualHost_v4, sizeof(from));
+  from.port = atoi(UDP_PORT);
+
+  fd = os_socket(&from, SOCK_DGRAM, "IPv4 uping listener", AF_INET);
+  if (fd < 0)
+    return -1;
+  if (!socket_add(&upingSock_v4, uping_echo_callback, 0, SS_DATAGRAM,
+                  SOCK_EVENT_READABLE, fd)) {
+    Debug((DEBUG_ERROR, "UPING: Unable to queue fd to event system"));
+    close(fd);
+    return -1;
+  }
+
+#ifdef AF_INET6
+  memcpy(&from, &VirtualHost_v6, sizeof(from));
+  from.port = atoi(UDP_PORT);
+
+  fd = os_socket(&from, SOCK_DGRAM, "IPv6 uping listener", AF_INET6);
+  if (fd < 0)
+    return -1;
+  if (!socket_add(&upingSock_v6, uping_echo_callback, 0, SS_DATAGRAM,
+                  SOCK_EVENT_READABLE, fd)) {
+    Debug((DEBUG_ERROR, "UPING: Unable to queue fd to event system"));
+    close(fd);
+    return -1;
+  }
+#endif
+
+  return 0;
+}
+
+
+/** Callback for socket activity on an outbound uping socket.
+ * @param[in] ev I/O event for socket.
+ */
+static void uping_read_callback(struct Event* ev)
+{
+  struct UPing *pptr;
+
+  assert(0 != ev_socket(ev));
+  assert(0 != s_data(ev_socket(ev)));
+
+  pptr = (struct UPing*) s_data(ev_socket(ev));
+
+  Debug((DEBUG_SEND, "uping_read_callback called, %p (%d)", pptr,
+        ev_type(ev)));
+
+  if (ev_type(ev) == ET_DESTROY) { /* being destroyed */
+    pptr->freeable &= ~UPING_PENDING_SOCKET;
+
+    if (!pptr->freeable)
+      MyFree(pptr); /* done with it, finally */
+  } else {
+    assert(ev_type(ev) == ET_READ || ev_type(ev) == ET_ERROR);
+
+    uping_read(pptr); /* read uping response */
+  }
+}
+
+/** Timer callback to send another outbound uping.
+ * @param[in] ev Event for uping timer.
+ */
+static void uping_sender_callback(struct Event* ev)
+{
+  struct UPing *pptr;
+
+  assert(0 != ev_timer(ev));
+  assert(0 != t_data(ev_timer(ev)));
+
+  pptr = (struct UPing*) t_data(ev_timer(ev));
+
+  Debug((DEBUG_SEND, "uping_sender_callback called, %p (%d)", pptr,
+        ev_type(ev)));
+
+  if (ev_type(ev) == ET_DESTROY) { /* being destroyed */
+    pptr->freeable &= ~UPING_PENDING_SENDER;
+
+    if (!pptr->freeable)
+      MyFree(pptr); /* done with it, finally */
+  } else {
+    assert(ev_type(ev) == ET_EXPIRE);
+
+    pptr->lastsent = CurrentTime; /* store last ping time */
+    uping_send(pptr); /* send a ping */
+
+    if (pptr->sent == pptr->count) /* done sending pings, don't send more */
+      timer_del(ev_timer(ev));
+  }
+}
+
+/** Timer callback to stop upings.
+ * @param[in] ev Event for uping expiration.
+ */
+static void uping_killer_callback(struct Event* ev)
+{
+  struct UPing *pptr;
+
+  assert(0 != ev_timer(ev));
+  assert(0 != t_data(ev_timer(ev)));
+
+  pptr = (struct UPing*) t_data(ev_timer(ev));
+
+  Debug((DEBUG_SEND, "uping_killer_callback called, %p (%d)", pptr,
+        ev_type(ev)));
+
+  if (ev_type(ev) == ET_DESTROY) { /* being destroyed */
+    pptr->freeable &= ~UPING_PENDING_KILLER;
+
+    if (!pptr->freeable)
+      MyFree(pptr); /* done with it, finally */
+  } else {
+    assert(ev_type(ev) == ET_EXPIRE);
+
+    uping_end(pptr); /* <FUDD>kill the uping, kill the uping!</FUDD> */
+  }
+}
+
+/** Start a uping.
+ * This sets up the timers, UPing flags, and sends a notice to the
+ * requesting client.
+ */
+static void uping_start(struct UPing* pptr)
+{
+  assert(0 != pptr);
+
+  timer_add(timer_init(&pptr->sender), uping_sender_callback, (void*) pptr,
+           TT_PERIODIC, 1);
+  timer_add(timer_init(&pptr->killer), uping_killer_callback, (void*) pptr,
+           TT_RELATIVE, UPINGTIMEOUT);
+  pptr->freeable |= UPING_PENDING_SENDER | UPING_PENDING_KILLER;
+
+  sendcmdto_one(&me, CMD_NOTICE, pptr->client, "%C :Sending %d ping%s to %s",
+               pptr->client, pptr->count, (pptr->count == 1) ? "" : "s",
+               pptr->name);
+  pptr->active = 1;
+}
+
+/** Send a uping to another server.
+ * @param[in] pptr Descriptor for uping.
+ */
+void uping_send(struct UPing* pptr)
+{
+  struct timeval tv;
+  char buf[BUFSIZE + 1];
+
+  assert(0 != pptr);
+  if (pptr->sent == pptr->count)
+    return;
+  memset(buf, 0, sizeof(buf));
+
+  gettimeofday(&tv, NULL);
+  sprintf(buf, " %10lu%c%6lu", (unsigned long)tv.tv_sec, '\0', (unsigned long)tv.tv_usec);
+
+  Debug((DEBUG_SEND, "send_ping: sending [%s %s] to %s.%d on %d",
+         buf, &buf[12],
+          ircd_ntoa(&pptr->addr.addr), pptr->addr.port,
+         pptr->fd));
+
+  if (os_sendto_nonb(pptr->fd, buf, BUFSIZE, NULL, 0, &pptr->addr) != IO_SUCCESS)
+  {
+    const char* msg = strerror(errno);
+    if (!msg)
+      msg = "Unknown error";
+    if (pptr->client)
+      sendcmdto_one(&me, CMD_NOTICE, pptr->client, "%C :UPING: send failed: "
+                   "%s", pptr->client, msg);
+    Debug((DEBUG_DEBUG, "UPING: send_ping: sendto failed on %d: %s", pptr->fd, msg));
+    uping_end(pptr);
+    return;
+  }
+  ++pptr->sent;
+}
+
+/** Read the response from an outbound uping.
+ * @param[in] pptr UPing to check.
+ */
+void uping_read(struct UPing* pptr)
+{
+  struct irc_sockaddr sin;
+  struct timeval     tv;
+  unsigned int       len;
+  unsigned int       pingtime;
+  char*              s;
+  char               buf[BUFSIZE + 1];
+  IOResult           ior;
+
+  assert(0 != pptr);
+
+  gettimeofday(&tv, NULL);
+
+  ior = os_recvfrom_nonb(pptr->fd, buf, BUFSIZE, &len, &sin);
+  if (IO_BLOCKED == ior)
+    return;
+  else if (IO_FAILURE == ior) {
+    const char* msg = strerror(errno);
+    if (!msg)
+      msg = "Unknown error";
+    sendcmdto_one(&me, CMD_NOTICE, pptr->client, "%C :UPING: receive error: "
+                 "%s", pptr->client, msg);
+    uping_end(pptr);
+    return;
+  }
+
+  if (len < 19)
+    return;                    /* Broken packet */
+
+  ++pptr->received;
+
+  buf[len] = 0;
+  pingtime = (tv.tv_sec - atol(&buf[1])) * 1000
+             + (tv.tv_usec - atol(buf + strlen(buf) + 1)) / 1000;
+
+  pptr->ms_ave += pingtime;
+  if (!pptr->ms_min || pptr->ms_min > pingtime)
+    pptr->ms_min = pingtime;
+  if (pingtime > pptr->ms_max)
+    pptr->ms_max = pingtime;
+
+  timer_chg(&pptr->killer, TT_RELATIVE, UPINGTIMEOUT);
+
+  s = pptr->buf + strlen(pptr->buf);
+  sprintf(s, " %u", pingtime);
+
+  if (pptr->received == pptr->count)
+    uping_end(pptr);
+  return;
+}
+
+/** Start sending upings to a server.
+ * @param[in] sptr Client requesting the upings.
+ * @param[in] aconf ConfItem containing the address to ping.
+ * @param[in] port Port number to ping.
+ * @param[in] count Number of times to ping (should be at least 20).
+ * @return Zero.
+ */
+int uping_server(struct Client* sptr, struct ConfItem* aconf, int port, int count)
+{
+  int fd;
+  int family = 0;
+  struct UPing* pptr;
+  struct irc_sockaddr *local;
+
+  assert(0 != sptr);
+  assert(0 != aconf);
+
+  if (!irc_in_addr_valid(&aconf->address.addr)) {
+    sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :UPING: Host lookup failed for "
+                 "%s", sptr, aconf->name);
+    return 0;
+  }
+
+  if (IsUPing(sptr))
+    uping_cancel(sptr, sptr);  /* Cancel previous ping request */
+
+  if (irc_in_addr_is_ipv4(&aconf->address.addr)) {
+    local = &VirtualHost_v4;
+    family = AF_INET;
+  } else {
+    local = &VirtualHost_v6;
+  }
+  fd = os_socket(local, SOCK_DGRAM, "Outbound uping socket", family);
+  if (fd < 0)
+    return 0;
+
+  pptr = (struct UPing*) MyMalloc(sizeof(struct UPing));
+  assert(0 != pptr);
+  memset(pptr, 0, sizeof(struct UPing));
+
+  if (!socket_add(&pptr->socket, uping_read_callback, (void*) pptr,
+                 SS_DATAGRAM, SOCK_EVENT_READABLE, fd)) {
+    sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :UPING: Can't queue fd for "
+                 "reading", sptr);
+    close(fd);
+    MyFree(pptr);
+    return 0;
+  }
+
+  pptr->fd                  = fd;
+  memcpy(&pptr->addr.addr, &aconf->address.addr, sizeof(pptr->addr.addr));
+  pptr->addr.port           = port;
+  pptr->count               = IRCD_MIN(20, count);
+  pptr->client              = sptr;
+  pptr->freeable            = UPING_PENDING_SOCKET;
+  strcpy(pptr->name, aconf->name);
+
+  pptr->next = pingList;
+  pingList   = pptr;
+
+  SetUPing(sptr);
+  uping_start(pptr);
+  return 0;
+}
+
+/** Clean up a UPing structure, reporting results to the requester.
+ * @param[in,out] pptr UPing results.
+ */
+void uping_end(struct UPing* pptr)
+{
+  Debug((DEBUG_DEBUG, "uping_end: %p", pptr));
+
+  if (pptr->client) {
+    if (pptr->lastsent) {
+      if (0 < pptr->received) {
+       sendcmdto_one(&me, CMD_NOTICE, pptr->client, "%C :UPING %s%s",
+                     pptr->client, pptr->name, pptr->buf);
+       sendcmdto_one(&me, CMD_NOTICE, pptr->client, "%C :UPING Stats: "
+                     "sent %d recvd %d ; min/avg/max = %u/%u/%u ms",
+                     pptr->client, pptr->sent, pptr->received, pptr->ms_min,
+                     (2 * pptr->ms_ave) / (2 * pptr->received), pptr->ms_max);
+      } else
+       sendcmdto_one(&me, CMD_NOTICE, pptr->client, "%C :UPING: no response "
+                     "from %s within %d seconds", pptr->client, pptr->name,
+                     UPINGTIMEOUT);
+    } else
+      sendcmdto_one(&me, CMD_NOTICE, pptr->client, "%C :UPING: Could not "
+                   "start ping to %s", pptr->client, pptr->name);
+  }
+
+  close(pptr->fd);
+  pptr->fd = -1;
+  uping_erase(pptr);
+  if (pptr->client)
+    ClearUPing(pptr->client);
+  if (pptr->freeable & UPING_PENDING_SOCKET)
+    socket_del(&pptr->socket);
+  if (pptr->freeable & UPING_PENDING_SENDER)
+    timer_del(&pptr->sender);
+  if (pptr->freeable & UPING_PENDING_KILLER)
+    timer_del(&pptr->killer);
+}
+
+/** Change notifications for any upings by \a sptr.
+ * @param[in] sptr Client to stop notifying.
+ * @param[in] acptr New client to notify (or NULL).
+ */
+void uping_cancel(struct Client *sptr, struct Client* acptr)
+{
+  struct UPing* ping;
+  struct UPing* ping_next;
+
+  Debug((DEBUG_DEBUG, "UPING: canceling uping for %s", cli_name(sptr)));
+  for (ping = pingList; ping; ping = ping_next) {
+    ping_next = ping->next;
+    if (sptr == ping->client) {
+      ping->client = acptr;
+      uping_end(ping);
+    }
+  }
+  ClearUPing(sptr);
+}
diff --git a/ircd/userload.c b/ircd/userload.c
new file mode 100644 (file)
index 0000000..9ad57c2
--- /dev/null
@@ -0,0 +1,270 @@
+/*
+ * Userload module by Michael L. VanLoon (mlv) <michaelv@iastate.edu>
+ * Written 2/93.  Originally grafted into irc2.7.2g 4/93.
+ *
+ * Rewritten 9/97 by Carlo Wood (Run) <carlo@runaway.xs4all.nl>
+ * because previous version used ridiculous amounts of memory
+ * (stored all loads of the passed three days ~ 8 megs).
+ *
+ * IRC - Internet Relay Chat, ircd/userload.c
+ * Copyright (C) 1990 University of Oulu, Computing Center
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+/** @file
+ * @brief Userload tracking and statistics.
+ * @version $Id: userload.c 1231 2004-10-05 04:21:37Z entrope $
+ */
+#include "config.h"
+
+#include "userload.h"
+#include "client.h"
+#include "ircd.h"
+#include "msg.h"
+#include "numnicks.h"
+#include "querycmds.h"
+#include "s_misc.h"
+#include "s_stats.h"
+#include "send.h"
+#include "struct.h"
+#include "sys.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+
+struct current_load_st current_load;    /**< The current load */
+
+static struct current_load_st cspm_sum; /**< Number of connections times number
+                                           of seconds per minute. */
+static struct current_load_st csph_sum; /**< Number of connections times number
+                                           of seconds per hour. */
+static struct current_load_st cspm[60]; /**< Last 60 minutes */
+static struct current_load_st csph[72]; /**< Last 72 hours */
+
+static int m_index; /**< Next entry to use in #cspm. */
+static int h_index; /**< Next entry to use in #csph. */
+
+/** Update load average to reflect a change in the local client count.
+ */
+void update_load(void)
+{
+  static struct tm tm_now;      /* Current time. */
+  static time_t last_sec;       /* Seconds of last time that
+                                   update_load() called. */
+  static time_t last_min;
+  static time_t last;           /* Last time that update_load() was called. */
+  static struct current_load_st last_load;      /* The load last time that
+                                                   update_load() was called. */
+  static int initialized;       /* Boolean, set when initialized. */
+  int diff_time;        /* Temp. variable used to hold time intervals
+                                   in seconds, minutes or hours. */
+
+  /* Update `current_load' */
+  current_load.client_count = UserStats.local_clients;
+  current_load.conn_count = UserStats.local_clients + UserStats.local_servers;
+
+  /* Nothing needed when still in the same second */
+  if (!(diff_time = CurrentTime - last))
+  {
+    last_load = current_load;   /* Update last_load to be the load last
+                                   time that update_load() was called. */
+    return;
+  }
+
+  /* If we get here we entered a new second */
+
+  /*
+   * Make sure we keep the accurate time in 'tm_now'
+   */
+  if ((tm_now.tm_sec += diff_time) > 59)
+  {
+    /* This is done once every minute */
+    diff_time = tm_now.tm_sec / 60;
+    tm_now.tm_sec -= 60 * diff_time;
+    if ((tm_now.tm_min += diff_time) > 59)
+    {
+      /* This is done once every hour */
+      diff_time = tm_now.tm_min / 60;
+      tm_now.tm_min -= 60 * diff_time;
+      if ((tm_now.tm_hour += diff_time) > 23)
+      {
+        tm_now = *localtime(&CurrentTime);      /* Only called once a day */
+        if (!initialized)
+        {
+          initialized = 1;
+          last_sec = 60;
+          last_min = tm_now.tm_min;
+        }
+      }
+    }
+
+    /* If we get here we entered a new minute */
+
+    /* Finish the calculation of cspm of the last minute first: */
+    diff_time = 60 - last_sec;
+    cspm_sum.conn_count += last_load.conn_count * diff_time;
+    cspm_sum.client_count += last_load.client_count * diff_time;
+    cspm_sum.local_count += last_load.local_count * diff_time;
+
+    /* Add the completed minute to the Connections*Seconds/Hour sum */
+    csph_sum.conn_count += cspm_sum.conn_count - cspm[m_index].conn_count;
+    csph_sum.client_count += cspm_sum.client_count - cspm[m_index].client_count;
+    csph_sum.local_count += cspm_sum.local_count - cspm[m_index].local_count;
+
+    /* Store the completed minute in an array */
+    cspm[m_index] = cspm_sum;
+
+    /* How long did last_cspm last ? */
+    diff_time = tm_now.tm_min - last_min;
+    last_min = tm_now.tm_min;
+
+    if (diff_time < 0)
+      diff_time += 60;          /* update_load() must be called at
+                                   _least_ once an hour */
+
+    if (diff_time > 1)          /* Did more then one minute pass ? */
+    {
+      /* Calculate the constant load during those extra minutes */
+      cspm_sum.conn_count = last_load.conn_count * 60;
+      cspm_sum.client_count = last_load.client_count * 60;
+      cspm_sum.local_count = last_load.local_count * 60;
+    }
+
+    for (;;)
+    {
+      /* Increase minute index */
+      if (++m_index == 60)
+      {
+        m_index = 0;
+        /* Keep a list of the last 72 hours */
+        csph[h_index] = csph_sum;
+        if (++h_index == 72)
+          h_index = 0;
+      }
+
+      if (--diff_time <= 0)     /* '<' to prevent endless loop if update_load()
+                                   was not called once an hour :/ */
+        break;
+
+      /* Add extra minutes to the Connections*Seconds/Hour sum */
+      csph_sum.conn_count += cspm_sum.conn_count - cspm[m_index].conn_count;
+      csph_sum.client_count +=
+          cspm_sum.client_count - cspm[m_index].client_count;
+      csph_sum.local_count += cspm_sum.local_count - cspm[m_index].local_count;
+
+      /* Store extra minutes in the array */
+      cspm[m_index] = cspm_sum;
+    }
+
+    /* Now start the calculation of the new minute: */
+    last_sec = tm_now.tm_sec;
+    cspm_sum.conn_count = last_load.conn_count * last_sec;
+    cspm_sum.client_count = last_load.client_count * last_sec;
+    cspm_sum.local_count = last_load.local_count * last_sec;
+  }
+  else
+  {
+    /* A new second, but the same minute as last time */
+    /* How long did last_load last ? */
+    diff_time = tm_now.tm_sec - last_sec;
+    last_sec = tm_now.tm_sec;
+    if (diff_time == 1)         /* Just one second ? */
+    {
+      cspm_sum.conn_count += last_load.conn_count;
+      cspm_sum.client_count += last_load.client_count;
+      cspm_sum.local_count += last_load.local_count;
+    }
+    else
+    {
+      /* More then one second */
+      /* At most 3 integer multiplication per second */
+      cspm_sum.conn_count += last_load.conn_count * diff_time;
+      cspm_sum.client_count += last_load.client_count * diff_time;
+      cspm_sum.local_count += last_load.local_count * diff_time;
+    }
+  }
+  last_load = current_load;     /* Update last_load to be the load last
+                                   time that update_load() was called. */
+  last = CurrentTime;
+}
+
+/** Statistics callback to display userload.
+ * @param[in] sptr Client requesting statistics.
+ * @param[in] sd Stats descriptor for request (ignored).
+ * @param[in] param Extra parameter from user (ignored).
+ */
+void
+calc_load(struct Client *sptr, const struct StatDesc *sd, char *param)
+{
+  /* *INDENT-OFF* */
+  static const char *header =
+  /*   ----.-  ----.-  ----  ----  ----   ------------ */
+      "Minute  Hour    Day   Yest. YYest. Userload for:";
+  /* *INDENT-ON* */
+  static const char *what[3] = {
+    "local clients",
+    "total clients",
+    "total connections"
+  };
+  int i, j, times[5][3];        /* [min,hour,day,Yest,YYest]
+                                   [local,client,conn] */
+  int last_m_index = m_index, last_h_index = h_index;
+
+  update_load();                /* We want stats accurate as of *now* */
+
+  if (--last_m_index < 0)
+    last_m_index = 59;
+  times[0][0] = (cspm[last_m_index].local_count + 3) / 6;
+  times[0][1] = (cspm[last_m_index].client_count + 3) / 6;
+  times[0][2] = (cspm[last_m_index].conn_count + 3) / 6;
+
+  times[1][0] = (csph_sum.local_count + 180) / 360;
+  times[1][1] = (csph_sum.client_count + 180) / 360;
+  times[1][2] = (csph_sum.conn_count + 180) / 360;
+
+  for (i = 2; i < 5; ++i)
+  {
+    times[i][0] = 43200;
+    times[i][1] = 43200;
+    times[i][2] = 43200;
+    for (j = 0; j < 24; ++j)
+    {
+      if (--last_h_index < 0)
+        last_h_index = 71;
+      times[i][0] += csph[last_h_index].local_count;
+      times[i][1] += csph[last_h_index].client_count;
+      times[i][2] += csph[last_h_index].conn_count;
+    }
+    times[i][0] /= 86400;
+    times[i][1] /= 86400;
+    times[i][2] /= 86400;
+  }
+
+  sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :%s", sptr, header);
+  for (i = 0; i < 3; ++i)
+    sendcmdto_one(&me, CMD_NOTICE, sptr,
+                 "%C :%4d.%1d  %4d.%1d  %4d  %4d  %4d   %s", sptr,
+                 times[0][i] / 10, times[0][i] % 10,
+                 times[1][i] / 10, times[1][i] % 10,
+                 times[2][i], times[3][i], times[4][i], what[i]);
+}
+
+/** Initialize the userload statistics. */
+void initload(void)
+{
+  memset(&current_load, 0, sizeof(current_load));
+  update_load();                /* Initialize the load list */
+}
diff --git a/ircd/version.c b/ircd/version.c
new file mode 100644 (file)
index 0000000..7f74b2b
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * IRC - Internet Relay Chat, ircd/version.c
+ * Copyright (C) 1990 Chelsea Ashley Dyerman
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/*
+ * This file is generated by version.c.SH. Any changes made will go away.
+ */
+
+#include "version.h"
+#include "patchlevel.h"
+
+const char *generation = "313";
+const char *creation = "Mon Jun 27 2011 at 23:27:26 CEST";
+const char *version = BASE_VERSION RELEASE PATCHLEVEL PATCHSET;
+const char *svn_srev = "0";
+
+const char *infotext[] = {
+    "IRC --",
+    "This program is free software; see LICENSE in the distribution",
+    "",
+    "Based on the original code written by Jarkko Oikarinen, version 2.6:",
+    "Wiz          Jarkko Oikarinen         <jto@tolsun.oulu.fi>",
+    "",
+    "The main developer of version u2.9 and u2.10 was:",
+    "Run          Carlo Wood               <carlo@runaway.xs4all.nl>",
+    "",
+    "The head developer of the u2.10 source tree was:",
+    "Bleep        Thomas Helvey            <tomh@inxpress.net>",
+    "",
+    "The current maintainors of the u2.10 source tree are:",
+    "Isomer       Perry Lorier             <perry@coders.net>",
+    "Kev          Kevin Mitchell           <klmitch@mit.edu>",
+    "",
+    "Contributors to this release:",
+    "Kev, Isomer, Gte, Ghostwolf, Bleep",
+    "Debugging and support:",
+    "SeKs, Maniac-, HeKTik, OmniDynmc, Liandrin, Dianora",
+    "Special thanks to Angel and Buff for believing in us and putting"
+    "up with frantic late night phone calls"
+    "",
+    "Thanks goes to all other people who contributed to any version.",
+    "A full listing of all coders can be found in doc/Authors in the",
+    "source.",
+    0,
+};
diff --git a/ircd/version.c.SH b/ircd/version.c.SH
new file mode 100644 (file)
index 0000000..3243327
--- /dev/null
@@ -0,0 +1,94 @@
+#! /bin/sh
+
+# $Id: version.c.SH 1852 2007-11-30 23:50:04Z klmitch $
+
+echo "Extracting ircd/version.c ..."
+
+srcdir=$1
+
+if test -r version.c
+then
+   generation=`sed -n 's/^const char \*generation = \"\(.*\)\";/\1/p' < version.c`
+   if test ! "$generation" ; then generation=0; fi
+else
+   generation=0
+fi
+
+generation=`expr $generation + 1`
+
+creation=`date | \
+awk '{if (NF == 6) \
+        { print $1 " " $2 " " $3 " " $6 " at " $4 " " $5 } \
+else \
+        { print $1 " " $2 " " $3 " " $7 " at " $4 " " $5 " " $6 }}'`
+
+
+svn_revision=`svn info | grep Revision | grep -o -E '[0-9]+'`
+if test "x$svn_revision" = "x" ; then
+  svn_revision="0"
+fi
+
+
+/bin/cat >version.c <<!SUB!THIS!
+/*
+ * IRC - Internet Relay Chat, ircd/version.c
+ * Copyright (C) 1990 Chelsea Ashley Dyerman
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/*
+ * This file is generated by version.c.SH. Any changes made will go away.
+ */
+
+#include "version.h"
+#include "patchlevel.h"
+
+const char *generation = "$generation";
+const char *creation = "$creation";
+const char *version = BASE_VERSION RELEASE PATCHLEVEL PATCHSET;
+const char *svn_srev = "$svn_revision";
+
+const char *infotext[] = {
+    "IRC --",
+    "This program is free software; see LICENSE in the distribution",
+    "",
+    "Based on the original code written by Jarkko Oikarinen, version 2.6:",
+    "Wiz          Jarkko Oikarinen         <jto@tolsun.oulu.fi>",
+    "",
+    "The main developer of version u2.9 and u2.10 was:",
+    "Run          Carlo Wood               <carlo@runaway.xs4all.nl>",
+    "",
+    "The head developer of the u2.10 source tree was:",
+    "Bleep        Thomas Helvey            <tomh@inxpress.net>",
+    "",
+    "The current maintainors of the u2.10 source tree are:",
+    "Isomer       Perry Lorier             <perry@coders.net>",
+    "Kev          Kevin Mitchell           <klmitch@mit.edu>",
+    "",
+    "Contributors to this release:",
+    "Kev, Isomer, Gte, Ghostwolf, Bleep",
+    "Debugging and support:",
+    "SeKs, Maniac-, HeKTik, OmniDynmc, Liandrin, Dianora",
+    "Special thanks to Angel and Buff for believing in us and putting"
+    "up with frantic late night phone calls"
+    "",
+    "Thanks goes to all other people who contributed to any version.",
+    "A full listing of all coders can be found in doc/Authors in the",
+    "source.",
+    0,
+};
+!SUB!THIS!
+
diff --git a/ircd/whocmds.c b/ircd/whocmds.c
new file mode 100644 (file)
index 0000000..584cebb
--- /dev/null
@@ -0,0 +1,278 @@
+/*
+ * IRC - Internet Relay Chat, ircd/s_user.c (formerly ircd/s_msg.c)
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ *                    University of Oulu, Computing Center
+ *
+ * See file AUTHORS in IRC package for additional names of
+ * the programmers.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+/** @file
+ * @brief Support functions for /WHO-like commands.
+ * @version $Id: whocmds.c 1838 2007-10-30 01:53:33Z entrope $
+ */
+#include "config.h"
+
+#include "whocmds.h"
+#include "channel.h"
+#include "client.h"
+#include "hash.h"
+#include "ircd.h"
+#include "ircd_chattr.h"
+#include "ircd_features.h"
+#include "ircd_reply.h"
+#include "ircd_snprintf.h"
+#include "ircd_string.h"
+#include "list.h"
+#include "match.h"
+#include "numeric.h"
+#include "numnicks.h"
+#include "querycmds.h"
+#include "random.h"
+#include "s_bsd.h"
+#include "s_conf.h"
+#include "s_misc.h"
+#include "s_user.h"
+#include "send.h"
+#include "struct.h"
+#include "sys.h"
+#include "userload.h"
+#include "version.h"
+#include "whowas.h"
+#include "msg.h"
+
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+/** Send a WHO reply to a client who asked.
+ * @param[in] sptr Client who is searching for other users.
+ * @param[in] acptr Client who may be shown to \a sptr.
+ * @param[in] repchan Shared channel that provides visibility.
+ * @param[in] fields Bitmask of WHO_FIELD_* values, indicating what to show.
+ * @param[in] qrt Query type string (ignored unless \a fields & WHO_FIELD_QTY).
+ */
+void do_who(struct Client* sptr, struct Client* acptr, struct Channel* repchan,
+            int fields, char* qrt)
+{
+  char *p1;
+  struct Membership *chan = 0;
+
+  static char buf1[512];
+  /* NOTE: with current fields list and sizes this _cannot_ overrun, 
+     and also the message finally sent shouldn't ever be truncated */
+
+  p1 = buf1;
+  buf1[1] = '\0';
+
+  /* If we don't have a channel and we need one... try to find it,
+     unless the listing is for a channel service, we already know
+     that there are no common channels, thus use PubChannel and not
+     SeeChannel */
+  if (repchan)
+  {
+    chan = find_channel_member(acptr, repchan);
+  }
+  else if ((!fields || (fields & (WHO_FIELD_CHA | WHO_FIELD_FLA)))
+           && !IsChannelService(acptr) && (!IsNoChan(acptr) || IsOper(sptr) || sptr == acptr))
+  {
+    for (chan = cli_user(acptr)->channel; chan; chan = chan->next_channel)
+      if (PubChannel(chan->channel) &&
+          (acptr == sptr || !IsZombie(chan)))
+        break;
+  }
+
+  /* Place the fields one by one in the buffer and send it
+     note that fields == NULL means "default query" */
+
+  if (fields & WHO_FIELD_QTY)   /* Query type */
+  {
+    *(p1++) = ' ';
+    if (BadPtr(qrt))
+      *(p1++) = '0';
+    else
+      while ((*qrt) && (*(p1++) = *(qrt++)));
+  }
+
+  if (!fields || (fields & WHO_FIELD_CHA))
+  {
+    char *p2;
+    *(p1++) = ' ';
+    if ((p2 = (chan ? chan->channel->chname : NULL)))
+      while ((*p2) && (*(p1++) = *(p2++)));
+    else
+      *(p1++) = '*';
+  }
+
+  if (!fields || (fields & WHO_FIELD_UID))
+  {
+    char *p2 = cli_user(acptr)->username;
+    *(p1++) = ' ';
+    while ((*p2) && (*(p1++) = *(p2++)));
+  }
+
+  if (fields & WHO_FIELD_NIP)
+  {
+    const char* p2 = HasHiddenHost(acptr) && !IsAnOper(sptr) ?
+      feature_str(FEAT_HIDDEN_IP) :
+      ircd_ntoa(&cli_ip(acptr));
+    *(p1++) = ' ';
+    while ((*p2) && (*(p1++) = *(p2++)));
+  }
+
+  if (!fields || (fields & WHO_FIELD_HOS))
+  {
+    char *p2 = cli_user(acptr)->host;
+    *(p1++) = ' ';
+    while ((*p2) && (*(p1++) = *(p2++)));
+  }
+
+  if (!fields || (fields & WHO_FIELD_SER))
+  {
+    const char *p2 = (feature_bool(FEAT_HIS_WHO_SERVERNAME) && !IsAnOper(sptr)) ?
+                       feature_str(FEAT_HIS_SERVERNAME) :
+                       cli_name(cli_user(acptr)->server);
+    *(p1++) = ' ';
+    while ((*p2) && (*(p1++) = *(p2++)));
+  }
+
+  if (!fields || (fields & WHO_FIELD_NIC))
+  {
+    char *p2 = cli_name(acptr);
+    *(p1++) = ' ';
+    while ((*p2) && (*(p1++) = *(p2++)));
+  }
+
+  if (!fields || (fields & WHO_FIELD_FLA))
+  {
+    *(p1++) = ' ';
+    if (cli_user(acptr)->away)
+      *(p1++) = 'G';
+    else
+      *(p1++) = 'H';
+    if SeeOper(sptr,acptr)
+      *(p1++) = '*';
+    if (!chan) {
+      /* No flags possible for the channel, so skip them all. */
+    }
+    else if (fields) {
+      /* If you specified flags then we assume you know how to parse
+       * multiple channel status flags, as this is currently the only
+       * way to know if someone has @'s *and* is +'d.
+       */
+      if (IsChanOp(chan))
+        *(p1++) = '@';
+      if (HasVoice(chan))
+        *(p1++) = '+';
+      if (IsZombie(chan))
+        *(p1++) = '!';
+      if (IsDelayedJoin(chan))
+        *(p1++) = '<';
+    }
+    else {
+      if (IsChanOp(chan))
+        *(p1++) = '@';
+      else if (HasVoice(chan))
+        *(p1++) = '+';
+      else if (IsZombie(chan))
+        *(p1++) = '!';
+      else if (IsDelayedJoin(chan))
+        *(p1++) = '<';
+    }
+    if (IsDeaf(acptr))
+      *(p1++) = 'd';
+    if (IsAnOper(sptr))
+    {
+      if (IsInvisible(acptr))
+        *(p1++) = 'i';
+      if (SendWallops(acptr))
+        *(p1++) = 'w';
+      if (SendDebug(acptr))
+        *(p1++) = 'g';
+    }
+    if (HasHiddenHost(acptr))
+      *(p1++) = 'x';
+  }
+
+  if (!fields || (fields & WHO_FIELD_DIS))
+  {
+    *p1++ = ' ';
+    if (!fields)
+      *p1++ = ':';              /* Place colon here for default reply */
+    if (feature_bool(FEAT_HIS_WHO_HOPCOUNT) && !IsAnOper(sptr))
+      *p1++ = (sptr == acptr) ? '0' : '3';
+    else
+      /* three digit hopcount maximum */
+      p1 += ircd_snprintf(0, p1, 3, "%d", cli_hopcount(acptr));
+  }
+
+  if (fields & WHO_FIELD_IDL)
+  {
+    *p1++ = ' ';
+    if (MyUser(acptr) &&
+       (IsAnOper(sptr) || !feature_bool(FEAT_HIS_WHO_SERVERNAME) ||
+        acptr == sptr))
+      p1 += ircd_snprintf(0, p1, 11, "%d",
+                          CurrentTime - cli_user(acptr)->last);
+    else
+      *p1++ = '0';
+  }
+
+  if (fields & WHO_FIELD_ACC)
+  {
+    char *p2 = cli_user(acptr)->account;
+    *(p1++) = ' ';
+    if (*p2)
+      while ((*p2) && (*(p1++) = *(p2++)));
+    else
+      *(p1++) = '0';
+  }
+
+  if (fields & WHO_FIELD_OPL)
+  {
+      if (!chan || !IsChanOp(chan))
+      {
+        strcpy(p1, " n/a");
+        p1 += 4;
+      }
+      else
+      {
+        int vis_level = MAXOPLEVEL;
+        if ((IsGlobalChannel(chan->channel->chname) ? IsOper(sptr) : IsAnOper(sptr))
+            || is_chan_op(sptr, chan->channel))
+          vis_level = OpLevel(chan);
+        p1 += ircd_snprintf(0, p1, 5, " %d", vis_level);
+      }
+  }
+
+  if (!fields || (fields & WHO_FIELD_REN))
+  {
+    char *p2 = cli_info(acptr);
+    *p1++ = ' ';
+    if (fields)
+      *p1++ = ':';              /* Place colon here for special reply */
+    while ((*p2) && (*(p1++) = *(p2++)));
+  }
+
+  /* The first char will always be an useless blank and we 
+     need to terminate buf1 */
+  *p1 = '\0';
+  p1 = buf1;
+  send_reply(sptr, fields ? RPL_WHOSPCRPL : RPL_WHOREPLY, ++p1);
+}
diff --git a/ircd/whowas.c b/ircd/whowas.c
new file mode 100644 (file)
index 0000000..ec91b67
--- /dev/null
@@ -0,0 +1,401 @@
+/*
+ * IRC - Internet Relay Chat, ircd/whowas.c
+ * Copyright (C) 1990 Markku Savela
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * --- avalon --- 6th April 1992
+ * rewritten to scrap linked lists and use a table of structures which
+ * is referenced like a circular loop. Should be faster and more efficient.
+ *
+ * --- comstud --- 25th March 1997
+ * Everything rewritten from scratch.  Avalon's code was bad.  My version
+ * is faster and more efficient.  No more hangs on /squits and you can
+ * safely raise NICKNAMEHISTORYLENGTH to a higher value without hurting
+ * performance.
+ *
+ * --- comstud --- 5th August 1997
+ * Fixed for Undernet..
+ *
+ * --- Run --- 27th August 1997
+ * Speeded up the code, added comments.
+ */
+#include "config.h"
+
+#include "whowas.h"
+#include "client.h"
+#include "ircd.h"
+#include "ircd_alloc.h"
+#include "ircd_chattr.h"
+#include "ircd_features.h"
+#include "ircd_log.h"
+#include "ircd_string.h"
+#include "list.h"
+#include "numeric.h"
+#include "s_debug.h"
+#include "s_misc.h"
+#include "s_user.h"
+#include "send.h"
+#include "struct.h"
+#include "sys.h"
+#include "msg.h"
+
+/* #include <assert.h> -- Now using assert in ircd_log.h */
+#include <stdlib.h>
+#include <string.h>
+
+
+/** Keeps track of whowas least-recently-used list. */
+static struct {
+  struct Whowas *ww_list;      /**< list of whowas structures */
+  struct Whowas *ww_tail;      /**< tail of list for getting structures */
+  unsigned int  ww_alloc;      /**< alloc count */
+} wwList = { 0, 0, 0 };
+
+/** Hash table of Whowas entries by nickname. */
+struct Whowas* whowashash[WW_MAX];
+
+/** @file
+ * @brief Manipulation functions for the whowas list.
+ * @version $Id: whowas.c 1633 2006-03-25 03:46:56Z entrope $
+ *
+ * Since the introduction of numeric nicks (at least for upstream messages,
+ * like MODE +o &lt;nick>, KICK #chan &lt;nick>, KILL &lt;nick> etc), there is no
+ * real important reason for a nick history anymore.
+ * Nevertheless, there are two reason why we might want to keep it:
+ * @li The /WHOWAS command, which is often useful to catch harassing
+ *    users or abusers in general.
+ * @li Clients still use the normal nicks in the client-server protocol,
+ *    and it might be considered a nice feature that here we still have
+ *    nick chasing.
+ *
+ * Note however that BOTH reasons make it redundant to keep a whowas history
+ * for users that split off.
+ *
+ * The rewrite of comstud was many to safe cpu during net.breaks and therefore
+ * a bit redundant imho (Run).
+ *
+ * But - it was written anyway.  So lets look at the structure of the
+ * whowas history now:
+ *
+ * We still have a static table of 'struct Whowas' structures in which we add
+ * new nicks (plus info) as in a rotating buffer.  We keep a global pointer
+ * `whowas_next' that points to the next entry to be overwritten - or to
+ * the oldest entry in the table (which is the same).
+ *
+ * Each entry keeps pointers for two doubly linked lists (thus four pointers):
+ * A list of the entries that have the same hash value ('hashv list'), and
+ * a list of the entries that have the same online pointer (`online list').
+ * Note that the last list (pointers) is only updated as long as online points
+ * to the corresponding client: As soon as the client signs off, this list
+ * is not anymore maintained (and hopefully not used anymore either ;).
+ *
+ * So now we have two ways of accessing this database:
+ * @li Given a &lt;nick> we can calculate a hashv and then whowashash[hashv] will
+ *    point to the start of the 'hash list': all entries with the same hashv.
+ *    We'll have to search this list to find the entry with the correct &lt;nick>.
+ *    Once we found the correct whowas entry, we have a pointer to the
+ *    corresponding client - if still online - for nick chasing purposes.
+ *    Note that the same nick can occur multiple times in the whowas history,
+ *    each of these having the same hash value of course.  While a /WHOWAS on
+ *    just a nick will return all entries, nick chasing will only find the
+ *    first in the list.  Because new entries are added at the start of the
+ *    'hash list' we will always find the youngest entry, which is what we want.
+ * @li Given an online client we have a pointer to the first whowas entry
+ *    of the linked list of whowas entries that all belong to this client.
+ *    We ONLY need this to reset all `online' pointers when this client
+ *    signs off.
+ *
+ * 27/8/97:
+ *
+ * Note that following:
+ *
+ * @li We *only* (need to) change the 'hash list' and the 'online' list
+ *    in add_history().
+ * @li There we always ADD an entry to the BEGINNING of the 'hash list'
+ *    and the 'online list': *new* entries are at the start of the lists.
+ *    The oldest entries are at the end of the lists.
+ * @li We always REMOVE the oldest entry we have (whowas_next), this means
+ *    that this is always an entry that is at the *end* of the 'hash list'
+ *    and 'online list' that it is a part of: the next pointer will
+ *    always be NULL.
+ * @li The previous pointer is *only* used to update the next pointer of the
+ *    previous entry, therefore we could better use a pointer to this
+ *    next pointer: That is faster - saves us a 'if' test (it will never be
+ *    NULL because the last added entry will point to the pointer that
+ *    points to the start of the list) and we won't need special code to
+ *    update the list start pointers.
+ *
+ * I incorporated these considerations into the code below.
+ *
+ * --Run
+ */
+
+/** Unlink a Whowas structure and free everything inside it.
+ * @param[in,out] ww The whowas record to free.
+ * @return The pointer \a ww.
+ */
+static struct Whowas *
+whowas_clean(struct Whowas *ww)
+{
+  if (!ww)
+    return 0;
+
+  Debug((DEBUG_LIST, "Cleaning whowas structure for %s", ww->name));
+
+  if (ww->online) { /* unlink from client */
+    if (ww->cnext) /* shouldn't happen, but I'm not confident of that */
+      ww->cnext->cprevnextp = ww->cprevnextp;
+    *ww->cprevnextp = ww->cnext;
+  }
+
+  if (ww->hnext) /* now unlink from hash table */
+    ww->hnext->hprevnextp = ww->hprevnextp;
+  *ww->hprevnextp = ww->hnext;
+
+  if (ww->wnext) /* unlink from whowas linked list... */
+    ww->wnext->wprev = ww->wprev;
+  if (ww->wprev)
+    ww->wprev->wnext = ww->wnext;
+
+  if (wwList.ww_tail == ww) /* update tail pointer appropriately */
+    wwList.ww_tail = ww->wprev;
+
+  /* Free old info */
+  if (ww->name)
+    MyFree(ww->name);
+  if (ww->username)
+    MyFree(ww->username);
+  if (ww->hostname)
+    MyFree(ww->hostname);
+  if (ww->realhost)
+    MyFree(ww->realhost);
+  if (ww->servername)
+    MyFree(ww->servername);
+  if (ww->realname)
+    MyFree(ww->realname);
+  if (ww->away)
+    MyFree(ww->away);
+
+  return ww;
+}
+
+/** Clean and free a whowas record.
+ * @param[in] ww Whowas record to free.
+ */
+static void
+whowas_free(struct Whowas *ww)
+{
+  if (!ww)
+    return;
+
+  Debug((DEBUG_LIST, "Destroying whowas structure for %s", ww->name));
+
+  whowas_clean(ww);
+  MyFree(ww);
+
+  wwList.ww_alloc--;
+}
+
+/** Return a fresh Whowas record.
+ * If the total number of records is smaller than determined by
+ * FEAT_NICKNAMEHISTORYLENGTH, allocate a new one.  Otherwise,
+ * reuse the oldest record in use.
+ * @return A pointer to a clean Whowas.
+ */
+static struct Whowas *
+whowas_alloc(void)
+{
+  struct Whowas *ww;
+
+  if (wwList.ww_alloc >= feature_int(FEAT_NICKNAMEHISTORYLENGTH)) {
+    /* reclaim the oldest whowas entry */
+    ww = whowas_clean(wwList.ww_tail);
+  } else {
+    /* allocate a new one */
+    wwList.ww_alloc++;
+    ww = (struct Whowas *) MyMalloc(sizeof(struct Whowas));
+  }
+
+  assert(ww != NULL);
+  memset(ww, 0, sizeof(*ww));
+  return ww;
+}
+
+/** If necessary, trim the whowas list.
+ * This function trims the whowas list until it contains no more than
+ * FEAT_NICKNAMEHISTORYLENGTH records.
+ */
+void
+whowas_realloc(void)
+{
+  Debug((DEBUG_LIST, "whowas_realloc() called with alloc count %d, "
+        "history length %d, tail pointer %p", wwList.ww_alloc,
+        feature_int(FEAT_NICKNAMEHISTORYLENGTH), wwList.ww_tail));
+
+  while (wwList.ww_alloc > feature_int(FEAT_NICKNAMEHISTORYLENGTH)) {
+    if (!wwList.ww_tail) { /* list is empty... */
+      Debug((DEBUG_LIST, "whowas list emptied with alloc count %d",
+            wwList.ww_alloc));
+      return;
+    }
+
+    whowas_free(wwList.ww_tail); /* free oldest element of whowas list */
+  }
+}
+
+/** Add a client to the whowas list.
+ * @param[in] cptr Client to add.
+ * @param[in] still_on If non-zero, link the record to the client's personal history.
+ */
+void add_history(struct Client *cptr, int still_on)
+{
+  struct Whowas *ww;
+
+  if (!(ww = whowas_alloc()))
+    return; /* couldn't get a structure */
+
+  ww->hashv = hash_whowas_name(cli_name(cptr)); /* initialize struct */
+  ww->logoff = CurrentTime;
+  DupString(ww->name, cli_name(cptr));
+  DupString(ww->username, cli_user(cptr)->username);
+  DupString(ww->hostname, cli_user(cptr)->host);
+  if (HasHiddenHost(cptr))
+    DupString(ww->realhost, cli_user(cptr)->realhost);
+  DupString(ww->servername, cli_name(cli_user(cptr)->server));
+  DupString(ww->realname, cli_info(cptr));
+  if (cli_user(cptr)->away)
+    DupString(ww->away, cli_user(cptr)->away);
+
+  if (still_on) { /* user changed nicknames... */
+    ww->online = cptr;
+    if ((ww->cnext = cli_whowas(cptr)))
+      ww->cnext->cprevnextp = &ww->cnext;
+    ww->cprevnextp = &(cli_whowas(cptr));
+    cli_whowas(cptr) = ww;
+  } else /* user quit */
+    ww->online = 0;
+
+  /* link new whowas structure to list */
+  ww->wnext = wwList.ww_list;
+  if (wwList.ww_list)
+    wwList.ww_list->wprev = ww;
+  wwList.ww_list = ww;
+
+  if (!wwList.ww_tail) /* update the tail pointer... */
+    wwList.ww_tail = ww;
+
+  /* Now link it into the hash table */
+  if ((ww->hnext = whowashash[ww->hashv]))
+    ww->hnext->hprevnextp = &ww->hnext;
+  ww->hprevnextp = &whowashash[ww->hashv];
+  whowashash[ww->hashv] = ww;
+}
+
+/** Clear all Whowas::online pointers that point to a client.
+ * @param[in] cptr Client who is going offline.
+ */
+void off_history(const struct Client *cptr)
+{
+  struct Whowas *temp;
+
+  for (temp = cli_whowas(cptr); temp; temp = temp->cnext)
+    temp->online = NULL;
+}
+
+/** Find a client who has recently used a particular nickname.
+ * @param[in] nick Nickname to find.
+ * @param[in] timelimit Maximum age for entry.
+ * @return User's online client, or NULL if none is found.
+ */
+struct Client *get_history(const char *nick, time_t timelimit)
+{
+  struct Whowas *temp = whowashash[hash_whowas_name(nick)];
+  timelimit = CurrentTime - timelimit;
+
+  for (; temp; temp = temp->hnext)
+    if (0 == ircd_strcmp(nick, temp->name) && temp->logoff > timelimit)
+      return temp->online;
+
+  return NULL;
+}
+
+/** Count memory used by whowas list.
+ * @param[out] wwu Number of entries in whowas list.
+ * @param[out] wwum Total number of bytes used by nickname, username,
+ * hostname and servername fields.
+ * @param[out] wwa Number of away strings in whowas list.
+ * @param[out] wwam Total number of bytes used by away strings.
+ */
+void count_whowas_memory(int *wwu, size_t *wwum, int *wwa, size_t *wwam)
+{
+  struct Whowas *tmp;
+  int u = 0;
+  int a = 0;
+  size_t um = 0;
+  size_t am = 0;
+  assert(0 != wwu);
+  assert(0 != wwum);
+  assert(0 != wwa);
+  assert(0 != wwam);
+
+  for (tmp = wwList.ww_list; tmp; tmp = tmp->wnext) {
+    u++;
+    um += (strlen(tmp->name) + 1);
+    um += (strlen(tmp->username) + 1);
+    um += (strlen(tmp->hostname) + 1);
+    um += (strlen(tmp->servername) + 1);
+    if (tmp->away) {
+      a++;
+      am += (strlen(tmp->away) + 1);
+    }
+  }
+  *wwu = u;
+  *wwum = um;
+  *wwa = a;
+  *wwam = am;
+}
+
+/** Initialize whowas table. */
+void initwhowas(void)
+{
+  int i;
+
+  for (i = 0; i < WW_MAX; i++)
+    whowashash[i] = 0;
+}
+
+/** Calculate a hash value for a string.
+ * @param[in] name Nickname to calculate hash over.
+ * @return Calculated hash value.
+ */
+unsigned int hash_whowas_name(const char *name)
+{
+  unsigned int hash = 0;
+  unsigned int hash2 = 0;
+  unsigned char lower;
+
+  do
+  {
+    lower = ToLower(*name);
+    hash = (hash << 1) + lower;
+    hash2 = (hash2 >> 1) + lower;
+  }
+  while (*++name);
+
+  return ((hash & WW_MAX_INITIAL_MASK) << BITS_PER_COL) +
+      (hash2 & BITS_PER_COL_MASK);
+}
+
diff --git a/ircd/y.tab.c b/ircd/y.tab.c
new file mode 100644 (file)
index 0000000..e0509c4
--- /dev/null
@@ -0,0 +1,4106 @@
+/* A Bison parser, made by GNU Bison 2.3.  */
+
+/* Skeleton implementation for Bison's Yacc-like parsers in C
+
+   Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006
+   Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin Street, Fifth Floor,
+   Boston, MA 02110-1301, USA.  */
+
+/* As a special exception, you may create a larger work that contains
+   part or all of the Bison parser skeleton and distribute that work
+   under terms of your choice, so long as that work isn't itself a
+   parser generator using the skeleton or a modified version thereof
+   as a parser skeleton.  Alternatively, if you modify or redistribute
+   the parser skeleton itself, you may (at your option) remove this
+   special exception, which will cause the skeleton and the resulting
+   Bison output files to be licensed under the GNU General Public
+   License without this special exception.
+
+   This special exception was added by the Free Software Foundation in
+   version 2.2 of Bison.  */
+
+/* C LALR(1) parser skeleton written by Richard Stallman, by
+   simplifying the original so-called "semantic" parser.  */
+
+/* All symbols defined below should begin with yy or YY, to avoid
+   infringing on user name space.  This should be done even for local
+   variables, as they might otherwise be expanded by user macros.
+   There are some unavoidable exceptions within include files to
+   define necessary library symbols; they are noted "INFRINGES ON
+   USER NAME SPACE" below.  */
+
+/* Identify Bison output.  */
+#define YYBISON 1
+
+/* Bison version.  */
+#define YYBISON_VERSION "2.3"
+
+/* Skeleton name.  */
+#define YYSKELETON_NAME "yacc.c"
+
+/* Pure parsers.  */
+#define YYPURE 0
+
+/* Using locations.  */
+#define YYLSP_NEEDED 0
+
+
+
+/* Tokens.  */
+#ifndef YYTOKENTYPE
+# define YYTOKENTYPE
+   /* Put the tokens into the symbol table, so that GDB and other debuggers
+      know about them.  */
+   enum yytokentype {
+     QSTRING = 258,
+     NUMBER = 259,
+     GENERAL = 260,
+     ADMIN = 261,
+     LOCATION = 262,
+     CONTACT = 263,
+     CONNECT = 264,
+     CLASS = 265,
+     CHANNEL = 266,
+     PINGFREQ = 267,
+     CONNECTFREQ = 268,
+     MAXLINKS = 269,
+     MAXHOPS = 270,
+     SENDQ = 271,
+     NAME = 272,
+     HOST = 273,
+     IP = 274,
+     USERNAME = 275,
+     PASS = 276,
+     LOCAL = 277,
+     SECONDS = 278,
+     MINUTES = 279,
+     HOURS = 280,
+     DAYS = 281,
+     WEEKS = 282,
+     MONTHS = 283,
+     YEARS = 284,
+     DECADES = 285,
+     BYTES = 286,
+     KBYTES = 287,
+     MBYTES = 288,
+     GBYTES = 289,
+     TBYTES = 290,
+     SERVER = 291,
+     PORT = 292,
+     MASK = 293,
+     HUB = 294,
+     LEAF = 295,
+     UWORLD = 296,
+     YES = 297,
+     NO = 298,
+     OPER = 299,
+     VHOST = 300,
+     HIDDEN = 301,
+     MOTD = 302,
+     JUPE = 303,
+     NICK = 304,
+     NUMERIC = 305,
+     DESCRIPTION = 306,
+     CLIENT = 307,
+     KILL = 308,
+     CRULE = 309,
+     REAL = 310,
+     REASON = 311,
+     TFILE = 312,
+     RULE = 313,
+     ALL = 314,
+     FEATURES = 315,
+     QUARANTINE = 316,
+     PSEUDO = 317,
+     PREPEND = 318,
+     USERMODE = 319,
+     IAUTH = 320,
+     TIMEOUT = 321,
+     FAST = 322,
+     AUTOCONNECT = 323,
+     PROGRAM = 324,
+     TOK_IPV4 = 325,
+     TOK_IPV6 = 326,
+     DNS = 327,
+     FORWARDS = 328,
+     SECURE = 329,
+     WEBIRC = 330,
+     SPOOF = 331,
+     MAXCHANS = 332,
+     REQUIRED = 333,
+     SSL = 334,
+     CERT = 335,
+     CACERT = 336,
+     TPRIV_CHAN_LIMIT = 337,
+     TPRIV_MODE_LCHAN = 338,
+     TPRIV_DEOP_LCHAN = 339,
+     TPRIV_WALK_LCHAN = 340,
+     TPRIV_LOCAL_KILL = 341,
+     TPRIV_REHASH = 342,
+     TPRIV_RESTART = 343,
+     TPRIV_DIE = 344,
+     TPRIV_GLINE = 345,
+     TPRIV_LOCAL_GLINE = 346,
+     TPRIV_LOCAL_JUPE = 347,
+     TPRIV_LOCAL_BADCHAN = 348,
+     TPRIV_LOCAL_OPMODE = 349,
+     TPRIV_OPMODE = 350,
+     TPRIV_SET = 351,
+     TPRIV_WHOX = 352,
+     TPRIV_BADCHAN = 353,
+     TPRIV_SEE_CHAN = 354,
+     TPRIV_SHOW_INVIS = 355,
+     TPRIV_SHOW_ALL_INVIS = 356,
+     TPRIV_PROPAGATE = 357,
+     TPRIV_UNLIMIT_QUERY = 358,
+     TPRIV_DISPLAY = 359,
+     TPRIV_SEE_OPERS = 360,
+     TPRIV_WIDE_GLINE = 361,
+     TPRIV_FORCE_OPMODE = 362,
+     TPRIV_FORCE_LOCAL_OPMODE = 363,
+     TPRIV_APASS_OPMODE = 364,
+     TPRIV_LIST_CHAN = 365,
+     TPRIV_SEE_IDLETIME = 366,
+     TPRIV_UMODE_NETSERV = 367,
+     TPRIV_UMODE_NOCHAN = 368,
+     TPRIV_UMODE_NOIDLE = 369,
+     TPRIV_UMODE_CHSERV = 370,
+     TPRIV_UMODE_XTRAOP = 371,
+     TPRIV_FLOOD = 372,
+     TPRIV_HALFFLOOD = 373,
+     TPRIV_UNLIMITED_TARGET = 374,
+     TPRIV_UMODE_OVERRIDECC = 375,
+     TPRIV_HIDE_IDLETIME = 376,
+     TPRIV_NOAMSG_OVERRIDE = 377
+   };
+#endif
+/* Tokens.  */
+#define QSTRING 258
+#define NUMBER 259
+#define GENERAL 260
+#define ADMIN 261
+#define LOCATION 262
+#define CONTACT 263
+#define CONNECT 264
+#define CLASS 265
+#define CHANNEL 266
+#define PINGFREQ 267
+#define CONNECTFREQ 268
+#define MAXLINKS 269
+#define MAXHOPS 270
+#define SENDQ 271
+#define NAME 272
+#define HOST 273
+#define IP 274
+#define USERNAME 275
+#define PASS 276
+#define LOCAL 277
+#define SECONDS 278
+#define MINUTES 279
+#define HOURS 280
+#define DAYS 281
+#define WEEKS 282
+#define MONTHS 283
+#define YEARS 284
+#define DECADES 285
+#define BYTES 286
+#define KBYTES 287
+#define MBYTES 288
+#define GBYTES 289
+#define TBYTES 290
+#define SERVER 291
+#define PORT 292
+#define MASK 293
+#define HUB 294
+#define LEAF 295
+#define UWORLD 296
+#define YES 297
+#define NO 298
+#define OPER 299
+#define VHOST 300
+#define HIDDEN 301
+#define MOTD 302
+#define JUPE 303
+#define NICK 304
+#define NUMERIC 305
+#define DESCRIPTION 306
+#define CLIENT 307
+#define KILL 308
+#define CRULE 309
+#define REAL 310
+#define REASON 311
+#define TFILE 312
+#define RULE 313
+#define ALL 314
+#define FEATURES 315
+#define QUARANTINE 316
+#define PSEUDO 317
+#define PREPEND 318
+#define USERMODE 319
+#define IAUTH 320
+#define TIMEOUT 321
+#define FAST 322
+#define AUTOCONNECT 323
+#define PROGRAM 324
+#define TOK_IPV4 325
+#define TOK_IPV6 326
+#define DNS 327
+#define FORWARDS 328
+#define SECURE 329
+#define WEBIRC 330
+#define SPOOF 331
+#define MAXCHANS 332
+#define REQUIRED 333
+#define SSL 334
+#define CERT 335
+#define CACERT 336
+#define TPRIV_CHAN_LIMIT 337
+#define TPRIV_MODE_LCHAN 338
+#define TPRIV_DEOP_LCHAN 339
+#define TPRIV_WALK_LCHAN 340
+#define TPRIV_LOCAL_KILL 341
+#define TPRIV_REHASH 342
+#define TPRIV_RESTART 343
+#define TPRIV_DIE 344
+#define TPRIV_GLINE 345
+#define TPRIV_LOCAL_GLINE 346
+#define TPRIV_LOCAL_JUPE 347
+#define TPRIV_LOCAL_BADCHAN 348
+#define TPRIV_LOCAL_OPMODE 349
+#define TPRIV_OPMODE 350
+#define TPRIV_SET 351
+#define TPRIV_WHOX 352
+#define TPRIV_BADCHAN 353
+#define TPRIV_SEE_CHAN 354
+#define TPRIV_SHOW_INVIS 355
+#define TPRIV_SHOW_ALL_INVIS 356
+#define TPRIV_PROPAGATE 357
+#define TPRIV_UNLIMIT_QUERY 358
+#define TPRIV_DISPLAY 359
+#define TPRIV_SEE_OPERS 360
+#define TPRIV_WIDE_GLINE 361
+#define TPRIV_FORCE_OPMODE 362
+#define TPRIV_FORCE_LOCAL_OPMODE 363
+#define TPRIV_APASS_OPMODE 364
+#define TPRIV_LIST_CHAN 365
+#define TPRIV_SEE_IDLETIME 366
+#define TPRIV_UMODE_NETSERV 367
+#define TPRIV_UMODE_NOCHAN 368
+#define TPRIV_UMODE_NOIDLE 369
+#define TPRIV_UMODE_CHSERV 370
+#define TPRIV_UMODE_XTRAOP 371
+#define TPRIV_FLOOD 372
+#define TPRIV_HALFFLOOD 373
+#define TPRIV_UNLIMITED_TARGET 374
+#define TPRIV_UMODE_OVERRIDECC 375
+#define TPRIV_HIDE_IDLETIME 376
+#define TPRIV_NOAMSG_OVERRIDE 377
+
+
+
+
+/* Copy the first part of user declarations.  */
+#line 22 "./ircd_parser.y"
+
+
+#include "config.h"
+#include "s_conf.h"
+#include "class.h"
+#include "client.h"
+#include "crule.h"
+#include "ircd_features.h"
+#include "fileio.h"
+#include "gline.h"
+#include "hash.h"
+#include "ircd.h"
+#include "ircd_alloc.h"
+#include "ircd_chattr.h"
+#include "ircd_log.h"
+#include "ircd_reply.h"
+#include "ircd_snprintf.h"
+#include "ircd_string.h"
+#include "list.h"
+#include "listener.h"
+#include "match.h"
+#include "motd.h"
+#include "numeric.h"
+#include "numnicks.h"
+#include "opercmds.h"
+#include "parse.h"
+#include "res.h"
+#include "s_auth.h"
+#include "s_bsd.h"
+#include "s_conf.h"
+#include "s_debug.h"
+#include "s_misc.h"
+#include "send.h"
+#include "struct.h"
+#include "sys.h"
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <arpa/inet.h>
+
+#define MAX_STRINGS 80 /* Maximum number of feature params. */
+#define USE_IPV4 (1 << 16)
+#define USE_IPV6 (1 << 17)
+
+  extern struct LocalConf   localConf;
+  extern struct DenyConf*   denyConfList;
+  extern struct CRuleConf*  cruleConfList;
+  extern struct ServerConf* serverConfList;
+  extern struct s_map*      GlobalServiceMapList;
+  extern struct qline*      GlobalQuarantineList;
+
+  int yylex(void);
+  /* Now all the globals we need :/... */
+  int tping, tconn, maxlinks, sendq, port, invert, stringno, flags, maxchans, iauth_required = 0;
+  char *name, *pass, *host, *ip, *username, *origin, *hub_limit;
+  struct SLink *hosts;
+  char *stringlist[MAX_STRINGS];
+  struct ListenerFlags listen_flags;
+  struct ConnectionClass *c_class;
+  struct DenyConf *dconf;
+  struct ServerConf *sconf;
+  struct s_map *smap;
+  struct Privs privs;
+  struct Privs privs_dirty;
+  struct webirc_block *webirc;
+
+static void parse_error(char *pattern,...) {
+  static char error_buffer[1024];
+  va_list vl;
+  va_start(vl,pattern);
+  ircd_vsnprintf(NULL, error_buffer, sizeof(error_buffer), pattern, vl);
+  va_end(vl);
+  yyerror(error_buffer);
+}
+
+static void free_slist(struct SLink **link) {
+  struct SLink *next;
+  while (*link != NULL) {
+    next = (*link)->next;
+    MyFree((*link)->value.cp);
+    free_link(*link);
+    *link = next;
+  }
+}
+
+
+
+/* Enabling traces.  */
+#ifndef YYDEBUG
+# define YYDEBUG 0
+#endif
+
+/* Enabling verbose error messages.  */
+#ifdef YYERROR_VERBOSE
+# undef YYERROR_VERBOSE
+# define YYERROR_VERBOSE 1
+#else
+# define YYERROR_VERBOSE 0
+#endif
+
+/* Enabling the token table.  */
+#ifndef YYTOKEN_TABLE
+# define YYTOKEN_TABLE 0
+#endif
+
+#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
+typedef union YYSTYPE
+#line 207 "./ircd_parser.y"
+{
+ char *text;
+ int num;
+}
+/* Line 187 of yacc.c.  */
+#line 432 "y.tab.c"
+       YYSTYPE;
+# define yystype YYSTYPE /* obsolescent; will be withdrawn */
+# define YYSTYPE_IS_DECLARED 1
+# define YYSTYPE_IS_TRIVIAL 1
+#endif
+
+
+
+/* Copy the second part of user declarations.  */
+
+
+/* Line 216 of yacc.c.  */
+#line 445 "y.tab.c"
+
+#ifdef short
+# undef short
+#endif
+
+#ifdef YYTYPE_UINT8
+typedef YYTYPE_UINT8 yytype_uint8;
+#else
+typedef unsigned char yytype_uint8;
+#endif
+
+#ifdef YYTYPE_INT8
+typedef YYTYPE_INT8 yytype_int8;
+#elif (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+typedef signed char yytype_int8;
+#else
+typedef short int yytype_int8;
+#endif
+
+#ifdef YYTYPE_UINT16
+typedef YYTYPE_UINT16 yytype_uint16;
+#else
+typedef unsigned short int yytype_uint16;
+#endif
+
+#ifdef YYTYPE_INT16
+typedef YYTYPE_INT16 yytype_int16;
+#else
+typedef short int yytype_int16;
+#endif
+
+#ifndef YYSIZE_T
+# ifdef __SIZE_TYPE__
+#  define YYSIZE_T __SIZE_TYPE__
+# elif defined size_t
+#  define YYSIZE_T size_t
+# elif ! defined YYSIZE_T && (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+#  include <stddef.h> /* INFRINGES ON USER NAME SPACE */
+#  define YYSIZE_T size_t
+# else
+#  define YYSIZE_T unsigned int
+# endif
+#endif
+
+#define YYSIZE_MAXIMUM ((YYSIZE_T) -1)
+
+#ifndef YY_
+# if YYENABLE_NLS
+#  if ENABLE_NLS
+#   include <libintl.h> /* INFRINGES ON USER NAME SPACE */
+#   define YY_(msgid) dgettext ("bison-runtime", msgid)
+#  endif
+# endif
+# ifndef YY_
+#  define YY_(msgid) msgid
+# endif
+#endif
+
+/* Suppress unused-variable warnings by "using" E.  */
+#if ! defined lint || defined __GNUC__
+# define YYUSE(e) ((void) (e))
+#else
+# define YYUSE(e) /* empty */
+#endif
+
+/* Identity function, used to suppress warnings about constant conditions.  */
+#ifndef lint
+# define YYID(n) (n)
+#else
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+static int
+YYID (int i)
+#else
+static int
+YYID (i)
+    int i;
+#endif
+{
+  return i;
+}
+#endif
+
+#if ! defined yyoverflow || YYERROR_VERBOSE
+
+/* The parser invokes alloca or malloc; define the necessary symbols.  */
+
+# ifdef YYSTACK_USE_ALLOCA
+#  if YYSTACK_USE_ALLOCA
+#   ifdef __GNUC__
+#    define YYSTACK_ALLOC __builtin_alloca
+#   elif defined __BUILTIN_VA_ARG_INCR
+#    include <alloca.h> /* INFRINGES ON USER NAME SPACE */
+#   elif defined _AIX
+#    define YYSTACK_ALLOC __alloca
+#   elif defined _MSC_VER
+#    include <malloc.h> /* INFRINGES ON USER NAME SPACE */
+#    define alloca _alloca
+#   else
+#    define YYSTACK_ALLOC alloca
+#    if ! defined _ALLOCA_H && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+#     include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
+#     ifndef _STDLIB_H
+#      define _STDLIB_H 1
+#     endif
+#    endif
+#   endif
+#  endif
+# endif
+
+# ifdef YYSTACK_ALLOC
+   /* Pacify GCC's `empty if-body' warning.  */
+#  define YYSTACK_FREE(Ptr) do { /* empty */; } while (YYID (0))
+#  ifndef YYSTACK_ALLOC_MAXIMUM
+    /* The OS might guarantee only one guard page at the bottom of the stack,
+       and a page size can be as small as 4096 bytes.  So we cannot safely
+       invoke alloca (N) if N exceeds 4096.  Use a slightly smaller number
+       to allow for a few compiler-allocated temporary stack slots.  */
+#   define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */
+#  endif
+# else
+#  define YYSTACK_ALLOC YYMALLOC
+#  define YYSTACK_FREE YYFREE
+#  ifndef YYSTACK_ALLOC_MAXIMUM
+#   define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM
+#  endif
+#  if (defined __cplusplus && ! defined _STDLIB_H \
+       && ! ((defined YYMALLOC || defined malloc) \
+            && (defined YYFREE || defined free)))
+#   include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
+#   ifndef _STDLIB_H
+#    define _STDLIB_H 1
+#   endif
+#  endif
+#  ifndef YYMALLOC
+#   define YYMALLOC malloc
+#   if ! defined malloc && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */
+#   endif
+#  endif
+#  ifndef YYFREE
+#   define YYFREE free
+#   if ! defined free && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+void free (void *); /* INFRINGES ON USER NAME SPACE */
+#   endif
+#  endif
+# endif
+#endif /* ! defined yyoverflow || YYERROR_VERBOSE */
+
+
+#if (! defined yyoverflow \
+     && (! defined __cplusplus \
+        || (defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL)))
+
+/* A type that is properly aligned for any stack member.  */
+union yyalloc
+{
+  yytype_int16 yyss;
+  YYSTYPE yyvs;
+  };
+
+/* The size of the maximum gap between one aligned stack and the next.  */
+# define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1)
+
+/* The size of an array large to enough to hold all stacks, each with
+   N elements.  */
+# define YYSTACK_BYTES(N) \
+     ((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE)) \
+      + YYSTACK_GAP_MAXIMUM)
+
+/* Copy COUNT objects from FROM to TO.  The source and destination do
+   not overlap.  */
+# ifndef YYCOPY
+#  if defined __GNUC__ && 1 < __GNUC__
+#   define YYCOPY(To, From, Count) \
+      __builtin_memcpy (To, From, (Count) * sizeof (*(From)))
+#  else
+#   define YYCOPY(To, From, Count)             \
+      do                                       \
+       {                                       \
+         YYSIZE_T yyi;                         \
+         for (yyi = 0; yyi < (Count); yyi++)   \
+           (To)[yyi] = (From)[yyi];            \
+       }                                       \
+      while (YYID (0))
+#  endif
+# endif
+
+/* Relocate STACK from its old location to the new one.  The
+   local variables YYSIZE and YYSTACKSIZE give the old and new number of
+   elements in the stack, and YYPTR gives the new location of the
+   stack.  Advance YYPTR to a properly aligned location for the next
+   stack.  */
+# define YYSTACK_RELOCATE(Stack)                                       \
+    do                                                                 \
+      {                                                                        \
+       YYSIZE_T yynewbytes;                                            \
+       YYCOPY (&yyptr->Stack, Stack, yysize);                          \
+       Stack = &yyptr->Stack;                                          \
+       yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \
+       yyptr += yynewbytes / sizeof (*yyptr);                          \
+      }                                                                        \
+    while (YYID (0))
+
+#endif
+
+/* YYFINAL -- State number of the termination state.  */
+#define YYFINAL  62
+/* YYLAST -- Last index in YYTABLE.  */
+#define YYLAST   686
+
+/* YYNTOKENS -- Number of terminals.  */
+#define YYNTOKENS  134
+/* YYNNTS -- Number of nonterminals.  */
+#define YYNNTS  155
+/* YYNRULES -- Number of rules.  */
+#define YYNRULES  325
+/* YYNRULES -- Number of states.  */
+#define YYNSTATES  637
+
+/* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX.  */
+#define YYUNDEFTOK  2
+#define YYMAXUTOK   377
+
+#define YYTRANSLATE(YYX)                                               \
+  ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK)
+
+/* YYTRANSLATE[YYLEX] -- Bison symbol number corresponding to YYLEX.  */
+static const yytype_uint8 yytranslate[] =
+{
+       0,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,   133,     2,     2,     2,     2,     2,     2,
+     128,   129,   125,   123,     2,   124,     2,   126,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,   127,
+       2,   132,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,   130,     2,   131,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     1,     2,     3,     4,
+       5,     6,     7,     8,     9,    10,    11,    12,    13,    14,
+      15,    16,    17,    18,    19,    20,    21,    22,    23,    24,
+      25,    26,    27,    28,    29,    30,    31,    32,    33,    34,
+      35,    36,    37,    38,    39,    40,    41,    42,    43,    44,
+      45,    46,    47,    48,    49,    50,    51,    52,    53,    54,
+      55,    56,    57,    58,    59,    60,    61,    62,    63,    64,
+      65,    66,    67,    68,    69,    70,    71,    72,    73,    74,
+      75,    76,    77,    78,    79,    80,    81,    82,    83,    84,
+      85,    86,    87,    88,    89,    90,    91,    92,    93,    94,
+      95,    96,    97,    98,    99,   100,   101,   102,   103,   104,
+     105,   106,   107,   108,   109,   110,   111,   112,   113,   114,
+     115,   116,   117,   118,   119,   120,   121,   122
+};
+
+#if YYDEBUG
+/* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in
+   YYRHS.  */
+static const yytype_uint16 yyprhs[] =
+{
+       0,     0,     3,     6,     8,    10,    12,    14,    16,    18,
+      20,    22,    24,    26,    28,    30,    32,    34,    36,    38,
+      40,    42,    44,    46,    49,    51,    53,    56,    58,    61,
+      63,    65,    67,    69,    71,    73,    75,    77,    79,    82,
+      85,    88,    91,    94,    96,   100,   104,   108,   112,   116,
+     122,   125,   127,   129,   134,   135,   142,   145,   147,   149,
+     151,   153,   155,   157,   159,   164,   169,   174,   179,   186,
+     192,   193,   200,   203,   205,   207,   209,   214,   219,   220,
+     227,   230,   232,   234,   236,   238,   240,   242,   244,   246,
+     248,   253,   258,   263,   268,   273,   278,   283,   284,   291,
+     294,   296,   298,   300,   302,   304,   306,   308,   310,   312,
+     314,   316,   318,   320,   325,   330,   335,   340,   345,   350,
+     353,   356,   361,   366,   371,   376,   381,   386,   392,   395,
+     397,   399,   404,   410,   412,   415,   417,   419,   421,   423,
+     425,   430,   435,   440,   445,   450,   452,   454,   456,   458,
+     460,   462,   464,   466,   468,   470,   472,   474,   476,   478,
+     480,   482,   484,   486,   488,   490,   492,   494,   496,   498,
+     500,   502,   504,   506,   508,   510,   512,   514,   516,   518,
+     520,   522,   524,   526,   528,   530,   532,   534,   536,   538,
+     540,   542,   543,   545,   547,   550,   553,   559,   562,   564,
+     566,   568,   570,   572,   574,   576,   578,   584,   590,   597,
+     602,   607,   612,   617,   622,   627,   632,   633,   640,   643,
+     645,   647,   649,   651,   653,   655,   657,   659,   664,   669,
+     674,   679,   684,   689,   694,   695,   702,   705,   707,   709,
+     711,   713,   715,   717,   722,   727,   732,   737,   742,   743,
+     750,   753,   755,   757,   759,   761,   766,   771,   776,   781,
+     787,   790,   792,   794,   796,   801,   806,   812,   815,   817,
+     818,   824,   827,   829,   831,   837,   840,   842,   847,   848,
+     856,   859,   861,   863,   865,   867,   869,   874,   879,   884,
+     887,   893,   896,   898,   900,   902,   903,   909,   914,   915,
+     922,   925,   927,   932,   933,   940,   943,   945,   947,   949,
+     951,   953,   955,   957,   962,   967,   973,   978,   984,   989,
+     995,   998,  1000,  1002,  1004,  1009
+};
+
+/* YYRHS -- A `-1'-separated list of the rules' RHS.  */
+static const yytype_int16 yyrhs[] =
+{
+     135,     0,    -1,   135,   136,    -1,   136,    -1,   157,    -1,
+     147,    -1,   163,    -1,   174,    -1,   190,    -1,   194,    -1,
+     205,    -1,   143,    -1,   215,    -1,   226,    -1,   235,    -1,
+     242,    -1,   247,    -1,   253,    -1,   256,    -1,   264,    -1,
+     270,    -1,   274,    -1,   284,    -1,     1,   127,    -1,   142,
+      -1,   138,    -1,   138,   139,    -1,   139,    -1,   142,   140,
+      -1,    23,    -1,    24,    -1,    25,    -1,    26,    -1,    27,
+      -1,    28,    -1,    29,    -1,    30,    -1,   142,    -1,   142,
+      31,    -1,   142,    32,    -1,   142,    33,    -1,   142,    34,
+      -1,   142,    35,    -1,     4,    -1,   142,   123,   142,    -1,
+     142,   124,   142,    -1,   142,   125,   142,    -1,   142,   126,
+     142,    -1,   128,   142,   129,    -1,    48,   130,   144,   131,
+     127,    -1,   145,   144,    -1,   145,    -1,   146,    -1,    49,
+     132,     3,   127,    -1,    -1,     5,   148,   130,   149,   131,
+     127,    -1,   150,   149,    -1,   150,    -1,   151,    -1,   152,
+      -1,   154,    -1,   153,    -1,   155,    -1,   156,    -1,    50,
+     132,     4,   127,    -1,    17,   132,     3,   127,    -1,    51,
+     132,     3,   127,    -1,    45,   132,     3,   127,    -1,    72,
+      45,   132,   204,     3,   127,    -1,    72,    36,   132,     3,
+     127,    -1,    -1,     6,   158,   130,   159,   131,   127,    -1,
+     159,   160,    -1,   160,    -1,   161,    -1,   162,    -1,     7,
+     132,     3,   127,    -1,     8,   132,     3,   127,    -1,    -1,
+      10,   164,   130,   165,   131,   127,    -1,   166,   165,    -1,
+     166,    -1,   167,    -1,   169,    -1,   170,    -1,   171,    -1,
+     172,    -1,   173,    -1,   201,    -1,   168,    -1,    17,   132,
+       3,   127,    -1,    77,   132,   142,   127,    -1,    12,   132,
+     137,   127,    -1,    13,   132,   137,   127,    -1,    14,   132,
+     142,   127,    -1,    16,   132,   141,   127,    -1,    64,   132,
+       3,   127,    -1,    -1,     9,   175,   130,   176,   131,   127,
+      -1,   177,   176,    -1,   177,    -1,   178,    -1,   179,    -1,
+     180,    -1,   181,    -1,   182,    -1,   183,    -1,   184,    -1,
+     185,    -1,   186,    -1,   187,    -1,   188,    -1,   189,    -1,
+      17,   132,     3,   127,    -1,    21,   132,     3,   127,    -1,
+      10,   132,     3,   127,    -1,    18,   132,     3,   127,    -1,
+      37,   132,     4,   127,    -1,    45,   132,     3,   127,    -1,
+      40,   127,    -1,    39,   127,    -1,    39,   132,     3,   127,
+      -1,    15,   132,   142,   127,    -1,    68,   132,    42,   127,
+      -1,    68,   132,    43,   127,    -1,    74,   132,    42,   127,
+      -1,    74,   132,    43,   127,    -1,    41,   130,   191,   131,
+     127,    -1,   192,   191,    -1,   192,    -1,   193,    -1,    17,
+     132,     3,   127,    -1,    44,   130,   195,   131,   127,    -1,
+     196,    -1,   195,   196,    -1,   197,    -1,   198,    -1,   199,
+      -1,   200,    -1,   201,    -1,    17,   132,     3,   127,    -1,
+      21,   132,     3,   127,    -1,    18,   132,     3,   127,    -1,
+      10,   132,     3,   127,    -1,   202,   132,   203,   127,    -1,
+      82,    -1,    83,    -1,    84,    -1,    85,    -1,   111,    -1,
+     121,    -1,   113,    -1,   114,    -1,   115,    -1,   116,    -1,
+     112,    -1,   117,    -1,   118,    -1,   119,    -1,   120,    -1,
+      53,    -1,    86,    -1,    87,    -1,    88,    -1,    89,    -1,
+      90,    -1,    91,    -1,    48,    -1,    92,    -1,    94,    -1,
+      95,    -1,    96,    -1,    97,    -1,    98,    -1,    93,    -1,
+      99,    -1,   100,    -1,   101,    -1,   102,    -1,   103,    -1,
+     104,    -1,   105,    -1,   106,    -1,   110,    -1,    22,    -1,
+     107,    -1,   108,    -1,   122,    -1,   109,    -1,    42,    -1,
+      43,    -1,    -1,    70,    -1,    71,    -1,    70,    71,    -1,
+      71,    70,    -1,    37,   130,   206,   131,   127,    -1,   207,
+     206,    -1,   207,    -1,   208,    -1,   209,    -1,   210,    -1,
+     211,    -1,   212,    -1,   213,    -1,   214,    -1,    37,   132,
+     204,     4,   127,    -1,    45,   132,   204,     3,   127,    -1,
+      45,   132,   204,     3,     4,   127,    -1,    38,   132,     3,
+     127,    -1,    36,   132,    42,   127,    -1,    36,   132,    43,
+     127,    -1,    46,   132,    42,   127,    -1,    46,   132,    43,
+     127,    -1,    74,   132,    42,   127,    -1,    74,   132,    43,
+     127,    -1,    -1,    52,   216,   130,   217,   131,   127,    -1,
+     218,   217,    -1,   218,    -1,   219,    -1,   220,    -1,   221,
+      -1,   222,    -1,   223,    -1,   224,    -1,   225,    -1,    18,
+     132,     3,   127,    -1,    19,   132,     3,   127,    -1,    20,
+     132,     3,   127,    -1,    10,   132,     3,   127,    -1,    21,
+     132,     3,   127,    -1,    14,   132,   142,   127,    -1,    37,
+     132,   142,   127,    -1,    -1,    53,   227,   130,   228,   131,
+     127,    -1,   229,   228,    -1,   229,    -1,   230,    -1,   232,
+      -1,   231,    -1,   234,    -1,   233,    -1,    18,   132,     3,
+     127,    -1,    20,   132,     3,   127,    -1,    55,   132,     3,
+     127,    -1,    56,   132,     3,   127,    -1,    57,   132,     3,
+     127,    -1,    -1,    54,   236,   130,   237,   131,   127,    -1,
+     238,   237,    -1,   238,    -1,   239,    -1,   240,    -1,   241,
+      -1,    36,   132,     3,   127,    -1,    58,   132,     3,   127,
+      -1,    59,   132,    42,   127,    -1,    59,   132,    43,   127,
+      -1,    47,   130,   243,   131,   127,    -1,   244,   243,    -1,
+     244,    -1,   245,    -1,   246,    -1,    18,   132,     3,   127,
+      -1,    57,   132,     3,   127,    -1,    60,   130,   248,   131,
+     127,    -1,   248,   249,    -1,   249,    -1,    -1,     3,   250,
+     132,   251,   127,    -1,   251,   252,    -1,   252,    -1,     3,
+      -1,    61,   130,   254,   131,   127,    -1,   254,   255,    -1,
+     255,    -1,     3,   132,     3,   127,    -1,    -1,    62,     3,
+     130,   257,   258,   131,   127,    -1,   259,   258,    -1,   259,
+      -1,   260,    -1,   261,    -1,   262,    -1,   263,    -1,    17,
+     132,     3,   127,    -1,    63,   132,     3,   127,    -1,    49,
+     132,     3,   127,    -1,    67,   127,    -1,    65,   130,   265,
+     131,   127,    -1,   266,   265,    -1,   266,    -1,   267,    -1,
+     269,    -1,    -1,    69,   132,   268,   251,   127,    -1,    78,
+     132,   203,   127,    -1,    -1,    73,   271,   130,   272,   131,
+     127,    -1,   272,   273,    -1,   273,    -1,     3,   132,     3,
+     127,    -1,    -1,    75,   275,   130,   276,   131,   127,    -1,
+     276,   277,    -1,   277,    -1,   278,    -1,   279,    -1,   280,
+      -1,   281,    -1,   282,    -1,   283,    -1,    21,   132,     3,
+     127,    -1,    18,   132,     3,   127,    -1,    18,   133,   132,
+       3,   127,    -1,    76,   132,     3,   127,    -1,    76,   133,
+     132,     3,   127,    -1,    17,   132,     3,   127,    -1,    79,
+     130,   285,   131,   127,    -1,   285,   286,    -1,   286,    -1,
+     287,    -1,   288,    -1,    80,   132,     3,   127,    -1,    81,
+     132,     3,   127,    -1
+};
+
+/* YYRLINE[YYN] -- source line where rule number YYN was defined.  */
+static const yytype_uint16 yyrline[] =
+{
+       0,   214,   214,   214,   215,   215,   215,   215,   216,   216,
+     216,   216,   216,   217,   217,   217,   217,   217,   218,   218,
+     218,   218,   218,   218,   222,   222,   224,   227,   229,   234,
+     235,   236,   237,   238,   239,   240,   241,   244,   247,   250,
+     253,   256,   259,   265,   269,   272,   275,   278,   285,   290,
+     291,   291,   292,   293,   300,   299,   310,   310,   311,   311,
+     311,   311,   312,   312,   314,   323,   335,   342,   359,   381,
+     390,   389,   405,   405,   406,   406,   407,   416,   422,   422,
+     448,   448,   449,   449,   449,   449,   450,   450,   450,   450,
+     451,   456,   460,   464,   468,   472,   476,   483,   482,   527,
+     527,   528,   528,   528,   528,   529,   529,   529,   529,   530,
+     530,   530,   530,   531,   536,   541,   548,   553,   557,   562,
+     566,   571,   576,   580,   581,   582,   583,   585,   586,   586,
+     587,   588,   593,   627,   627,   628,   628,   628,   628,   628,
+     629,   634,   639,   655,   663,   673,   674,   675,   676,   677,
+     678,   679,   680,   681,   682,   683,   684,   685,   686,   687,
+     688,   689,   690,   691,   692,   693,   694,   695,   696,   697,
+     698,   699,   700,   701,   702,   703,   704,   705,   706,   707,
+     708,   709,   710,   711,   712,   713,   714,   715,   716,   718,
+     718,   724,   725,   726,   727,   728,   732,   767,   767,   768,
+     768,   768,   768,   768,   768,   768,   769,   780,   790,   804,
+     810,   813,   818,   821,   826,   829,   835,   834,   880,   880,
+     881,   881,   881,   881,   881,   881,   881,   882,   895,   909,
+     914,   921,   926,   930,   936,   935,   955,   955,   956,   956,
+     956,   956,   956,   957,   976,   982,   988,   995,  1003,  1002,
+    1035,  1035,  1036,  1036,  1036,  1038,  1047,  1053,  1056,  1061,
+    1072,  1072,  1073,  1073,  1074,  1083,  1089,  1090,  1090,  1093,
+    1092,  1103,  1103,  1104,  1112,  1113,  1113,  1114,  1124,  1123,
+    1152,  1152,  1153,  1153,  1153,  1153,  1154,  1159,  1164,  1178,
+    1183,  1194,  1194,  1195,  1195,  1197,  1196,  1205,  1210,  1210,
+    1216,  1216,  1217,  1225,  1225,  1241,  1241,  1242,  1242,  1242,
+    1242,  1242,  1242,  1243,  1249,  1255,  1261,  1267,  1273,  1292,
+    1293,  1293,  1294,  1294,  1295,  1299
+};
+#endif
+
+#if YYDEBUG || YYERROR_VERBOSE || YYTOKEN_TABLE
+/* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM.
+   First, the terminals, then, starting at YYNTOKENS, nonterminals.  */
+static const char *const yytname[] =
+{
+  "$end", "error", "$undefined", "QSTRING", "NUMBER", "GENERAL", "ADMIN",
+  "LOCATION", "CONTACT", "CONNECT", "CLASS", "CHANNEL", "PINGFREQ",
+  "CONNECTFREQ", "MAXLINKS", "MAXHOPS", "SENDQ", "NAME", "HOST", "IP",
+  "USERNAME", "PASS", "LOCAL", "SECONDS", "MINUTES", "HOURS", "DAYS",
+  "WEEKS", "MONTHS", "YEARS", "DECADES", "BYTES", "KBYTES", "MBYTES",
+  "GBYTES", "TBYTES", "SERVER", "PORT", "MASK", "HUB", "LEAF", "UWORLD",
+  "YES", "NO", "OPER", "VHOST", "HIDDEN", "MOTD", "JUPE", "NICK",
+  "NUMERIC", "DESCRIPTION", "CLIENT", "KILL", "CRULE", "REAL", "REASON",
+  "TFILE", "RULE", "ALL", "FEATURES", "QUARANTINE", "PSEUDO", "PREPEND",
+  "USERMODE", "IAUTH", "TIMEOUT", "FAST", "AUTOCONNECT", "PROGRAM",
+  "TOK_IPV4", "TOK_IPV6", "DNS", "FORWARDS", "SECURE", "WEBIRC", "SPOOF",
+  "MAXCHANS", "REQUIRED", "SSL", "CERT", "CACERT", "TPRIV_CHAN_LIMIT",
+  "TPRIV_MODE_LCHAN", "TPRIV_DEOP_LCHAN", "TPRIV_WALK_LCHAN",
+  "TPRIV_LOCAL_KILL", "TPRIV_REHASH", "TPRIV_RESTART", "TPRIV_DIE",
+  "TPRIV_GLINE", "TPRIV_LOCAL_GLINE", "TPRIV_LOCAL_JUPE",
+  "TPRIV_LOCAL_BADCHAN", "TPRIV_LOCAL_OPMODE", "TPRIV_OPMODE", "TPRIV_SET",
+  "TPRIV_WHOX", "TPRIV_BADCHAN", "TPRIV_SEE_CHAN", "TPRIV_SHOW_INVIS",
+  "TPRIV_SHOW_ALL_INVIS", "TPRIV_PROPAGATE", "TPRIV_UNLIMIT_QUERY",
+  "TPRIV_DISPLAY", "TPRIV_SEE_OPERS", "TPRIV_WIDE_GLINE",
+  "TPRIV_FORCE_OPMODE", "TPRIV_FORCE_LOCAL_OPMODE", "TPRIV_APASS_OPMODE",
+  "TPRIV_LIST_CHAN", "TPRIV_SEE_IDLETIME", "TPRIV_UMODE_NETSERV",
+  "TPRIV_UMODE_NOCHAN", "TPRIV_UMODE_NOIDLE", "TPRIV_UMODE_CHSERV",
+  "TPRIV_UMODE_XTRAOP", "TPRIV_FLOOD", "TPRIV_HALFFLOOD",
+  "TPRIV_UNLIMITED_TARGET", "TPRIV_UMODE_OVERRIDECC",
+  "TPRIV_HIDE_IDLETIME", "TPRIV_NOAMSG_OVERRIDE", "'+'", "'-'", "'*'",
+  "'/'", "';'", "'('", "')'", "'{'", "'}'", "'='", "'!'", "$accept",
+  "blocks", "block", "timespec", "factoredtimes", "factoredtime",
+  "timefactor", "sizespec", "expr", "jupeblock", "jupeitems", "jupeitem",
+  "jupenick", "generalblock", "@1", "generalitems", "generalitem",
+  "generalnumeric", "generalname", "generaldesc", "generalvhost",
+  "generaldnsvhost", "generaldnsserver", "adminblock", "@2", "adminitems",
+  "adminitem", "adminlocation", "admincontact", "classblock", "@3",
+  "classitems", "classitem", "classname", "maxchans", "classpingfreq",
+  "classconnfreq", "classmaxlinks", "classsendq", "classusermode",
+  "connectblock", "@4", "connectitems", "connectitem", "connectname",
+  "connectpass", "connectclass", "connecthost", "connectport",
+  "connectvhost", "connectleaf", "connecthub", "connecthublimit",
+  "connectmaxhops", "connectauto", "connectsecure", "uworldblock",
+  "uworlditems", "uworlditem", "uworldname", "operblock", "operitems",
+  "operitem", "opername", "operpass", "operhost", "operclass", "priv",
+  "privtype", "yesorno", "address_family", "portblock", "portitems",
+  "portitem", "portnumber", "portvhost", "portvhostnumber", "portmask",
+  "portserver", "porthidden", "portsecure", "clientblock", "@5",
+  "clientitems", "clientitem", "clienthost", "clientip", "clientusername",
+  "clientclass", "clientpass", "clientmaxlinks", "clientport", "killblock",
+  "@6", "killitems", "killitem", "killuhost", "killusername", "killreal",
+  "killreason", "killreasonfile", "cruleblock", "@7", "cruleitems",
+  "cruleitem", "cruleserver", "crulerule", "cruleall", "motdblock",
+  "motditems", "motditem", "motdhost", "motdfile", "featuresblock",
+  "featureitems", "featureitem", "@8", "stringlist", "extrastring",
+  "quarantineblock", "quarantineitems", "quarantineitem", "pseudoblock",
+  "@9", "pseudoitems", "pseudoitem", "pseudoname", "pseudoprepend",
+  "pseudonick", "pseudoflags", "iauthblock", "iauthitems", "iauthitem",
+  "iauthprogram", "@10", "iauthrequired", "forwardsblock", "@11",
+  "forwarditems", "forwarditem", "webircblock", "@12", "webircitems",
+  "webircitem", "webircpass", "webirchost", "webircnhost", "webircspoof",
+  "webircnspoof", "webircname", "sslblock", "sslitems", "sslitem",
+  "sslcert", "sslcacert", 0
+};
+#endif
+
+# ifdef YYPRINT
+/* YYTOKNUM[YYLEX-NUM] -- Internal token number corresponding to
+   token YYLEX-NUM.  */
+static const yytype_uint16 yytoknum[] =
+{
+       0,   256,   257,   258,   259,   260,   261,   262,   263,   264,
+     265,   266,   267,   268,   269,   270,   271,   272,   273,   274,
+     275,   276,   277,   278,   279,   280,   281,   282,   283,   284,
+     285,   286,   287,   288,   289,   290,   291,   292,   293,   294,
+     295,   296,   297,   298,   299,   300,   301,   302,   303,   304,
+     305,   306,   307,   308,   309,   310,   311,   312,   313,   314,
+     315,   316,   317,   318,   319,   320,   321,   322,   323,   324,
+     325,   326,   327,   328,   329,   330,   331,   332,   333,   334,
+     335,   336,   337,   338,   339,   340,   341,   342,   343,   344,
+     345,   346,   347,   348,   349,   350,   351,   352,   353,   354,
+     355,   356,   357,   358,   359,   360,   361,   362,   363,   364,
+     365,   366,   367,   368,   369,   370,   371,   372,   373,   374,
+     375,   376,   377,    43,    45,    42,    47,    59,    40,    41,
+     123,   125,    61,    33
+};
+# endif
+
+/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives.  */
+static const yytype_uint16 yyr1[] =
+{
+       0,   134,   135,   135,   136,   136,   136,   136,   136,   136,
+     136,   136,   136,   136,   136,   136,   136,   136,   136,   136,
+     136,   136,   136,   136,   137,   137,   138,   138,   139,   140,
+     140,   140,   140,   140,   140,   140,   140,   141,   141,   141,
+     141,   141,   141,   142,   142,   142,   142,   142,   142,   143,
+     144,   144,   145,   146,   148,   147,   149,   149,   150,   150,
+     150,   150,   150,   150,   151,   152,   153,   154,   155,   156,
+     158,   157,   159,   159,   160,   160,   161,   162,   164,   163,
+     165,   165,   166,   166,   166,   166,   166,   166,   166,   166,
+     167,   168,   169,   170,   171,   172,   173,   175,   174,   176,
+     176,   177,   177,   177,   177,   177,   177,   177,   177,   177,
+     177,   177,   177,   178,   179,   180,   181,   182,   183,   184,
+     185,   186,   187,   188,   188,   189,   189,   190,   191,   191,
+     192,   193,   194,   195,   195,   196,   196,   196,   196,   196,
+     197,   198,   199,   200,   201,   202,   202,   202,   202,   202,
+     202,   202,   202,   202,   202,   202,   202,   202,   202,   202,
+     202,   202,   202,   202,   202,   202,   202,   202,   202,   202,
+     202,   202,   202,   202,   202,   202,   202,   202,   202,   202,
+     202,   202,   202,   202,   202,   202,   202,   202,   202,   203,
+     203,   204,   204,   204,   204,   204,   205,   206,   206,   207,
+     207,   207,   207,   207,   207,   207,   208,   209,   210,   211,
+     212,   212,   213,   213,   214,   214,   216,   215,   217,   217,
+     218,   218,   218,   218,   218,   218,   218,   219,   220,   221,
+     222,   223,   224,   225,   227,   226,   228,   228,   229,   229,
+     229,   229,   229,   230,   231,   232,   233,   234,   236,   235,
+     237,   237,   238,   238,   238,   239,   240,   241,   241,   242,
+     243,   243,   244,   244,   245,   246,   247,   248,   248,   250,
+     249,   251,   251,   252,   253,   254,   254,   255,   257,   256,
+     258,   258,   259,   259,   259,   259,   260,   261,   262,   263,
+     264,   265,   265,   266,   266,   268,   267,   269,   271,   270,
+     272,   272,   273,   275,   274,   276,   276,   277,   277,   277,
+     277,   277,   277,   278,   279,   280,   281,   282,   283,   284,
+     285,   285,   286,   286,   287,   288
+};
+
+/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN.  */
+static const yytype_uint8 yyr2[] =
+{
+       0,     2,     2,     1,     1,     1,     1,     1,     1,     1,
+       1,     1,     1,     1,     1,     1,     1,     1,     1,     1,
+       1,     1,     1,     2,     1,     1,     2,     1,     2,     1,
+       1,     1,     1,     1,     1,     1,     1,     1,     2,     2,
+       2,     2,     2,     1,     3,     3,     3,     3,     3,     5,
+       2,     1,     1,     4,     0,     6,     2,     1,     1,     1,
+       1,     1,     1,     1,     4,     4,     4,     4,     6,     5,
+       0,     6,     2,     1,     1,     1,     4,     4,     0,     6,
+       2,     1,     1,     1,     1,     1,     1,     1,     1,     1,
+       4,     4,     4,     4,     4,     4,     4,     0,     6,     2,
+       1,     1,     1,     1,     1,     1,     1,     1,     1,     1,
+       1,     1,     1,     4,     4,     4,     4,     4,     4,     2,
+       2,     4,     4,     4,     4,     4,     4,     5,     2,     1,
+       1,     4,     5,     1,     2,     1,     1,     1,     1,     1,
+       4,     4,     4,     4,     4,     1,     1,     1,     1,     1,
+       1,     1,     1,     1,     1,     1,     1,     1,     1,     1,
+       1,     1,     1,     1,     1,     1,     1,     1,     1,     1,
+       1,     1,     1,     1,     1,     1,     1,     1,     1,     1,
+       1,     1,     1,     1,     1,     1,     1,     1,     1,     1,
+       1,     0,     1,     1,     2,     2,     5,     2,     1,     1,
+       1,     1,     1,     1,     1,     1,     5,     5,     6,     4,
+       4,     4,     4,     4,     4,     4,     0,     6,     2,     1,
+       1,     1,     1,     1,     1,     1,     1,     4,     4,     4,
+       4,     4,     4,     4,     0,     6,     2,     1,     1,     1,
+       1,     1,     1,     4,     4,     4,     4,     4,     0,     6,
+       2,     1,     1,     1,     1,     4,     4,     4,     4,     5,
+       2,     1,     1,     1,     4,     4,     5,     2,     1,     0,
+       5,     2,     1,     1,     5,     2,     1,     4,     0,     7,
+       2,     1,     1,     1,     1,     1,     4,     4,     4,     2,
+       5,     2,     1,     1,     1,     0,     5,     4,     0,     6,
+       2,     1,     4,     0,     6,     2,     1,     1,     1,     1,
+       1,     1,     1,     4,     4,     5,     4,     5,     4,     5,
+       2,     1,     1,     1,     4,     4
+};
+
+/* YYDEFACT[STATE-NAME] -- Default rule to reduce with in state
+   STATE-NUM when YYTABLE doesn't specify something else to do.  Zero
+   means the default is an error.  */
+static const yytype_uint16 yydefact[] =
+{
+       0,     0,    54,    70,    97,    78,     0,     0,     0,     0,
+       0,   216,   234,   248,     0,     0,     0,     0,   298,   303,
+       0,     0,     3,    11,     5,     4,     6,     7,     8,     9,
+      10,    12,    13,    14,    15,    16,    17,    18,    19,    20,
+      21,    22,    23,     0,     0,     0,     0,     0,     0,     0,
+       0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
+       0,     0,     1,     2,     0,     0,     0,     0,     0,     0,
+       0,     0,     0,     0,     0,   198,   199,   200,   201,   202,
+     203,   204,   205,     0,     0,   129,   130,     0,     0,     0,
+       0,   184,   167,   160,   145,   146,   147,   148,   161,   162,
+     163,   164,   165,   166,   168,   174,   169,   170,   171,   172,
+     173,   175,   176,   177,   178,   179,   180,   181,   182,   185,
+     186,   188,   183,   149,   155,   151,   152,   153,   154,   156,
+     157,   158,   159,   150,   187,     0,   133,   135,   136,   137,
+     138,   139,     0,     0,     0,     0,   261,   262,   263,     0,
+       0,    51,    52,     0,     0,     0,   269,     0,   268,     0,
+       0,   276,   278,     0,     0,     0,   292,   293,   294,     0,
+       0,     0,     0,     0,   321,   322,   323,     0,     0,     0,
+       0,     0,     0,    57,    58,    59,    61,    60,    62,    63,
+       0,     0,     0,    73,    74,    75,     0,     0,     0,     0,
+       0,     0,     0,     0,     0,     0,     0,     0,   100,   101,
+     102,   103,   104,   105,   106,   107,   108,   109,   110,   111,
+     112,     0,     0,     0,     0,     0,     0,     0,     0,    81,
+      82,    89,    83,    84,    85,    86,    87,    88,     0,   191,
+       0,   191,     0,     0,     0,   197,     0,     0,   128,     0,
+       0,     0,     0,     0,   134,     0,     0,     0,     0,   260,
+       0,     0,    50,     0,     0,     0,     0,     0,     0,     0,
+       0,   219,   220,   221,   222,   223,   224,   225,   226,     0,
+       0,     0,     0,     0,     0,   237,   238,   240,   239,   242,
+     241,     0,     0,     0,     0,   251,   252,   253,   254,     0,
+       0,   267,     0,     0,   275,     0,   295,     0,     0,   291,
+       0,     0,   301,     0,     0,     0,     0,     0,   306,   307,
+     308,   309,   310,   311,   312,     0,     0,     0,   320,     0,
+       0,     0,     0,     0,     0,     0,    56,     0,     0,     0,
+      72,     0,     0,     0,     0,     0,     0,   120,     0,   119,
+       0,     0,     0,     0,    99,     0,     0,     0,     0,     0,
+       0,     0,     0,    80,     0,     0,   192,   193,     0,     0,
+       0,     0,     0,     0,     0,   196,     0,   127,     0,     0,
+       0,     0,   132,   189,   190,     0,     0,     0,   259,     0,
+      49,     0,     0,     0,     0,     0,     0,     0,     0,   218,
+       0,     0,     0,     0,     0,     0,   236,     0,     0,     0,
+       0,   250,     0,   266,     0,   274,     0,     0,     0,     0,
+       0,   281,   282,   283,   284,   285,     0,     0,   290,     0,
+       0,   300,     0,     0,     0,     0,     0,     0,     0,   305,
+       0,     0,   319,     0,     0,     0,     0,     0,   191,    55,
+       0,     0,    71,     0,    43,     0,     0,     0,     0,     0,
+       0,     0,     0,     0,     0,     0,     0,    98,     0,    25,
+      27,    24,     0,     0,     0,    37,     0,     0,     0,    79,
+     210,   211,   194,   195,     0,   209,     0,   212,   213,   214,
+     215,   131,   143,   140,   142,   141,   144,   264,   265,    53,
+       0,     0,     0,     0,     0,     0,     0,   217,     0,     0,
+       0,     0,     0,   235,     0,     0,     0,     0,   249,   273,
+       0,   272,   277,     0,     0,     0,   289,     0,   280,     0,
+     297,     0,   299,     0,     0,     0,     0,     0,     0,   304,
+     324,   325,    65,    67,    64,    66,     0,     0,    76,    77,
+     115,     0,     0,     0,     0,     0,   122,   113,   116,   114,
+     117,   121,   118,   123,   124,   125,   126,    92,    26,     0,
+      29,    30,    31,    32,    33,    34,    35,    36,    28,    93,
+      94,    95,    38,    39,    40,    41,    42,    90,    96,    91,
+     206,     0,   207,   230,   232,   227,   228,   229,   231,   233,
+     243,   244,   245,   246,   247,   255,   256,   257,   258,   270,
+     271,     0,     0,     0,   279,   296,   302,   318,   314,     0,
+     313,   316,     0,    69,     0,    48,    44,    45,    46,    47,
+     208,   286,   288,   287,   315,   317,    68
+};
+
+/* YYDEFGOTO[NTERM-NUM].  */
+static const yytype_int16 yydefgoto[] =
+{
+      -1,    21,    22,   468,   469,   470,   578,   474,   471,    23,
+     150,   151,   152,    24,    43,   182,   183,   184,   185,   186,
+     187,   188,   189,    25,    44,   192,   193,   194,   195,    26,
+      46,   228,   229,   230,   231,   232,   233,   234,   235,   236,
+      27,    45,   207,   208,   209,   210,   211,   212,   213,   214,
+     215,   216,   217,   218,   219,   220,    28,    84,    85,    86,
+      29,   135,   136,   137,   138,   139,   140,   141,   142,   385,
+     368,    30,    74,    75,    76,    77,    78,    79,    80,    81,
+      82,    31,    52,   270,   271,   272,   273,   274,   275,   276,
+     277,   278,    32,    53,   284,   285,   286,   287,   288,   289,
+     290,    33,    54,   294,   295,   296,   297,   298,    34,   145,
+     146,   147,   148,    35,   157,   158,   299,   520,   521,    36,
+     160,   161,    37,   305,   420,   421,   422,   423,   424,   425,
+      38,   165,   166,   167,   426,   168,    39,    59,   311,   312,
+      40,    60,   317,   318,   319,   320,   321,   322,   323,   324,
+      41,   173,   174,   175,   176
+};
+
+/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
+   STATE-NUM.  */
+#define YYPACT_NINF -454
+static const yytype_int16 yypact[] =
+{
+     480,  -104,  -454,  -454,  -454,  -454,  -103,   -96,   -64,   -53,
+     -34,  -454,  -454,  -454,   -27,   -23,    97,   -21,  -454,  -454,
+     -19,    37,  -454,  -454,  -454,  -454,  -454,  -454,  -454,  -454,
+    -454,  -454,  -454,  -454,  -454,  -454,  -454,  -454,  -454,  -454,
+    -454,  -454,  -454,   -16,   -10,    16,    22,    34,   122,   247,
+      -5,    92,    25,    41,    56,   190,   191,    66,     4,    67,
+      77,   -72,  -454,  -454,     3,    57,   130,   358,    73,    74,
+     124,   134,   148,   149,    78,    34,  -454,  -454,  -454,  -454,
+    -454,  -454,  -454,   150,   136,   122,  -454,   151,   153,   154,
+     155,  -454,  -454,  -454,  -454,  -454,  -454,  -454,  -454,  -454,
+    -454,  -454,  -454,  -454,  -454,  -454,  -454,  -454,  -454,  -454,
+    -454,  -454,  -454,  -454,  -454,  -454,  -454,  -454,  -454,  -454,
+    -454,  -454,  -454,  -454,  -454,  -454,  -454,  -454,  -454,  -454,
+    -454,  -454,  -454,  -454,  -454,   132,  -454,  -454,  -454,  -454,
+    -454,  -454,   156,   157,   159,   161,    -5,  -454,  -454,   162,
+     165,    92,  -454,   158,    31,   -14,  -454,     0,  -454,   166,
+       1,  -454,  -454,   167,   169,   171,     4,  -454,  -454,   252,
+      18,   172,   173,   -63,  -454,  -454,  -454,   174,   175,   176,
+     177,    59,   179,     3,  -454,  -454,  -454,  -454,  -454,  -454,
+     180,   181,    -1,  -454,  -454,  -454,   182,   183,   184,   185,
+     186,   187,  -106,   163,   188,   189,   192,   194,   130,  -454,
+    -454,  -454,  -454,  -454,  -454,  -454,  -454,  -454,  -454,  -454,
+    -454,   195,   196,   241,   244,   245,   246,   249,   248,   358,
+    -454,  -454,  -454,  -454,  -454,  -454,  -454,  -454,    50,   -30,
+     281,   -30,    63,    75,   170,  -454,   290,   199,  -454,   300,
+     308,   319,   320,   255,  -454,    83,   380,   381,   258,  -454,
+     383,   260,  -454,   256,   257,   259,   261,   262,   263,   264,
+     266,   158,  -454,  -454,  -454,  -454,  -454,  -454,  -454,   267,
+     268,   269,   270,   271,   273,    31,  -454,  -454,  -454,  -454,
+    -454,   275,   276,   277,   274,   -14,  -454,  -454,  -454,   278,
+     265,  -454,   387,   285,  -454,    52,  -454,    83,   286,  -454,
+     282,     2,  -454,   283,    -4,   284,    11,     7,  -454,  -454,
+    -454,  -454,  -454,  -454,  -454,   395,   414,   291,  -454,   416,
+     417,   419,   418,   292,   293,   299,  -454,   424,   425,   302,
+    -454,   427,     6,   428,   429,   430,   432,  -454,   431,  -454,
+     434,   118,   120,   311,  -454,     6,     6,     6,     6,   436,
+     479,     6,   356,  -454,   357,   360,   420,   422,   484,   366,
+     491,   368,   369,   370,   371,  -454,   372,  -454,   373,   374,
+     375,   376,  -454,  -454,  -454,   377,   378,   379,  -454,   382,
+    -454,   504,     6,   505,   507,   508,   509,     6,   386,  -454,
+     511,   512,   513,   515,   516,   393,  -454,   519,   520,   123,
+     398,  -454,   523,  -454,   402,  -454,   399,   403,   404,   410,
+     407,    52,  -454,  -454,  -454,  -454,   523,   412,  -454,   527,
+     421,  -454,   540,   541,   415,   543,   546,   426,   423,  -454,
+     433,   435,  -454,   437,   438,   439,   440,   548,   -30,  -454,
+     441,   442,  -454,   443,  -454,     6,    65,   444,   445,   446,
+     447,   448,   449,   450,   451,   452,   453,  -454,   454,     6,
+    -454,    33,   455,    76,   456,    -2,   457,   458,   135,  -454,
+    -454,  -454,  -454,  -454,   459,  -454,    10,  -454,  -454,  -454,
+    -454,  -454,  -454,  -454,  -454,  -454,  -454,  -454,  -454,  -454,
+     460,   147,   461,   462,   463,   464,   152,  -454,   465,   466,
+     467,   468,   469,  -454,   470,   471,   472,   473,  -454,  -454,
+       8,  -454,  -454,   549,   551,   553,  -454,   474,  -454,     9,
+    -454,   475,  -454,   476,   477,   554,   478,   481,   558,  -454,
+    -454,  -454,  -454,  -454,  -454,  -454,   482,   560,  -454,  -454,
+    -454,    58,     6,     6,     6,     6,  -454,  -454,  -454,  -454,
+    -454,  -454,  -454,  -454,  -454,  -454,  -454,  -454,  -454,    33,
+    -454,  -454,  -454,  -454,  -454,  -454,  -454,  -454,  -454,  -454,
+    -454,  -454,  -454,  -454,  -454,  -454,  -454,  -454,  -454,  -454,
+    -454,   483,  -454,  -454,  -454,  -454,  -454,  -454,  -454,  -454,
+    -454,  -454,  -454,  -454,  -454,  -454,  -454,  -454,  -454,  -454,
+    -454,   485,   486,   487,  -454,  -454,  -454,  -454,  -454,   488,
+    -454,  -454,   489,  -454,   490,  -454,    48,    48,  -454,  -454,
+    -454,  -454,  -454,  -454,  -454,  -454,  -454
+};
+
+/* YYPGOTO[NTERM-NUM].  */
+static const yytype_int16 yypgoto[] =
+{
+    -454,  -454,   585,   251,  -454,   142,  -454,  -454,  -342,  -454,
+     492,  -454,  -454,  -454,  -454,   493,  -454,  -454,  -454,  -454,
+    -454,  -454,  -454,  -454,  -454,  -454,   494,  -454,  -454,  -454,
+    -454,   389,  -454,  -454,  -454,  -454,  -454,  -454,  -454,  -454,
+    -454,  -454,   411,  -454,  -454,  -454,  -454,  -454,  -454,  -454,
+    -454,  -454,  -454,  -454,  -454,  -454,  -454,   535,  -454,  -454,
+    -454,  -454,   495,  -454,  -454,  -454,  -454,   -65,  -454,   314,
+    -240,  -454,   547,  -454,  -454,  -454,  -454,  -454,  -454,  -454,
+    -454,  -454,  -454,   352,  -454,  -454,  -454,  -454,  -454,  -454,
+    -454,  -454,  -454,  -454,   339,  -454,  -454,  -454,  -454,  -454,
+    -454,  -454,  -454,   330,  -454,  -454,  -454,  -454,  -454,   496,
+    -454,  -454,  -454,  -454,  -454,   497,  -454,   200,  -453,  -454,
+    -454,   498,  -454,  -454,   206,  -454,  -454,  -454,  -454,  -454,
+    -454,   499,  -454,  -454,  -454,  -454,  -454,  -454,  -454,   317,
+    -454,  -454,  -454,   312,  -454,  -454,  -454,  -454,  -454,  -454,
+    -454,  -454,   500,  -454,  -454
+};
+
+/* YYTABLE[YYPACT[STATE-NUM]].  What to do in state STATE-NUM.  If
+   positive, shift that token.  If negative, reduce the rule which
+   number is the opposite.  If zero, do what YYDEFACT says.
+   If YYTABLE_NINF, syntax error.  */
+#define YYTABLE_NINF -1
+static const yytype_uint16 yytable[] =
+{
+     456,   370,   237,   156,   159,   310,   190,   191,   171,   172,
+     454,   519,   519,   143,   591,   473,   475,   171,   172,   478,
+     177,   347,   291,    42,   313,   314,   348,    47,   315,   582,
+     583,   584,   585,   586,    48,   313,   314,    62,     1,   315,
+     366,   367,     2,     3,   292,   293,     4,     5,   178,   279,
+     501,   280,   144,   179,   180,   506,   570,   571,   572,   573,
+     574,   575,   576,   577,   190,   191,    49,   610,   327,   416,
+      68,    69,    70,   163,     6,   181,   610,    50,     7,    71,
+      72,     8,   164,   316,     9,    10,   281,   282,   283,    11,
+      12,    13,   364,   365,   316,   333,    51,    14,    15,    16,
+      57,   417,    17,    55,   334,   371,   372,    56,    73,    58,
+      18,    61,    19,   551,    64,   418,    20,   373,   374,   419,
+      65,   552,   553,   554,   555,   383,   384,   569,   433,   434,
+     339,   300,   303,   430,   455,   609,   615,   592,   438,    83,
+     196,   149,    87,   436,   437,   197,    66,   198,   199,    88,
+      89,   200,    67,    90,    91,   153,   552,   553,   554,   555,
+     463,   464,   465,   466,   237,   516,   517,   201,   263,   202,
+     203,   154,   264,   554,   555,   204,   265,   266,   267,   268,
+      92,   552,   553,   554,   555,    93,   155,   625,   552,   553,
+     554,   555,   556,   156,   159,   269,   162,   169,   205,   552,
+     553,   554,   555,   580,   206,   238,   239,   170,   547,   244,
+     626,   627,   628,   629,    94,    95,    96,    97,    98,    99,
+     100,   101,   102,   103,   104,   105,   106,   107,   108,   109,
+     110,   111,   112,   113,   114,   115,   116,   117,   118,   119,
+     120,   121,   122,   123,   124,   125,   126,   127,   128,   129,
+     130,   131,   132,   133,   134,   310,   240,    87,   552,   553,
+     554,   555,   589,   253,    88,    89,   241,   247,    90,    91,
+     552,   553,   554,   555,   594,   552,   553,   554,   555,   599,
+     242,   243,   246,   249,   369,   250,   251,   252,   255,   256,
+     349,   257,   258,   376,   260,    92,   261,   375,   302,   306,
+      93,   307,   308,   378,   325,   326,   329,   330,   331,   332,
+     335,   379,   337,   338,   341,   342,   343,   344,   345,   346,
+     350,   351,   380,   381,   352,   353,   377,   355,   356,    94,
+      95,    96,    97,    98,    99,   100,   101,   102,   103,   104,
+     105,   106,   107,   108,   109,   110,   111,   112,   113,   114,
+     115,   116,   117,   118,   119,   120,   121,   122,   123,   124,
+     125,   126,   127,   128,   129,   130,   131,   132,   133,   134,
+     221,   222,   223,   357,   224,   225,   358,   359,   360,   362,
+      91,   361,   382,   386,   387,   388,   389,   390,   391,   392,
+     414,   393,   413,   394,   395,   396,   397,   398,   440,   400,
+     401,   402,   403,   404,   405,   410,    92,   407,   408,   409,
+     412,    93,   415,   428,   429,   432,   435,   441,   442,   443,
+     444,   446,   226,   445,   447,   448,   449,   450,   451,   452,
+     453,   457,   458,   459,   461,   227,   460,   462,   467,   476,
+      94,    95,    96,    97,    98,    99,   100,   101,   102,   103,
+     104,   105,   106,   107,   108,   109,   110,   111,   112,   113,
+     114,   115,   116,   117,   118,   119,   120,   121,   122,   123,
+     124,   125,   126,   127,   128,   129,   130,   131,   132,   133,
+     134,     1,   477,   479,   480,     2,     3,   481,   484,     4,
+       5,   482,   483,   485,   486,   487,   488,   489,   490,   491,
+     492,   493,   494,   495,   496,   497,   498,   500,   502,   499,
+     503,   504,   505,   507,   508,   509,   510,     6,   511,   512,
+     513,     7,   514,   515,     8,   518,   519,     9,    10,   522,
+     531,   523,    11,    12,    13,   524,   525,   526,   527,   530,
+      14,    15,    16,   533,   534,    17,   536,   535,   532,   537,
+     539,   546,   611,    18,   612,    19,   613,   619,   538,    20,
+     540,   622,   541,   624,   542,   543,   544,   545,   548,   549,
+     550,   557,   558,   559,   560,   561,   562,   563,   564,   565,
+     566,   567,   579,   581,   587,   588,   590,   593,   595,   596,
+     597,   598,   600,   601,   602,   603,   604,   605,   606,   607,
+     608,   614,   616,   617,   618,   620,    63,   472,   621,   623,
+     630,   568,   631,   632,   633,   634,   635,   636,   363,   354,
+     248,   427,   245,   399,   406,   411,   529,   528,   431,   439,
+     254,     0,     0,     0,     0,     0,     0,     0,     0,     0,
+       0,     0,   259,   262,     0,     0,     0,     0,     0,     0,
+       0,     0,     0,     0,   301,     0,     0,     0,   304,     0,
+       0,     0,     0,     0,     0,   309,     0,     0,     0,     0,
+       0,     0,     0,   328,     0,     0,   336,     0,     0,     0,
+       0,     0,     0,     0,     0,     0,   340
+};
+
+static const yytype_int16 yycheck[] =
+{
+     342,   241,    67,     3,     3,     3,     7,     8,    80,    81,
+       4,     3,     3,    18,     4,   357,   358,    80,    81,   361,
+      17,   127,    36,   127,    17,    18,   132,   130,    21,    31,
+      32,    33,    34,    35,   130,    17,    18,     0,     1,    21,
+      70,    71,     5,     6,    58,    59,     9,    10,    45,    18,
+     392,    20,    57,    50,    51,   397,    23,    24,    25,    26,
+      27,    28,    29,    30,     7,     8,   130,   520,   131,    17,
+      36,    37,    38,    69,    37,    72,   529,   130,    41,    45,
+      46,    44,    78,    76,    47,    48,    55,    56,    57,    52,
+      53,    54,    42,    43,    76,    36,   130,    60,    61,    62,
+       3,    49,    65,   130,    45,    42,    43,   130,    74,   130,
+      73,   130,    75,   455,   130,    63,    79,    42,    43,    67,
+     130,   123,   124,   125,   126,    42,    43,   469,   132,   133,
+     131,   131,   131,   131,   128,   127,   127,   127,   131,    17,
+      10,    49,    10,   132,   133,    15,   130,    17,    18,    17,
+      18,    21,   130,    21,    22,   130,   123,   124,   125,   126,
+      42,    43,    42,    43,   229,    42,    43,    37,    10,    39,
+      40,   130,    14,   125,   126,    45,    18,    19,    20,    21,
+      48,   123,   124,   125,   126,    53,   130,   129,   123,   124,
+     125,   126,   127,     3,     3,    37,   130,   130,    68,   123,
+     124,   125,   126,   127,    74,   132,   132,   130,   448,   131,
+     552,   553,   554,   555,    82,    83,    84,    85,    86,    87,
+      88,    89,    90,    91,    92,    93,    94,    95,    96,    97,
+      98,    99,   100,   101,   102,   103,   104,   105,   106,   107,
+     108,   109,   110,   111,   112,   113,   114,   115,   116,   117,
+     118,   119,   120,   121,   122,     3,   132,    10,   123,   124,
+     125,   126,   127,   131,    17,    18,   132,   131,    21,    22,
+     123,   124,   125,   126,   127,   123,   124,   125,   126,   127,
+     132,   132,   132,   132,     3,   132,   132,   132,   132,   132,
+     127,   132,   131,     3,   132,    48,   131,   127,   132,   132,
+      53,   132,   131,     3,   132,   132,   132,   132,   132,   132,
+     131,     3,   132,   132,   132,   132,   132,   132,   132,   132,
+     132,   132,     3,     3,   132,   131,   127,   132,   132,    82,
+      83,    84,    85,    86,    87,    88,    89,    90,    91,    92,
+      93,    94,    95,    96,    97,    98,    99,   100,   101,   102,
+     103,   104,   105,   106,   107,   108,   109,   110,   111,   112,
+     113,   114,   115,   116,   117,   118,   119,   120,   121,   122,
+      12,    13,    14,   132,    16,    17,   132,   132,   132,   131,
+      22,   132,   127,     3,     3,   127,     3,   127,   132,   132,
+       3,   132,   127,   132,   132,   132,   132,   131,     3,   132,
+     132,   132,   132,   132,   131,   131,    48,   132,   132,   132,
+     132,    53,   127,   127,   132,   132,   132,     3,   127,     3,
+       3,     3,    64,     4,   132,   132,   127,     3,     3,   127,
+       3,     3,     3,     3,     3,    77,     4,     3,   127,     3,
+      82,    83,    84,    85,    86,    87,    88,    89,    90,    91,
+      92,    93,    94,    95,    96,    97,    98,    99,   100,   101,
+     102,   103,   104,   105,   106,   107,   108,   109,   110,   111,
+     112,   113,   114,   115,   116,   117,   118,   119,   120,   121,
+     122,     1,     3,   127,   127,     5,     6,   127,     4,     9,
+      10,    71,    70,   127,     3,   127,   127,   127,   127,   127,
+     127,   127,   127,   127,   127,   127,   127,     3,     3,   127,
+       3,     3,     3,   127,     3,     3,     3,    37,     3,     3,
+     127,    41,     3,     3,    44,   127,     3,    47,    48,   127,
+       3,   132,    52,    53,    54,   132,   132,   127,   131,   127,
+      60,    61,    62,     3,     3,    65,     3,   132,   127,     3,
+     127,     3,     3,    73,     3,    75,     3,     3,   132,    79,
+     127,     3,   127,     3,   127,   127,   127,   127,   127,   127,
+     127,   127,   127,   127,   127,   127,   127,   127,   127,   127,
+     127,   127,   127,   127,   127,   127,   127,   127,   127,   127,
+     127,   127,   127,   127,   127,   127,   127,   127,   127,   127,
+     127,   127,   127,   127,   127,   127,    21,   356,   127,   127,
+     127,   469,   127,   127,   127,   127,   127,   127,   229,   208,
+      85,   307,    75,   271,   285,   295,   426,   421,   311,   317,
+     135,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
+      -1,    -1,   146,   151,    -1,    -1,    -1,    -1,    -1,    -1,
+      -1,    -1,    -1,    -1,   157,    -1,    -1,    -1,   160,    -1,
+      -1,    -1,    -1,    -1,    -1,   166,    -1,    -1,    -1,    -1,
+      -1,    -1,    -1,   173,    -1,    -1,   183,    -1,    -1,    -1,
+      -1,    -1,    -1,    -1,    -1,    -1,   192
+};
+
+/* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
+   symbol of state STATE-NUM.  */
+static const yytype_uint16 yystos[] =
+{
+       0,     1,     5,     6,     9,    10,    37,    41,    44,    47,
+      48,    52,    53,    54,    60,    61,    62,    65,    73,    75,
+      79,   135,   136,   143,   147,   157,   163,   174,   190,   194,
+     205,   215,   226,   235,   242,   247,   253,   256,   264,   270,
+     274,   284,   127,   148,   158,   175,   164,   130,   130,   130,
+     130,   130,   216,   227,   236,   130,   130,     3,   130,   271,
+     275,   130,     0,   136,   130,   130,   130,   130,    36,    37,
+      38,    45,    46,    74,   206,   207,   208,   209,   210,   211,
+     212,   213,   214,    17,   191,   192,   193,    10,    17,    18,
+      21,    22,    48,    53,    82,    83,    84,    85,    86,    87,
+      88,    89,    90,    91,    92,    93,    94,    95,    96,    97,
+      98,    99,   100,   101,   102,   103,   104,   105,   106,   107,
+     108,   109,   110,   111,   112,   113,   114,   115,   116,   117,
+     118,   119,   120,   121,   122,   195,   196,   197,   198,   199,
+     200,   201,   202,    18,    57,   243,   244,   245,   246,    49,
+     144,   145,   146,   130,   130,   130,     3,   248,   249,     3,
+     254,   255,   130,    69,    78,   265,   266,   267,   269,   130,
+     130,    80,    81,   285,   286,   287,   288,    17,    45,    50,
+      51,    72,   149,   150,   151,   152,   153,   154,   155,   156,
+       7,     8,   159,   160,   161,   162,    10,    15,    17,    18,
+      21,    37,    39,    40,    45,    68,    74,   176,   177,   178,
+     179,   180,   181,   182,   183,   184,   185,   186,   187,   188,
+     189,    12,    13,    14,    16,    17,    64,    77,   165,   166,
+     167,   168,   169,   170,   171,   172,   173,   201,   132,   132,
+     132,   132,   132,   132,   131,   206,   132,   131,   191,   132,
+     132,   132,   132,   131,   196,   132,   132,   132,   131,   243,
+     132,   131,   144,    10,    14,    18,    19,    20,    21,    37,
+     217,   218,   219,   220,   221,   222,   223,   224,   225,    18,
+      20,    55,    56,    57,   228,   229,   230,   231,   232,   233,
+     234,    36,    58,    59,   237,   238,   239,   240,   241,   250,
+     131,   249,   132,   131,   255,   257,   132,   132,   131,   265,
+       3,   272,   273,    17,    18,    21,    76,   276,   277,   278,
+     279,   280,   281,   282,   283,   132,   132,   131,   286,   132,
+     132,   132,   132,    36,    45,   131,   149,   132,   132,   131,
+     160,   132,   132,   132,   132,   132,   132,   127,   132,   127,
+     132,   132,   132,   131,   176,   132,   132,   132,   132,   132,
+     132,   132,   131,   165,    42,    43,    70,    71,   204,     3,
+     204,    42,    43,    42,    43,   127,     3,   127,     3,     3,
+       3,     3,   127,    42,    43,   203,     3,     3,   127,     3,
+     127,   132,   132,   132,   132,   132,   132,   132,   131,   217,
+     132,   132,   132,   132,   132,   131,   228,   132,   132,   132,
+     131,   237,   132,   127,     3,   127,    17,    49,    63,    67,
+     258,   259,   260,   261,   262,   263,   268,   203,   127,   132,
+     131,   273,   132,   132,   133,   132,   132,   133,   131,   277,
+       3,     3,   127,     3,     3,     4,     3,   132,   132,   127,
+       3,     3,   127,     3,     4,   128,   142,     3,     3,     3,
+       4,     3,     3,    42,    43,    42,    43,   127,   137,   138,
+     139,   142,   137,   142,   141,   142,     3,     3,   142,   127,
+     127,   127,    71,    70,     4,   127,     3,   127,   127,   127,
+     127,   127,   127,   127,   127,   127,   127,   127,   127,   127,
+       3,   142,     3,     3,     3,     3,   142,   127,     3,     3,
+       3,     3,     3,   127,     3,     3,    42,    43,   127,     3,
+     251,   252,   127,   132,   132,   132,   127,   131,   258,   251,
+     127,     3,   127,     3,     3,   132,     3,     3,   132,   127,
+     127,   127,   127,   127,   127,   127,     3,   204,   127,   127,
+     127,   142,   123,   124,   125,   126,   127,   127,   127,   127,
+     127,   127,   127,   127,   127,   127,   127,   127,   139,   142,
+      23,    24,    25,    26,    27,    28,    29,    30,   140,   127,
+     127,   127,    31,    32,    33,    34,    35,   127,   127,   127,
+     127,     4,   127,   127,   127,   127,   127,   127,   127,   127,
+     127,   127,   127,   127,   127,   127,   127,   127,   127,   127,
+     252,     3,     3,     3,   127,   127,   127,   127,   127,     3,
+     127,   127,     3,   127,     3,   129,   142,   142,   142,   142,
+     127,   127,   127,   127,   127,   127,   127
+};
+
+#define yyerrok                (yyerrstatus = 0)
+#define yyclearin      (yychar = YYEMPTY)
+#define YYEMPTY                (-2)
+#define YYEOF          0
+
+#define YYACCEPT       goto yyacceptlab
+#define YYABORT                goto yyabortlab
+#define YYERROR                goto yyerrorlab
+
+
+/* Like YYERROR except do call yyerror.  This remains here temporarily
+   to ease the transition to the new meaning of YYERROR, for GCC.
+   Once GCC version 2 has supplanted version 1, this can go.  */
+
+#define YYFAIL         goto yyerrlab
+
+#define YYRECOVERING()  (!!yyerrstatus)
+
+#define YYBACKUP(Token, Value)                                 \
+do                                                             \
+  if (yychar == YYEMPTY && yylen == 1)                         \
+    {                                                          \
+      yychar = (Token);                                                \
+      yylval = (Value);                                                \
+      yytoken = YYTRANSLATE (yychar);                          \
+      YYPOPSTACK (1);                                          \
+      goto yybackup;                                           \
+    }                                                          \
+  else                                                         \
+    {                                                          \
+      yyerror (YY_("syntax error: cannot back up")); \
+      YYERROR;                                                 \
+    }                                                          \
+while (YYID (0))
+
+
+#define YYTERROR       1
+#define YYERRCODE      256
+
+
+/* YYLLOC_DEFAULT -- Set CURRENT to span from RHS[1] to RHS[N].
+   If N is 0, then set CURRENT to the empty location which ends
+   the previous symbol: RHS[0] (always defined).  */
+
+#define YYRHSLOC(Rhs, K) ((Rhs)[K])
+#ifndef YYLLOC_DEFAULT
+# define YYLLOC_DEFAULT(Current, Rhs, N)                               \
+    do                                                                 \
+      if (YYID (N))                                                    \
+       {                                                               \
+         (Current).first_line   = YYRHSLOC (Rhs, 1).first_line;        \
+         (Current).first_column = YYRHSLOC (Rhs, 1).first_column;      \
+         (Current).last_line    = YYRHSLOC (Rhs, N).last_line;         \
+         (Current).last_column  = YYRHSLOC (Rhs, N).last_column;       \
+       }                                                               \
+      else                                                             \
+       {                                                               \
+         (Current).first_line   = (Current).last_line   =              \
+           YYRHSLOC (Rhs, 0).last_line;                                \
+         (Current).first_column = (Current).last_column =              \
+           YYRHSLOC (Rhs, 0).last_column;                              \
+       }                                                               \
+    while (YYID (0))
+#endif
+
+
+/* YY_LOCATION_PRINT -- Print the location on the stream.
+   This macro was not mandated originally: define only if we know
+   we won't break user code: when these are the locations we know.  */
+
+#ifndef YY_LOCATION_PRINT
+# if YYLTYPE_IS_TRIVIAL
+#  define YY_LOCATION_PRINT(File, Loc)                 \
+     fprintf (File, "%d.%d-%d.%d",                     \
+             (Loc).first_line, (Loc).first_column,     \
+             (Loc).last_line,  (Loc).last_column)
+# else
+#  define YY_LOCATION_PRINT(File, Loc) ((void) 0)
+# endif
+#endif
+
+
+/* YYLEX -- calling `yylex' with the right arguments.  */
+
+#ifdef YYLEX_PARAM
+# define YYLEX yylex (YYLEX_PARAM)
+#else
+# define YYLEX yylex ()
+#endif
+
+/* Enable debugging if requested.  */
+#if YYDEBUG
+
+# ifndef YYFPRINTF
+#  include <stdio.h> /* INFRINGES ON USER NAME SPACE */
+#  define YYFPRINTF fprintf
+# endif
+
+# define YYDPRINTF(Args)                       \
+do {                                           \
+  if (yydebug)                                 \
+    YYFPRINTF Args;                            \
+} while (YYID (0))
+
+# define YY_SYMBOL_PRINT(Title, Type, Value, Location)                   \
+do {                                                                     \
+  if (yydebug)                                                           \
+    {                                                                    \
+      YYFPRINTF (stderr, "%s ", Title);                                          \
+      yy_symbol_print (stderr,                                           \
+                 Type, Value); \
+      YYFPRINTF (stderr, "\n");                                                  \
+    }                                                                    \
+} while (YYID (0))
+
+
+/*--------------------------------.
+| Print this symbol on YYOUTPUT.  |
+`--------------------------------*/
+
+/*ARGSUSED*/
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+static void
+yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep)
+#else
+static void
+yy_symbol_value_print (yyoutput, yytype, yyvaluep)
+    FILE *yyoutput;
+    int yytype;
+    YYSTYPE const * const yyvaluep;
+#endif
+{
+  if (!yyvaluep)
+    return;
+# ifdef YYPRINT
+  if (yytype < YYNTOKENS)
+    YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep);
+# else
+  YYUSE (yyoutput);
+# endif
+  switch (yytype)
+    {
+      default:
+       break;
+    }
+}
+
+
+/*--------------------------------.
+| Print this symbol on YYOUTPUT.  |
+`--------------------------------*/
+
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+static void
+yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep)
+#else
+static void
+yy_symbol_print (yyoutput, yytype, yyvaluep)
+    FILE *yyoutput;
+    int yytype;
+    YYSTYPE const * const yyvaluep;
+#endif
+{
+  if (yytype < YYNTOKENS)
+    YYFPRINTF (yyoutput, "token %s (", yytname[yytype]);
+  else
+    YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]);
+
+  yy_symbol_value_print (yyoutput, yytype, yyvaluep);
+  YYFPRINTF (yyoutput, ")");
+}
+
+/*------------------------------------------------------------------.
+| yy_stack_print -- Print the state stack from its BOTTOM up to its |
+| TOP (included).                                                   |
+`------------------------------------------------------------------*/
+
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+static void
+yy_stack_print (yytype_int16 *bottom, yytype_int16 *top)
+#else
+static void
+yy_stack_print (bottom, top)
+    yytype_int16 *bottom;
+    yytype_int16 *top;
+#endif
+{
+  YYFPRINTF (stderr, "Stack now");
+  for (; bottom <= top; ++bottom)
+    YYFPRINTF (stderr, " %d", *bottom);
+  YYFPRINTF (stderr, "\n");
+}
+
+# define YY_STACK_PRINT(Bottom, Top)                           \
+do {                                                           \
+  if (yydebug)                                                 \
+    yy_stack_print ((Bottom), (Top));                          \
+} while (YYID (0))
+
+
+/*------------------------------------------------.
+| Report that the YYRULE is going to be reduced.  |
+`------------------------------------------------*/
+
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+static void
+yy_reduce_print (YYSTYPE *yyvsp, int yyrule)
+#else
+static void
+yy_reduce_print (yyvsp, yyrule)
+    YYSTYPE *yyvsp;
+    int yyrule;
+#endif
+{
+  int yynrhs = yyr2[yyrule];
+  int yyi;
+  unsigned long int yylno = yyrline[yyrule];
+  YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu):\n",
+            yyrule - 1, yylno);
+  /* The symbols being reduced.  */
+  for (yyi = 0; yyi < yynrhs; yyi++)
+    {
+      fprintf (stderr, "   $%d = ", yyi + 1);
+      yy_symbol_print (stderr, yyrhs[yyprhs[yyrule] + yyi],
+                      &(yyvsp[(yyi + 1) - (yynrhs)])
+                                      );
+      fprintf (stderr, "\n");
+    }
+}
+
+# define YY_REDUCE_PRINT(Rule)         \
+do {                                   \
+  if (yydebug)                         \
+    yy_reduce_print (yyvsp, Rule); \
+} while (YYID (0))
+
+/* Nonzero means print parse trace.  It is left uninitialized so that
+   multiple parsers can coexist.  */
+int yydebug;
+#else /* !YYDEBUG */
+# define YYDPRINTF(Args)
+# define YY_SYMBOL_PRINT(Title, Type, Value, Location)
+# define YY_STACK_PRINT(Bottom, Top)
+# define YY_REDUCE_PRINT(Rule)
+#endif /* !YYDEBUG */
+
+
+/* YYINITDEPTH -- initial size of the parser's stacks.  */
+#ifndef        YYINITDEPTH
+# define YYINITDEPTH 200
+#endif
+
+/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only
+   if the built-in stack extension method is used).
+
+   Do not make this value too large; the results are undefined if
+   YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH)
+   evaluated with infinite-precision integer arithmetic.  */
+
+#ifndef YYMAXDEPTH
+# define YYMAXDEPTH 10000
+#endif
+
+\f
+
+#if YYERROR_VERBOSE
+
+# ifndef yystrlen
+#  if defined __GLIBC__ && defined _STRING_H
+#   define yystrlen strlen
+#  else
+/* Return the length of YYSTR.  */
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+static YYSIZE_T
+yystrlen (const char *yystr)
+#else
+static YYSIZE_T
+yystrlen (yystr)
+    const char *yystr;
+#endif
+{
+  YYSIZE_T yylen;
+  for (yylen = 0; yystr[yylen]; yylen++)
+    continue;
+  return yylen;
+}
+#  endif
+# endif
+
+# ifndef yystpcpy
+#  if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE
+#   define yystpcpy stpcpy
+#  else
+/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in
+   YYDEST.  */
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+static char *
+yystpcpy (char *yydest, const char *yysrc)
+#else
+static char *
+yystpcpy (yydest, yysrc)
+    char *yydest;
+    const char *yysrc;
+#endif
+{
+  char *yyd = yydest;
+  const char *yys = yysrc;
+
+  while ((*yyd++ = *yys++) != '\0')
+    continue;
+
+  return yyd - 1;
+}
+#  endif
+# endif
+
+# ifndef yytnamerr
+/* Copy to YYRES the contents of YYSTR after stripping away unnecessary
+   quotes and backslashes, so that it's suitable for yyerror.  The
+   heuristic is that double-quoting is unnecessary unless the string
+   contains an apostrophe, a comma, or backslash (other than
+   backslash-backslash).  YYSTR is taken from yytname.  If YYRES is
+   null, do not copy; instead, return the length of what the result
+   would have been.  */
+static YYSIZE_T
+yytnamerr (char *yyres, const char *yystr)
+{
+  if (*yystr == '"')
+    {
+      YYSIZE_T yyn = 0;
+      char const *yyp = yystr;
+
+      for (;;)
+       switch (*++yyp)
+         {
+         case '\'':
+         case ',':
+           goto do_not_strip_quotes;
+
+         case '\\':
+           if (*++yyp != '\\')
+             goto do_not_strip_quotes;
+           /* Fall through.  */
+         default:
+           if (yyres)
+             yyres[yyn] = *yyp;
+           yyn++;
+           break;
+
+         case '"':
+           if (yyres)
+             yyres[yyn] = '\0';
+           return yyn;
+         }
+    do_not_strip_quotes: ;
+    }
+
+  if (! yyres)
+    return yystrlen (yystr);
+
+  return yystpcpy (yyres, yystr) - yyres;
+}
+# endif
+
+/* Copy into YYRESULT an error message about the unexpected token
+   YYCHAR while in state YYSTATE.  Return the number of bytes copied,
+   including the terminating null byte.  If YYRESULT is null, do not
+   copy anything; just return the number of bytes that would be
+   copied.  As a special case, return 0 if an ordinary "syntax error"
+   message will do.  Return YYSIZE_MAXIMUM if overflow occurs during
+   size calculation.  */
+static YYSIZE_T
+yysyntax_error (char *yyresult, int yystate, int yychar)
+{
+  int yyn = yypact[yystate];
+
+  if (! (YYPACT_NINF < yyn && yyn <= YYLAST))
+    return 0;
+  else
+    {
+      int yytype = YYTRANSLATE (yychar);
+      YYSIZE_T yysize0 = yytnamerr (0, yytname[yytype]);
+      YYSIZE_T yysize = yysize0;
+      YYSIZE_T yysize1;
+      int yysize_overflow = 0;
+      enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 };
+      char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM];
+      int yyx;
+
+# if 0
+      /* This is so xgettext sees the translatable formats that are
+        constructed on the fly.  */
+      YY_("syntax error, unexpected %s");
+      YY_("syntax error, unexpected %s, expecting %s");
+      YY_("syntax error, unexpected %s, expecting %s or %s");
+      YY_("syntax error, unexpected %s, expecting %s or %s or %s");
+      YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s");
+# endif
+      char *yyfmt;
+      char const *yyf;
+      static char const yyunexpected[] = "syntax error, unexpected %s";
+      static char const yyexpecting[] = ", expecting %s";
+      static char const yyor[] = " or %s";
+      char yyformat[sizeof yyunexpected
+                   + sizeof yyexpecting - 1
+                   + ((YYERROR_VERBOSE_ARGS_MAXIMUM - 2)
+                      * (sizeof yyor - 1))];
+      char const *yyprefix = yyexpecting;
+
+      /* Start YYX at -YYN if negative to avoid negative indexes in
+        YYCHECK.  */
+      int yyxbegin = yyn < 0 ? -yyn : 0;
+
+      /* Stay within bounds of both yycheck and yytname.  */
+      int yychecklim = YYLAST - yyn + 1;
+      int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS;
+      int yycount = 1;
+
+      yyarg[0] = yytname[yytype];
+      yyfmt = yystpcpy (yyformat, yyunexpected);
+
+      for (yyx = yyxbegin; yyx < yyxend; ++yyx)
+       if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR)
+         {
+           if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM)
+             {
+               yycount = 1;
+               yysize = yysize0;
+               yyformat[sizeof yyunexpected - 1] = '\0';
+               break;
+             }
+           yyarg[yycount++] = yytname[yyx];
+           yysize1 = yysize + yytnamerr (0, yytname[yyx]);
+           yysize_overflow |= (yysize1 < yysize);
+           yysize = yysize1;
+           yyfmt = yystpcpy (yyfmt, yyprefix);
+           yyprefix = yyor;
+         }
+
+      yyf = YY_(yyformat);
+      yysize1 = yysize + yystrlen (yyf);
+      yysize_overflow |= (yysize1 < yysize);
+      yysize = yysize1;
+
+      if (yysize_overflow)
+       return YYSIZE_MAXIMUM;
+
+      if (yyresult)
+       {
+         /* Avoid sprintf, as that infringes on the user's name space.
+            Don't have undefined behavior even if the translation
+            produced a string with the wrong number of "%s"s.  */
+         char *yyp = yyresult;
+         int yyi = 0;
+         while ((*yyp = *yyf) != '\0')
+           {
+             if (*yyp == '%' && yyf[1] == 's' && yyi < yycount)
+               {
+                 yyp += yytnamerr (yyp, yyarg[yyi++]);
+                 yyf += 2;
+               }
+             else
+               {
+                 yyp++;
+                 yyf++;
+               }
+           }
+       }
+      return yysize;
+    }
+}
+#endif /* YYERROR_VERBOSE */
+\f
+
+/*-----------------------------------------------.
+| Release the memory associated to this symbol.  |
+`-----------------------------------------------*/
+
+/*ARGSUSED*/
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+static void
+yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep)
+#else
+static void
+yydestruct (yymsg, yytype, yyvaluep)
+    const char *yymsg;
+    int yytype;
+    YYSTYPE *yyvaluep;
+#endif
+{
+  YYUSE (yyvaluep);
+
+  if (!yymsg)
+    yymsg = "Deleting";
+  YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp);
+
+  switch (yytype)
+    {
+
+      default:
+       break;
+    }
+}
+\f
+
+/* Prevent warnings from -Wmissing-prototypes.  */
+
+#ifdef YYPARSE_PARAM
+#if defined __STDC__ || defined __cplusplus
+int yyparse (void *YYPARSE_PARAM);
+#else
+int yyparse ();
+#endif
+#else /* ! YYPARSE_PARAM */
+#if defined __STDC__ || defined __cplusplus
+int yyparse (void);
+#else
+int yyparse ();
+#endif
+#endif /* ! YYPARSE_PARAM */
+
+
+
+/* The look-ahead symbol.  */
+int yychar;
+
+/* The semantic value of the look-ahead symbol.  */
+YYSTYPE yylval;
+
+/* Number of syntax errors so far.  */
+int yynerrs;
+
+
+
+/*----------.
+| yyparse.  |
+`----------*/
+
+#ifdef YYPARSE_PARAM
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+int
+yyparse (void *YYPARSE_PARAM)
+#else
+int
+yyparse (YYPARSE_PARAM)
+    void *YYPARSE_PARAM;
+#endif
+#else /* ! YYPARSE_PARAM */
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+int
+yyparse (void)
+#else
+int
+yyparse ()
+
+#endif
+#endif
+{
+  
+  int yystate;
+  int yyn;
+  int yyresult;
+  /* Number of tokens to shift before error messages enabled.  */
+  int yyerrstatus;
+  /* Look-ahead token as an internal (translated) token number.  */
+  int yytoken = 0;
+#if YYERROR_VERBOSE
+  /* Buffer for error messages, and its allocated size.  */
+  char yymsgbuf[128];
+  char *yymsg = yymsgbuf;
+  YYSIZE_T yymsg_alloc = sizeof yymsgbuf;
+#endif
+
+  /* Three stacks and their tools:
+     `yyss': related to states,
+     `yyvs': related to semantic values,
+     `yyls': related to locations.
+
+     Refer to the stacks thru separate pointers, to allow yyoverflow
+     to reallocate them elsewhere.  */
+
+  /* The state stack.  */
+  yytype_int16 yyssa[YYINITDEPTH];
+  yytype_int16 *yyss = yyssa;
+  yytype_int16 *yyssp;
+
+  /* The semantic value stack.  */
+  YYSTYPE yyvsa[YYINITDEPTH];
+  YYSTYPE *yyvs = yyvsa;
+  YYSTYPE *yyvsp;
+
+
+
+#define YYPOPSTACK(N)   (yyvsp -= (N), yyssp -= (N))
+
+  YYSIZE_T yystacksize = YYINITDEPTH;
+
+  /* The variables used to return semantic value and location from the
+     action routines.  */
+  YYSTYPE yyval;
+
+
+  /* The number of symbols on the RHS of the reduced rule.
+     Keep to zero when no symbol should be popped.  */
+  int yylen = 0;
+
+  YYDPRINTF ((stderr, "Starting parse\n"));
+
+  yystate = 0;
+  yyerrstatus = 0;
+  yynerrs = 0;
+  yychar = YYEMPTY;            /* Cause a token to be read.  */
+
+  /* Initialize stack pointers.
+     Waste one element of value and location stack
+     so that they stay on the same level as the state stack.
+     The wasted elements are never initialized.  */
+
+  yyssp = yyss;
+  yyvsp = yyvs;
+
+  goto yysetstate;
+
+/*------------------------------------------------------------.
+| yynewstate -- Push a new state, which is found in yystate.  |
+`------------------------------------------------------------*/
+ yynewstate:
+  /* In all cases, when you get here, the value and location stacks
+     have just been pushed.  So pushing a state here evens the stacks.  */
+  yyssp++;
+
+ yysetstate:
+  *yyssp = yystate;
+
+  if (yyss + yystacksize - 1 <= yyssp)
+    {
+      /* Get the current used size of the three stacks, in elements.  */
+      YYSIZE_T yysize = yyssp - yyss + 1;
+
+#ifdef yyoverflow
+      {
+       /* Give user a chance to reallocate the stack.  Use copies of
+          these so that the &'s don't force the real ones into
+          memory.  */
+       YYSTYPE *yyvs1 = yyvs;
+       yytype_int16 *yyss1 = yyss;
+
+
+       /* Each stack pointer address is followed by the size of the
+          data in use in that stack, in bytes.  This used to be a
+          conditional around just the two extra args, but that might
+          be undefined if yyoverflow is a macro.  */
+       yyoverflow (YY_("memory exhausted"),
+                   &yyss1, yysize * sizeof (*yyssp),
+                   &yyvs1, yysize * sizeof (*yyvsp),
+
+                   &yystacksize);
+
+       yyss = yyss1;
+       yyvs = yyvs1;
+      }
+#else /* no yyoverflow */
+# ifndef YYSTACK_RELOCATE
+      goto yyexhaustedlab;
+# else
+      /* Extend the stack our own way.  */
+      if (YYMAXDEPTH <= yystacksize)
+       goto yyexhaustedlab;
+      yystacksize *= 2;
+      if (YYMAXDEPTH < yystacksize)
+       yystacksize = YYMAXDEPTH;
+
+      {
+       yytype_int16 *yyss1 = yyss;
+       union yyalloc *yyptr =
+         (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize));
+       if (! yyptr)
+         goto yyexhaustedlab;
+       YYSTACK_RELOCATE (yyss);
+       YYSTACK_RELOCATE (yyvs);
+
+#  undef YYSTACK_RELOCATE
+       if (yyss1 != yyssa)
+         YYSTACK_FREE (yyss1);
+      }
+# endif
+#endif /* no yyoverflow */
+
+      yyssp = yyss + yysize - 1;
+      yyvsp = yyvs + yysize - 1;
+
+
+      YYDPRINTF ((stderr, "Stack size increased to %lu\n",
+                 (unsigned long int) yystacksize));
+
+      if (yyss + yystacksize - 1 <= yyssp)
+       YYABORT;
+    }
+
+  YYDPRINTF ((stderr, "Entering state %d\n", yystate));
+
+  goto yybackup;
+
+/*-----------.
+| yybackup.  |
+`-----------*/
+yybackup:
+
+  /* Do appropriate processing given the current state.  Read a
+     look-ahead token if we need one and don't already have one.  */
+
+  /* First try to decide what to do without reference to look-ahead token.  */
+  yyn = yypact[yystate];
+  if (yyn == YYPACT_NINF)
+    goto yydefault;
+
+  /* Not known => get a look-ahead token if don't already have one.  */
+
+  /* YYCHAR is either YYEMPTY or YYEOF or a valid look-ahead symbol.  */
+  if (yychar == YYEMPTY)
+    {
+      YYDPRINTF ((stderr, "Reading a token: "));
+      yychar = YYLEX;
+    }
+
+  if (yychar <= YYEOF)
+    {
+      yychar = yytoken = YYEOF;
+      YYDPRINTF ((stderr, "Now at end of input.\n"));
+    }
+  else
+    {
+      yytoken = YYTRANSLATE (yychar);
+      YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc);
+    }
+
+  /* If the proper action on seeing token YYTOKEN is to reduce or to
+     detect an error, take that action.  */
+  yyn += yytoken;
+  if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken)
+    goto yydefault;
+  yyn = yytable[yyn];
+  if (yyn <= 0)
+    {
+      if (yyn == 0 || yyn == YYTABLE_NINF)
+       goto yyerrlab;
+      yyn = -yyn;
+      goto yyreduce;
+    }
+
+  if (yyn == YYFINAL)
+    YYACCEPT;
+
+  /* Count tokens shifted since error; after three, turn off error
+     status.  */
+  if (yyerrstatus)
+    yyerrstatus--;
+
+  /* Shift the look-ahead token.  */
+  YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc);
+
+  /* Discard the shifted token unless it is eof.  */
+  if (yychar != YYEOF)
+    yychar = YYEMPTY;
+
+  yystate = yyn;
+  *++yyvsp = yylval;
+
+  goto yynewstate;
+
+
+/*-----------------------------------------------------------.
+| yydefault -- do the default action for the current state.  |
+`-----------------------------------------------------------*/
+yydefault:
+  yyn = yydefact[yystate];
+  if (yyn == 0)
+    goto yyerrlab;
+  goto yyreduce;
+
+
+/*-----------------------------.
+| yyreduce -- Do a reduction.  |
+`-----------------------------*/
+yyreduce:
+  /* yyn is the number of a rule to reduce with.  */
+  yylen = yyr2[yyn];
+
+  /* If YYLEN is nonzero, implement the default value of the action:
+     `$$ = $1'.
+
+     Otherwise, the following line sets YYVAL to garbage.
+     This behavior is undocumented and Bison
+     users should not rely upon it.  Assigning to YYVAL
+     unconditionally makes the parser a bit smaller, and it avoids a
+     GCC warning that YYVAL may be used uninitialized.  */
+  yyval = yyvsp[1-yylen];
+
+
+  YY_REDUCE_PRINT (yyn);
+  switch (yyn)
+    {
+        case 26:
+#line 225 "./ircd_parser.y"
+    {
+  (yyval.num) = (yyvsp[(1) - (2)].num) + (yyvsp[(2) - (2)].num);
+}
+    break;
+
+  case 28:
+#line 230 "./ircd_parser.y"
+    {
+  (yyval.num) = (yyvsp[(1) - (2)].num) * (yyvsp[(2) - (2)].num);
+}
+    break;
+
+  case 29:
+#line 234 "./ircd_parser.y"
+    { (yyval.num) = 1; }
+    break;
+
+  case 30:
+#line 235 "./ircd_parser.y"
+    { (yyval.num) = 60; }
+    break;
+
+  case 31:
+#line 236 "./ircd_parser.y"
+    { (yyval.num) = 60 * 60; }
+    break;
+
+  case 32:
+#line 237 "./ircd_parser.y"
+    { (yyval.num) = 60 * 60 * 24; }
+    break;
+
+  case 33:
+#line 238 "./ircd_parser.y"
+    { (yyval.num) = 60 * 60 * 24 * 7; }
+    break;
+
+  case 34:
+#line 239 "./ircd_parser.y"
+    { (yyval.num) = 60 * 60 * 24 * 7 * 4; }
+    break;
+
+  case 35:
+#line 240 "./ircd_parser.y"
+    { (yyval.num) = 60 * 60 * 24 * 365; }
+    break;
+
+  case 36:
+#line 241 "./ircd_parser.y"
+    { (yyval.num) = 60 * 60 * 24 * 365 * 10; }
+    break;
+
+  case 37:
+#line 244 "./ircd_parser.y"
+    {
+                       (yyval.num) = (yyvsp[(1) - (1)].num);
+               }
+    break;
+
+  case 38:
+#line 247 "./ircd_parser.y"
+    { 
+                       (yyval.num) = (yyvsp[(1) - (2)].num);
+               }
+    break;
+
+  case 39:
+#line 250 "./ircd_parser.y"
+    {
+                       (yyval.num) = (yyvsp[(1) - (2)].num) * 1024;
+               }
+    break;
+
+  case 40:
+#line 253 "./ircd_parser.y"
+    {
+                       (yyval.num) = (yyvsp[(1) - (2)].num) * 1024 * 1024;
+               }
+    break;
+
+  case 41:
+#line 256 "./ircd_parser.y"
+    {
+                       (yyval.num) = (yyvsp[(1) - (2)].num) * 1024 * 1024 * 1024;
+               }
+    break;
+
+  case 42:
+#line 259 "./ircd_parser.y"
+    {
+                       (yyval.num) = (yyvsp[(1) - (2)].num) * 1024 * 1024 * 1024;
+               }
+    break;
+
+  case 43:
+#line 266 "./ircd_parser.y"
+    { 
+                       (yyval.num) = (yyvsp[(1) - (1)].num);
+               }
+    break;
+
+  case 44:
+#line 269 "./ircd_parser.y"
+    { 
+                       (yyval.num) = (yyvsp[(1) - (3)].num) + (yyvsp[(3) - (3)].num);
+               }
+    break;
+
+  case 45:
+#line 272 "./ircd_parser.y"
+    { 
+                       (yyval.num) = (yyvsp[(1) - (3)].num) - (yyvsp[(3) - (3)].num);
+               }
+    break;
+
+  case 46:
+#line 275 "./ircd_parser.y"
+    { 
+                       (yyval.num) = (yyvsp[(1) - (3)].num) * (yyvsp[(3) - (3)].num);
+               }
+    break;
+
+  case 47:
+#line 278 "./ircd_parser.y"
+    { 
+                       (yyval.num) = (yyvsp[(1) - (3)].num) / (yyvsp[(3) - (3)].num);
+               }
+    break;
+
+  case 48:
+#line 285 "./ircd_parser.y"
+    {
+                       (yyval.num) = (yyvsp[(2) - (3)].num);
+               }
+    break;
+
+  case 53:
+#line 294 "./ircd_parser.y"
+    {
+  addNickJupes((yyvsp[(3) - (4)].text));
+  MyFree((yyvsp[(3) - (4)].text));
+}
+    break;
+
+  case 54:
+#line 300 "./ircd_parser.y"
+    {
+    /* Zero out the vhost addresses, in case they were removed. */
+    memset(&VirtualHost_v4.addr, 0, sizeof(VirtualHost_v4.addr));
+    memset(&VirtualHost_v6.addr, 0, sizeof(VirtualHost_v6.addr));
+}
+    break;
+
+  case 55:
+#line 304 "./ircd_parser.y"
+    {
+  if (localConf.name == NULL)
+    parse_error("Your General block must contain a name.");
+  if (localConf.numeric == 0)
+    parse_error("Your General block must contain a numeric (between 1 and 4095).");
+}
+    break;
+
+  case 64:
+#line 315 "./ircd_parser.y"
+    {
+  if (localConf.numeric == 0)
+    localConf.numeric = (yyvsp[(3) - (4)].num);
+  else if (localConf.numeric != (yyvsp[(3) - (4)].num))
+    parse_error("Redefinition of server numeric %i (%i)", (yyvsp[(3) - (4)].num),
+               localConf.numeric);
+}
+    break;
+
+  case 65:
+#line 324 "./ircd_parser.y"
+    {
+  if (localConf.name == NULL)
+    localConf.name = (yyvsp[(3) - (4)].text);
+  else {
+    if (strcmp(localConf.name, (yyvsp[(3) - (4)].text)))
+      parse_error("Redefinition of server name %s (%s)", (yyvsp[(3) - (4)].text),
+                  localConf.name);
+    MyFree((yyvsp[(3) - (4)].text));
+  }
+}
+    break;
+
+  case 66:
+#line 336 "./ircd_parser.y"
+    {
+  MyFree(localConf.description);
+  localConf.description = (yyvsp[(3) - (4)].text);
+  ircd_strncpy(cli_info(&me), (yyvsp[(3) - (4)].text), REALLEN);
+}
+    break;
+
+  case 67:
+#line 343 "./ircd_parser.y"
+    {
+  struct irc_in_addr addr;
+  char *vhost = (yyvsp[(3) - (4)].text);
+
+  if (!strcmp(vhost, "*")) {
+    /* This traditionally meant bind to all interfaces and connect
+     * from the default. */
+  } else if (!ircd_aton(&addr, vhost))
+    parse_error("Invalid virtual host '%s'.", vhost);
+  else if (irc_in_addr_is_ipv4(&addr))
+    memcpy(&VirtualHost_v4.addr, &addr, sizeof(addr));
+  else
+    memcpy(&VirtualHost_v6.addr, &addr, sizeof(addr));
+  MyFree(vhost);
+}
+    break;
+
+  case 68:
+#line 360 "./ircd_parser.y"
+    {
+  struct irc_in_addr addr;
+  int families = (yyvsp[(4) - (6)].num);
+  char *vhost = (yyvsp[(5) - (6)].text);
+
+  if (!strcmp(vhost, "*")) {
+    /* Let the operating system assign the default. */
+  } else if (!ircd_aton(&addr, vhost))
+    parse_error("Invalid DNS virtual host '%s'.", vhost);
+  else
+  {
+    if ((families & USE_IPV4)
+        || (!families && irc_in_addr_is_ipv4(&addr)))
+      memcpy(&VirtualHost_dns_v4.addr, &addr, sizeof(addr));
+    if ((families & USE_IPV6)
+        || (!families && !irc_in_addr_is_ipv4(&addr)))
+      memcpy(&VirtualHost_dns_v6.addr, &addr, sizeof(addr));
+  }
+  MyFree(vhost);
+}
+    break;
+
+  case 69:
+#line 382 "./ircd_parser.y"
+    {
+  char *server = (yyvsp[(4) - (5)].text);
+
+  add_nameserver(server);
+  MyFree(server);
+}
+    break;
+
+  case 70:
+#line 390 "./ircd_parser.y"
+    {
+  MyFree(localConf.location1);
+  MyFree(localConf.location2);
+  MyFree(localConf.contact);
+  localConf.location1 = localConf.location2 = localConf.contact = NULL;
+}
+    break;
+
+  case 71:
+#line 397 "./ircd_parser.y"
+    {
+  if (localConf.location1 == NULL)
+    DupString(localConf.location1, "");
+  if (localConf.location2 == NULL)
+    DupString(localConf.location2, "");
+  if (localConf.contact == NULL)
+    DupString(localConf.contact, "");
+}
+    break;
+
+  case 76:
+#line 408 "./ircd_parser.y"
+    {
+  if (localConf.location1 == NULL)
+    localConf.location1 = (yyvsp[(3) - (4)].text);
+  else if (localConf.location2 == NULL)
+    localConf.location2 = (yyvsp[(3) - (4)].text);
+  else /* Otherwise just drop it. -A1kmm */
+    MyFree((yyvsp[(3) - (4)].text));
+}
+    break;
+
+  case 77:
+#line 417 "./ircd_parser.y"
+    {
+ MyFree(localConf.contact);
+ localConf.contact = (yyvsp[(3) - (4)].text);
+}
+    break;
+
+  case 78:
+#line 422 "./ircd_parser.y"
+    {
+  tping = 90;
+  maxchans = 0;
+}
+    break;
+
+  case 79:
+#line 426 "./ircd_parser.y"
+    {
+  if (name != NULL)
+  {
+    struct ConnectionClass *c_class;
+    add_class(name, tping, tconn, maxlinks, sendq, maxchans);
+    c_class = find_class(name);
+    MyFree(c_class->default_umode);
+    c_class->default_umode = pass;
+    memcpy(&c_class->privs, &privs, sizeof(c_class->privs));
+    memcpy(&c_class->privs_dirty, &privs_dirty, sizeof(c_class->privs_dirty));
+  }
+  else {
+   parse_error("Missing name in class block");
+  }
+  name = NULL;
+  pass = NULL;
+  tconn = 0;
+  maxlinks = 0;
+  sendq = 0;
+  memset(&privs, 0, sizeof(privs));
+  memset(&privs_dirty, 0, sizeof(privs_dirty));
+}
+    break;
+
+  case 90:
+#line 452 "./ircd_parser.y"
+    {
+  MyFree(name);
+  name = (yyvsp[(3) - (4)].text);
+}
+    break;
+
+  case 91:
+#line 457 "./ircd_parser.y"
+    {
+  maxchans = (yyvsp[(3) - (4)].num);
+}
+    break;
+
+  case 92:
+#line 461 "./ircd_parser.y"
+    {
+  tping = (yyvsp[(3) - (4)].num);
+}
+    break;
+
+  case 93:
+#line 465 "./ircd_parser.y"
+    {
+  tconn = (yyvsp[(3) - (4)].num);
+}
+    break;
+
+  case 94:
+#line 469 "./ircd_parser.y"
+    {
+  maxlinks = (yyvsp[(3) - (4)].num);
+}
+    break;
+
+  case 95:
+#line 473 "./ircd_parser.y"
+    {
+  sendq = (yyvsp[(3) - (4)].num);
+}
+    break;
+
+  case 96:
+#line 477 "./ircd_parser.y"
+    {
+  MyFree(pass);
+  pass = (yyvsp[(3) - (4)].text);
+}
+    break;
+
+  case 97:
+#line 483 "./ircd_parser.y"
+    {
+ flags = CONF_AUTOCONNECT;
+}
+    break;
+
+  case 98:
+#line 486 "./ircd_parser.y"
+    {
+ struct ConfItem *aconf = NULL;
+ if (name == NULL)
+  parse_error("Missing name in connect block");
+ else if (pass == NULL)
+  parse_error("Missing password in connect block");
+ else if (strlen(pass) > PASSWDLEN)
+  parse_error("Password too long in connect block");
+ else if (host == NULL)
+  parse_error("Missing host in connect block");
+ else if (strchr(host, '*') || strchr(host, '?'))
+  parse_error("Invalid host '%s' in connect block", host);
+ else if (c_class == NULL)
+  parse_error("Missing or non-existent class in connect block");
+ else {
+   aconf = make_conf(CONF_SERVER);
+   aconf->name = name;
+   aconf->origin_name = origin;
+   aconf->passwd = pass;
+   aconf->conn_class = c_class;
+   aconf->address.port = port;
+   aconf->host = host;
+   /* If the user specified a hub allowance, but not maximum links,
+    * allow an effectively unlimited number of hops.
+    */
+   aconf->maximum = (hub_limit != NULL && maxlinks == 0) ? 65535 : maxlinks;
+   aconf->hub_limit = hub_limit;
+   aconf->flags = flags;
+   lookup_confhost(aconf);
+ }
+ if (!aconf) {
+   MyFree(name);
+   MyFree(pass);
+   MyFree(host);
+   MyFree(origin);
+   MyFree(hub_limit);
+ }
+ name = pass = host = origin = hub_limit = NULL;
+ c_class = NULL;
+ port = flags = maxlinks = 0;
+}
+    break;
+
+  case 113:
+#line 532 "./ircd_parser.y"
+    {
+ MyFree(name);
+ name = (yyvsp[(3) - (4)].text);
+}
+    break;
+
+  case 114:
+#line 537 "./ircd_parser.y"
+    {
+ MyFree(pass);
+ pass = (yyvsp[(3) - (4)].text);
+}
+    break;
+
+  case 115:
+#line 542 "./ircd_parser.y"
+    {
+ c_class = find_class((yyvsp[(3) - (4)].text));
+ if (!c_class)
+  parse_error("No such connection class '%s' for Connect block", (yyvsp[(3) - (4)].text));
+ MyFree((yyvsp[(3) - (4)].text));
+}
+    break;
+
+  case 116:
+#line 549 "./ircd_parser.y"
+    {
+ MyFree(host);
+ host = (yyvsp[(3) - (4)].text);
+}
+    break;
+
+  case 117:
+#line 554 "./ircd_parser.y"
+    {
+ port = (yyvsp[(3) - (4)].num);
+}
+    break;
+
+  case 118:
+#line 558 "./ircd_parser.y"
+    {
+ MyFree(origin);
+ origin = (yyvsp[(3) - (4)].text);
+}
+    break;
+
+  case 119:
+#line 563 "./ircd_parser.y"
+    {
+ maxlinks = 0;
+}
+    break;
+
+  case 120:
+#line 567 "./ircd_parser.y"
+    {
+ MyFree(hub_limit);
+ DupString(hub_limit, "*");
+}
+    break;
+
+  case 121:
+#line 572 "./ircd_parser.y"
+    {
+ MyFree(hub_limit);
+ hub_limit = (yyvsp[(3) - (4)].text);
+}
+    break;
+
+  case 122:
+#line 577 "./ircd_parser.y"
+    {
+  maxlinks = (yyvsp[(3) - (4)].num);
+}
+    break;
+
+  case 123:
+#line 580 "./ircd_parser.y"
+    { flags |= CONF_AUTOCONNECT; }
+    break;
+
+  case 124:
+#line 581 "./ircd_parser.y"
+    { flags &= ~CONF_AUTOCONNECT; }
+    break;
+
+  case 125:
+#line 582 "./ircd_parser.y"
+    { flags |= CONF_SECURE; }
+    break;
+
+  case 126:
+#line 583 "./ircd_parser.y"
+    { flags &= ~CONF_SECURE; }
+    break;
+
+  case 131:
+#line 589 "./ircd_parser.y"
+    {
+  make_conf(CONF_UWORLD)->host = (yyvsp[(3) - (4)].text);
+}
+    break;
+
+  case 132:
+#line 594 "./ircd_parser.y"
+    {
+  struct ConfItem *aconf = NULL;
+  struct SLink *link;
+
+  if (name == NULL)
+    parse_error("Missing name in operator block");
+  else if (pass == NULL)
+    parse_error("Missing password in operator block");
+  /* Do not check password length because it may be crypted. */
+  else if (hosts == NULL)
+    parse_error("Missing host(s) in operator block");
+  else if (c_class == NULL)
+    parse_error("Invalid or missing class in operator block");
+  else if (!FlagHas(&privs_dirty, PRIV_PROPAGATE)
+           && !FlagHas(&c_class->privs_dirty, PRIV_PROPAGATE))
+    parse_error("Operator block for %s and class %s have no LOCAL setting", name, c_class->cc_name);
+  else for (link = hosts; link != NULL; link = link->next) {
+    aconf = make_conf(CONF_OPERATOR);
+    DupString(aconf->name, name);
+    DupString(aconf->passwd, pass);
+    conf_parse_userhost(aconf, link->value.cp);
+    aconf->conn_class = c_class;
+    memcpy(&aconf->privs, &privs, sizeof(aconf->privs));
+    memcpy(&aconf->privs_dirty, &privs_dirty, sizeof(aconf->privs_dirty));
+  }
+  MyFree(name);
+  MyFree(pass);
+  free_slist(&hosts);
+  name = pass = NULL;
+  c_class = NULL;
+  memset(&privs, 0, sizeof(privs));
+  memset(&privs_dirty, 0, sizeof(privs_dirty));
+}
+    break;
+
+  case 140:
+#line 630 "./ircd_parser.y"
+    {
+  MyFree(name);
+  name = (yyvsp[(3) - (4)].text);
+}
+    break;
+
+  case 141:
+#line 635 "./ircd_parser.y"
+    {
+  MyFree(pass);
+  pass = (yyvsp[(3) - (4)].text);
+}
+    break;
+
+  case 142:
+#line 640 "./ircd_parser.y"
+    {
+ struct SLink *link;
+ link = make_link();
+ if (!strchr((yyvsp[(3) - (4)].text), '@'))
+ {
+   int uh_len;
+   link->value.cp = (char*) MyMalloc((uh_len = strlen((yyvsp[(3) - (4)].text))+3));
+   ircd_snprintf(0, link->value.cp, uh_len, "*@%s", (yyvsp[(3) - (4)].text));
+ }
+ else
+   DupString(link->value.cp, (yyvsp[(3) - (4)].text));
+ MyFree((yyvsp[(3) - (4)].text));
+ link->next = hosts;
+ hosts = link;
+}
+    break;
+
+  case 143:
+#line 656 "./ircd_parser.y"
+    {
+ c_class = find_class((yyvsp[(3) - (4)].text));
+ if (!c_class)
+  parse_error("No such connection class '%s' for Operator block", (yyvsp[(3) - (4)].text));
+ MyFree((yyvsp[(3) - (4)].text));
+}
+    break;
+
+  case 144:
+#line 664 "./ircd_parser.y"
+    {
+  FlagSet(&privs_dirty, (yyvsp[(1) - (4)].num));
+  if (((yyvsp[(3) - (4)].num) == 1) ^ invert)
+    FlagSet(&privs, (yyvsp[(1) - (4)].num));
+  else
+    FlagClr(&privs, (yyvsp[(1) - (4)].num));
+  invert = 0;
+}
+    break;
+
+  case 145:
+#line 673 "./ircd_parser.y"
+    { (yyval.num) = PRIV_CHAN_LIMIT; }
+    break;
+
+  case 146:
+#line 674 "./ircd_parser.y"
+    { (yyval.num) = PRIV_MODE_LCHAN; }
+    break;
+
+  case 147:
+#line 675 "./ircd_parser.y"
+    { (yyval.num) = PRIV_DEOP_LCHAN; }
+    break;
+
+  case 148:
+#line 676 "./ircd_parser.y"
+    { (yyval.num) = PRIV_WALK_LCHAN; }
+    break;
+
+  case 149:
+#line 677 "./ircd_parser.y"
+    { (yyval.num) = PRIV_SEE_IDLETIME; }
+    break;
+
+  case 150:
+#line 678 "./ircd_parser.y"
+    { (yyval.num) = PRIV_HIDE_IDLETIME; }
+    break;
+
+  case 151:
+#line 679 "./ircd_parser.y"
+    { (yyval.num) = PRIV_UMODE_NOCHAN; }
+    break;
+
+  case 152:
+#line 680 "./ircd_parser.y"
+    { (yyval.num) = PRIV_UMODE_NOIDLE; }
+    break;
+
+  case 153:
+#line 681 "./ircd_parser.y"
+    { (yyval.num) = PRIV_UMODE_CHSERV; }
+    break;
+
+  case 154:
+#line 682 "./ircd_parser.y"
+    { (yyval.num) = PRIV_UMODE_XTRAOP; }
+    break;
+
+  case 155:
+#line 683 "./ircd_parser.y"
+    { (yyval.num) = PRIV_UMODE_NETSERV; }
+    break;
+
+  case 156:
+#line 684 "./ircd_parser.y"
+    { (yyval.num) = PRIV_FLOOD; }
+    break;
+
+  case 157:
+#line 685 "./ircd_parser.y"
+    { (yyval.num) = PRIV_HALFFLOOD; }
+    break;
+
+  case 158:
+#line 686 "./ircd_parser.y"
+    { (yyval.num) = PRIV_UNLIMITED_TARGET; }
+    break;
+
+  case 159:
+#line 687 "./ircd_parser.y"
+    { (yyval.num) = PRIV_UMODE_OVERRIDECC; }
+    break;
+
+  case 160:
+#line 688 "./ircd_parser.y"
+    { (yyval.num) = PRIV_KILL; }
+    break;
+
+  case 161:
+#line 689 "./ircd_parser.y"
+    { (yyval.num) = PRIV_LOCAL_KILL; }
+    break;
+
+  case 162:
+#line 690 "./ircd_parser.y"
+    { (yyval.num) = PRIV_REHASH; }
+    break;
+
+  case 163:
+#line 691 "./ircd_parser.y"
+    { (yyval.num) = PRIV_RESTART; }
+    break;
+
+  case 164:
+#line 692 "./ircd_parser.y"
+    { (yyval.num) = PRIV_DIE; }
+    break;
+
+  case 165:
+#line 693 "./ircd_parser.y"
+    { (yyval.num) = PRIV_GLINE; }
+    break;
+
+  case 166:
+#line 694 "./ircd_parser.y"
+    { (yyval.num) = PRIV_LOCAL_GLINE; }
+    break;
+
+  case 167:
+#line 695 "./ircd_parser.y"
+    { (yyval.num) = PRIV_JUPE; }
+    break;
+
+  case 168:
+#line 696 "./ircd_parser.y"
+    { (yyval.num) = PRIV_LOCAL_JUPE; }
+    break;
+
+  case 169:
+#line 697 "./ircd_parser.y"
+    { (yyval.num) = PRIV_LOCAL_OPMODE; }
+    break;
+
+  case 170:
+#line 698 "./ircd_parser.y"
+    { (yyval.num) = PRIV_OPMODE; }
+    break;
+
+  case 171:
+#line 699 "./ircd_parser.y"
+    { (yyval.num) = PRIV_SET; }
+    break;
+
+  case 172:
+#line 700 "./ircd_parser.y"
+    { (yyval.num) = PRIV_WHOX; }
+    break;
+
+  case 173:
+#line 701 "./ircd_parser.y"
+    { (yyval.num) = PRIV_BADCHAN; }
+    break;
+
+  case 174:
+#line 702 "./ircd_parser.y"
+    { (yyval.num) = PRIV_LOCAL_BADCHAN; }
+    break;
+
+  case 175:
+#line 703 "./ircd_parser.y"
+    { (yyval.num) = PRIV_SEE_CHAN; }
+    break;
+
+  case 176:
+#line 704 "./ircd_parser.y"
+    { (yyval.num) = PRIV_SHOW_INVIS; }
+    break;
+
+  case 177:
+#line 705 "./ircd_parser.y"
+    { (yyval.num) = PRIV_SHOW_ALL_INVIS; }
+    break;
+
+  case 178:
+#line 706 "./ircd_parser.y"
+    { (yyval.num) = PRIV_PROPAGATE; }
+    break;
+
+  case 179:
+#line 707 "./ircd_parser.y"
+    { (yyval.num) = PRIV_UNLIMIT_QUERY; }
+    break;
+
+  case 180:
+#line 708 "./ircd_parser.y"
+    { (yyval.num) = PRIV_DISPLAY; }
+    break;
+
+  case 181:
+#line 709 "./ircd_parser.y"
+    { (yyval.num) = PRIV_SEE_OPERS; }
+    break;
+
+  case 182:
+#line 710 "./ircd_parser.y"
+    { (yyval.num) = PRIV_WIDE_GLINE; }
+    break;
+
+  case 183:
+#line 711 "./ircd_parser.y"
+    { (yyval.num) = PRIV_LIST_CHAN; }
+    break;
+
+  case 184:
+#line 712 "./ircd_parser.y"
+    { (yyval.num) = PRIV_PROPAGATE; invert = 1; }
+    break;
+
+  case 185:
+#line 713 "./ircd_parser.y"
+    { (yyval.num) = PRIV_FORCE_OPMODE; }
+    break;
+
+  case 186:
+#line 714 "./ircd_parser.y"
+    { (yyval.num) = PRIV_FORCE_LOCAL_OPMODE; }
+    break;
+
+  case 187:
+#line 715 "./ircd_parser.y"
+    { (yyval.num) = PRIV_NOAMSG_OVERRIDE; }
+    break;
+
+  case 188:
+#line 716 "./ircd_parser.y"
+    { (yyval.num) = PRIV_APASS_OPMODE; }
+    break;
+
+  case 189:
+#line 718 "./ircd_parser.y"
+    { (yyval.num) = 1; }
+    break;
+
+  case 190:
+#line 718 "./ircd_parser.y"
+    { (yyval.num) = 0; }
+    break;
+
+  case 191:
+#line 724 "./ircd_parser.y"
+    { (yyval.num) = 0; }
+    break;
+
+  case 192:
+#line 725 "./ircd_parser.y"
+    { (yyval.num) = USE_IPV4; }
+    break;
+
+  case 193:
+#line 726 "./ircd_parser.y"
+    { (yyval.num) = USE_IPV6; }
+    break;
+
+  case 194:
+#line 727 "./ircd_parser.y"
+    { (yyval.num) = USE_IPV4 | USE_IPV6; }
+    break;
+
+  case 195:
+#line 728 "./ircd_parser.y"
+    { (yyval.num) = USE_IPV6 | USE_IPV4; }
+    break;
+
+  case 196:
+#line 732 "./ircd_parser.y"
+    {
+  struct ListenerFlags flags_here;
+  struct SLink *link;
+  if (hosts == NULL) {
+    struct SLink *link;
+    link = make_link();
+    DupString(link->value.cp, "*");
+    link->flags = 0;
+    link->next = hosts;
+    hosts = link;
+  }
+  for (link = hosts; link != NULL; link = link->next) {
+    memcpy(&flags_here, &listen_flags, sizeof(&flags_here));
+    switch (link->flags & (USE_IPV4 | USE_IPV6)) {
+    case USE_IPV4:
+      FlagSet(&flags_here, LISTEN_IPV4);
+      break;
+    case USE_IPV6:
+      FlagSet(&flags_here, LISTEN_IPV6);
+      break;
+    default: /* 0 or USE_IPV4|USE_IPV6 */
+      FlagSet(&flags_here, LISTEN_IPV4);
+      FlagSet(&flags_here, LISTEN_IPV6);
+      break;
+    }
+    if (link->flags & 65535)
+      port = link->flags & 65535;
+    add_listener(port, link->value.cp, pass, &flags_here);
+  }
+  free_slist(&hosts);
+  MyFree(pass);
+  memset(&listen_flags, 0, sizeof(listen_flags));
+  pass = NULL;
+  port = 0;
+}
+    break;
+
+  case 206:
+#line 770 "./ircd_parser.y"
+    {
+  if ((yyvsp[(4) - (5)].num) < 1 || (yyvsp[(4) - (5)].num) > 65535) {
+    parse_error("Port %d is out of range", port);
+  } else {
+    port = (yyvsp[(3) - (5)].num) | (yyvsp[(4) - (5)].num);
+    if (hosts && (0 == (hosts->flags & 65535)))
+      hosts->flags = (hosts->flags & ~65535) | port;
+  }
+}
+    break;
+
+  case 207:
+#line 781 "./ircd_parser.y"
+    {
+  struct SLink *link;
+  link = make_link();
+  link->value.cp = (yyvsp[(4) - (5)].text);
+  link->flags = (yyvsp[(3) - (5)].num) | port;
+  link->next = hosts;
+  hosts = link;
+}
+    break;
+
+  case 208:
+#line 791 "./ircd_parser.y"
+    {
+  if ((yyvsp[(5) - (6)].num) < 1 || (yyvsp[(5) - (6)].num) > 65535) {
+    parse_error("Port %d is out of range", port);
+  } else {
+    struct SLink *link;
+    link = make_link();
+    link->value.cp = (yyvsp[(4) - (6)].text);
+    link->flags = (yyvsp[(3) - (6)].num) | (yyvsp[(5) - (6)].num);
+    link->next = hosts;
+    hosts = link;
+  }
+}
+    break;
+
+  case 209:
+#line 805 "./ircd_parser.y"
+    {
+  MyFree(pass);
+  pass = (yyvsp[(3) - (4)].text);
+}
+    break;
+
+  case 210:
+#line 811 "./ircd_parser.y"
+    {
+  FlagSet(&listen_flags, LISTEN_SERVER);
+}
+    break;
+
+  case 211:
+#line 814 "./ircd_parser.y"
+    {
+  FlagClr(&listen_flags, LISTEN_SERVER);
+}
+    break;
+
+  case 212:
+#line 819 "./ircd_parser.y"
+    {
+  FlagSet(&listen_flags, LISTEN_HIDDEN);
+}
+    break;
+
+  case 213:
+#line 822 "./ircd_parser.y"
+    {
+  FlagClr(&listen_flags, LISTEN_HIDDEN);
+}
+    break;
+
+  case 214:
+#line 827 "./ircd_parser.y"
+    {
+  FlagSet(&listen_flags, LISTEN_SSL);
+}
+    break;
+
+  case 215:
+#line 830 "./ircd_parser.y"
+    {
+  FlagClr(&listen_flags, LISTEN_SSL);
+}
+    break;
+
+  case 216:
+#line 835 "./ircd_parser.y"
+    {
+  maxlinks = 65535;
+  port = 0;
+}
+    break;
+
+  case 217:
+#line 840 "./ircd_parser.y"
+    {
+  struct ConfItem *aconf = 0;
+  struct irc_in_addr addr;
+  unsigned char addrbits = 0;
+
+  if (!c_class)
+    parse_error("Invalid or missing class in Client block");
+  else if (pass && strlen(pass) > PASSWDLEN)
+    parse_error("Password too long in connect block");
+  else if (ip && !ipmask_parse(ip, &addr, &addrbits))
+    parse_error("Invalid IP address %s in Client block", ip);
+  else {
+    aconf = make_conf(CONF_CLIENT);
+    aconf->username = username;
+    aconf->host = host;
+    if (ip)
+      memcpy(&aconf->address.addr, &addr, sizeof(aconf->address.addr));
+    else
+      memset(&aconf->address.addr, 0, sizeof(aconf->address.addr));
+    aconf->address.port = port;
+    aconf->addrbits = addrbits;
+    aconf->name = ip;
+    aconf->conn_class = c_class;
+    aconf->maximum = maxlinks;
+    aconf->passwd = pass;
+  }
+  if (!aconf) {
+    MyFree(username);
+    MyFree(host);
+    MyFree(ip);
+    MyFree(pass);
+  }
+  host = NULL;
+  username = NULL;
+  c_class = NULL;
+  maxlinks = 0;
+  ip = NULL;
+  pass = NULL;
+  port = 0;
+}
+    break;
+
+  case 227:
+#line 883 "./ircd_parser.y"
+    {
+  char *sep = strchr((yyvsp[(3) - (4)].text), '@');
+  MyFree(host);
+  if (sep) {
+    *sep++ = '\0';
+    MyFree(username);
+    DupString(host, sep);
+    username = (yyvsp[(3) - (4)].text);
+  } else {
+    host = (yyvsp[(3) - (4)].text);
+  }
+}
+    break;
+
+  case 228:
+#line 896 "./ircd_parser.y"
+    {
+  char *sep;
+  sep = strchr((yyvsp[(3) - (4)].text), '@');
+  MyFree(ip);
+  if (sep) {
+    *sep++ = '\0';
+    MyFree(username);
+    DupString(ip, sep);
+    username = (yyvsp[(3) - (4)].text);
+  } else {
+    ip = (yyvsp[(3) - (4)].text);
+  }
+}
+    break;
+
+  case 229:
+#line 910 "./ircd_parser.y"
+    {
+  MyFree(username);
+  username = (yyvsp[(3) - (4)].text);
+}
+    break;
+
+  case 230:
+#line 915 "./ircd_parser.y"
+    {
+  c_class = find_class((yyvsp[(3) - (4)].text));
+  if (!c_class)
+    parse_error("No such connection class '%s' for Client block", (yyvsp[(3) - (4)].text));
+  MyFree((yyvsp[(3) - (4)].text));
+}
+    break;
+
+  case 231:
+#line 922 "./ircd_parser.y"
+    {
+  MyFree(pass);
+  pass = (yyvsp[(3) - (4)].text);
+}
+    break;
+
+  case 232:
+#line 927 "./ircd_parser.y"
+    {
+  maxlinks = (yyvsp[(3) - (4)].num);
+}
+    break;
+
+  case 233:
+#line 931 "./ircd_parser.y"
+    {
+  port = (yyvsp[(3) - (4)].num);
+}
+    break;
+
+  case 234:
+#line 936 "./ircd_parser.y"
+    {
+  dconf = (struct DenyConf*) MyCalloc(1, sizeof(*dconf));
+}
+    break;
+
+  case 235:
+#line 939 "./ircd_parser.y"
+    {
+  if (dconf->usermask || dconf->hostmask ||dconf->realmask) {
+    dconf->next = denyConfList;
+    denyConfList = dconf;
+  }
+  else
+  {
+    MyFree(dconf->usermask);
+    MyFree(dconf->hostmask);
+    MyFree(dconf->realmask);
+    MyFree(dconf->message);
+    MyFree(dconf);
+    parse_error("Kill block must match on at least one of username, host or realname");
+  }
+  dconf = NULL;
+}
+    break;
+
+  case 243:
+#line 958 "./ircd_parser.y"
+    {
+  char *h;
+  MyFree(dconf->hostmask);
+  MyFree(dconf->usermask);
+  if ((h = strchr((yyvsp[(3) - (4)].text), '@')) == NULL)
+  {
+    DupString(dconf->usermask, "*");
+    dconf->hostmask = (yyvsp[(3) - (4)].text);
+  }
+  else
+  {
+    *h++ = '\0';
+    DupString(dconf->hostmask, h);
+    dconf->usermask = (yyvsp[(3) - (4)].text);
+  }
+  ipmask_parse(dconf->hostmask, &dconf->address, &dconf->bits);
+}
+    break;
+
+  case 244:
+#line 977 "./ircd_parser.y"
+    {
+  MyFree(dconf->usermask);
+  dconf->usermask = (yyvsp[(3) - (4)].text);
+}
+    break;
+
+  case 245:
+#line 983 "./ircd_parser.y"
+    {
+ MyFree(dconf->realmask);
+ dconf->realmask = (yyvsp[(3) - (4)].text);
+}
+    break;
+
+  case 246:
+#line 989 "./ircd_parser.y"
+    {
+ dconf->flags &= ~DENY_FLAGS_FILE;
+ MyFree(dconf->message);
+ dconf->message = (yyvsp[(3) - (4)].text);
+}
+    break;
+
+  case 247:
+#line 996 "./ircd_parser.y"
+    {
+ dconf->flags |= DENY_FLAGS_FILE;
+ MyFree(dconf->message);
+ dconf->message = (yyvsp[(3) - (4)].text);
+}
+    break;
+
+  case 248:
+#line 1003 "./ircd_parser.y"
+    {
+  tconn = CRULE_AUTO;
+}
+    break;
+
+  case 249:
+#line 1006 "./ircd_parser.y"
+    {
+  struct CRuleNode *node = NULL;
+  struct SLink *link;
+
+  if (hosts == NULL)
+    parse_error("Missing server(s) in crule block");
+  else if (pass == NULL)
+    parse_error("Missing rule in crule block");
+  else if ((node = crule_parse(pass)) == NULL)
+    parse_error("Invalid rule '%s' in crule block", pass);
+  else for (link = hosts; link != NULL; link = link->next)
+  {
+    struct CRuleConf *p = (struct CRuleConf*) MyMalloc(sizeof(*p));
+    if (node == NULL)
+      node = crule_parse(pass);
+    DupString(p->hostmask, link->value.cp);
+    DupString(p->rule, pass);
+    p->type = tconn;
+    p->node = node;
+    node = NULL;
+    p->next = cruleConfList;
+    cruleConfList = p;
+  }
+  free_slist(&hosts);
+  MyFree(pass);
+  pass = NULL;
+  tconn = 0;
+}
+    break;
+
+  case 255:
+#line 1039 "./ircd_parser.y"
+    {
+  struct SLink *link;
+  link = make_link();
+  link->value.cp = (yyvsp[(3) - (4)].text);
+  link->next = hosts;
+  hosts = link;
+}
+    break;
+
+  case 256:
+#line 1048 "./ircd_parser.y"
+    {
+ MyFree(pass);
+ pass = (yyvsp[(3) - (4)].text);
+}
+    break;
+
+  case 257:
+#line 1054 "./ircd_parser.y"
+    {
+ tconn = CRULE_ALL;
+}
+    break;
+
+  case 258:
+#line 1057 "./ircd_parser.y"
+    {
+ tconn = CRULE_AUTO;
+}
+    break;
+
+  case 259:
+#line 1062 "./ircd_parser.y"
+    {
+  struct SLink *link;
+  if (pass != NULL)
+    for (link = hosts; link != NULL; link = link->next)
+      motd_add(link->value.cp, pass);
+  free_slist(&hosts);
+  MyFree(pass);
+  pass = NULL;
+}
+    break;
+
+  case 264:
+#line 1075 "./ircd_parser.y"
+    {
+  struct SLink *link;
+  link = make_link();
+  link->value.cp = (yyvsp[(3) - (4)].text);
+  link->next = hosts;
+  hosts = link;
+}
+    break;
+
+  case 265:
+#line 1084 "./ircd_parser.y"
+    {
+  MyFree(pass);
+  pass = (yyvsp[(3) - (4)].text);
+}
+    break;
+
+  case 269:
+#line 1093 "./ircd_parser.y"
+    {
+  stringlist[0] = (yyvsp[(1) - (1)].text);
+  stringno = 1;
+}
+    break;
+
+  case 270:
+#line 1096 "./ircd_parser.y"
+    {
+  unsigned int ii;
+  feature_set(NULL, (const char * const *)stringlist, stringno);
+  for (ii = 0; ii < stringno; ++ii)
+    MyFree(stringlist[ii]);
+}
+    break;
+
+  case 273:
+#line 1105 "./ircd_parser.y"
+    {
+  if (stringno < MAX_STRINGS)
+    stringlist[stringno++] = (yyvsp[(1) - (1)].text);
+  else
+    MyFree((yyvsp[(1) - (1)].text));
+}
+    break;
+
+  case 277:
+#line 1115 "./ircd_parser.y"
+    {
+  struct qline *qconf = MyCalloc(1, sizeof(*qconf));
+  qconf->chname = (yyvsp[(1) - (4)].text);
+  qconf->reason = (yyvsp[(3) - (4)].text);
+  qconf->next = GlobalQuarantineList;
+  GlobalQuarantineList = qconf;
+}
+    break;
+
+  case 278:
+#line 1124 "./ircd_parser.y"
+    {
+  smap = MyCalloc(1, sizeof(struct s_map));
+  smap->command = (yyvsp[(2) - (3)].text);
+}
+    break;
+
+  case 279:
+#line 1129 "./ircd_parser.y"
+    {
+  int valid = 0;
+
+  if (!smap->name)
+    parse_error("Missing name in pseudo %s block", smap->command);
+  else if (!smap->services)
+    parse_error("Missing nick in pseudo %s block", smap->command);
+  else if (!strIsAlpha(smap->command))
+    parse_error("Pseudo command %s invalid: must all be letters", smap->command);
+  else
+    valid = 1;
+  if (valid && register_mapping(smap))
+  {
+    smap->next = GlobalServiceMapList;
+    GlobalServiceMapList = smap;
+  }
+  else
+  {
+    free_mapping(smap);
+  }
+  smap = NULL;
+}
+    break;
+
+  case 286:
+#line 1155 "./ircd_parser.y"
+    {
+  MyFree(smap->name);
+  smap->name = (yyvsp[(3) - (4)].text);
+}
+    break;
+
+  case 287:
+#line 1160 "./ircd_parser.y"
+    {
+  MyFree(smap->prepend);
+  smap->prepend = (yyvsp[(3) - (4)].text);
+}
+    break;
+
+  case 288:
+#line 1165 "./ircd_parser.y"
+    {
+  char *sep = strchr((yyvsp[(3) - (4)].text), '@');
+
+  if (sep != NULL) {
+    size_t slen = strlen((yyvsp[(3) - (4)].text));
+    struct nick_host *nh = MyMalloc(sizeof(*nh) + slen);
+    memcpy(nh->nick, (yyvsp[(3) - (4)].text), slen + 1);
+    nh->nicklen = sep - (yyvsp[(3) - (4)].text);
+    nh->next = smap->services;
+    smap->services = nh;
+  }
+  MyFree((yyvsp[(3) - (4)].text));
+}
+    break;
+
+  case 289:
+#line 1179 "./ircd_parser.y"
+    {
+  smap->flags |= SMAP_FAST;
+}
+    break;
+
+  case 290:
+#line 1184 "./ircd_parser.y"
+    {
+  auth_spawn(stringno, stringlist, iauth_required);
+  while (stringno > 0)
+  {
+    --stringno;
+    MyFree(stringlist[stringno]);
+  }
+  iauth_required = 0;
+}
+    break;
+
+  case 295:
+#line 1197 "./ircd_parser.y"
+    {
+  while (stringno > 0)
+  {
+    --stringno;
+    MyFree(stringlist[stringno]);
+  }
+}
+    break;
+
+  case 297:
+#line 1206 "./ircd_parser.y"
+    {
+  iauth_required = (yyvsp[(3) - (4)].num);
+}
+    break;
+
+  case 298:
+#line 1210 "./ircd_parser.y"
+    {
+  unsigned int ii;
+  for(ii = 0; ii < 256; ++ii) {
+    MyFree(GlobalForwards[ii]);
+  }
+}
+    break;
+
+  case 302:
+#line 1218 "./ircd_parser.y"
+    {
+  unsigned char ch = (yyvsp[(1) - (4)].text)[0];
+  MyFree(GlobalForwards[ch]);
+  GlobalForwards[ch] = (yyvsp[(3) - (4)].text);
+  MyFree((yyvsp[(1) - (4)].text));
+}
+    break;
+
+  case 303:
+#line 1225 "./ircd_parser.y"
+    {
+    /* If we read a new webirc block, we create a new block. */
+    webirc = webirc_block();
+}
+    break;
+
+  case 304:
+#line 1228 "./ircd_parser.y"
+    {
+    /* check for integrity */
+    if(!webirc->name[0]) {
+        parse_error("Every WebIRC block needs at least a name entry.");
+        webirc_list_clear(webirc);
+        MyFree(webirc);
+        webirc = NULL;
+    }
+    else {
+        webirc_establish(webirc);
+        webirc = NULL;
+    }
+}
+    break;
+
+  case 313:
+#line 1243 "./ircd_parser.y"
+    {
+    unsigned int len;
+    if((len = strlen((yyvsp[(3) - (4)].text))) > 0)
+        webirc_set(webirc, WEBIRC_PASS, (yyvsp[(3) - (4)].text), len, 0);
+    MyFree((yyvsp[(3) - (4)].text));
+}
+    break;
+
+  case 314:
+#line 1249 "./ircd_parser.y"
+    {
+    unsigned int len;
+    if((len = strlen((yyvsp[(3) - (4)].text))) > 0)
+        webirc_set(webirc, WEBIRC_HOST, (yyvsp[(3) - (4)].text), len, 0);
+    MyFree((yyvsp[(3) - (4)].text));
+}
+    break;
+
+  case 315:
+#line 1255 "./ircd_parser.y"
+    {
+    unsigned int len;
+    if((len = strlen((yyvsp[(4) - (5)].text))) > 0)
+        webirc_set(webirc, WEBIRC_HOST, (yyvsp[(4) - (5)].text), len, 1);
+    MyFree((yyvsp[(4) - (5)].text));
+}
+    break;
+
+  case 316:
+#line 1261 "./ircd_parser.y"
+    {
+    unsigned int len;
+    if((len = strlen((yyvsp[(3) - (4)].text))) > 0)
+        webirc_set(webirc, WEBIRC_SPOOF, (yyvsp[(3) - (4)].text), len, 0);
+    MyFree((yyvsp[(3) - (4)].text));
+}
+    break;
+
+  case 317:
+#line 1267 "./ircd_parser.y"
+    {
+    unsigned int len;
+    if((len = strlen((yyvsp[(4) - (5)].text))) > 0)
+        webirc_set(webirc, WEBIRC_SPOOF, (yyvsp[(4) - (5)].text), len, 1);
+    MyFree((yyvsp[(4) - (5)].text));
+}
+    break;
+
+  case 318:
+#line 1273 "./ircd_parser.y"
+    {
+    unsigned int len;
+    if(webirc->name[0]) {
+        MyFree((yyvsp[(3) - (4)].text));
+        parse_error("Only one name entry per WebIRC is allowed.");
+    }
+    else if((len = strlen((yyvsp[(3) - (4)].text))) > NICKLEN) {
+        MyFree((yyvsp[(3) - (4)].text));
+        parse_error("WebIRC block name length is limited to NICKLEN.");
+    }
+    else {
+        if((len = strlen((yyvsp[(3) - (4)].text))) > 0) {
+            strcpy(webirc->name, (yyvsp[(3) - (4)].text));
+            webirc->name[len] = '\0';
+        }
+        MyFree((yyvsp[(3) - (4)].text));
+    }
+}
+    break;
+
+  case 324:
+#line 1295 "./ircd_parser.y"
+    {
+    ssl_setcert((yyvsp[(3) - (4)].text));
+    MyFree((yyvsp[(3) - (4)].text));
+}
+    break;
+
+  case 325:
+#line 1299 "./ircd_parser.y"
+    {
+    ssl_addtrust((yyvsp[(3) - (4)].text));
+    MyFree((yyvsp[(3) - (4)].text));
+}
+    break;
+
+
+/* Line 1267 of yacc.c.  */
+#line 3893 "y.tab.c"
+      default: break;
+    }
+  YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc);
+
+  YYPOPSTACK (yylen);
+  yylen = 0;
+  YY_STACK_PRINT (yyss, yyssp);
+
+  *++yyvsp = yyval;
+
+
+  /* Now `shift' the result of the reduction.  Determine what state
+     that goes to, based on the state we popped back to and the rule
+     number reduced by.  */
+
+  yyn = yyr1[yyn];
+
+  yystate = yypgoto[yyn - YYNTOKENS] + *yyssp;
+  if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp)
+    yystate = yytable[yystate];
+  else
+    yystate = yydefgoto[yyn - YYNTOKENS];
+
+  goto yynewstate;
+
+
+/*------------------------------------.
+| yyerrlab -- here on detecting error |
+`------------------------------------*/
+yyerrlab:
+  /* If not already recovering from an error, report this error.  */
+  if (!yyerrstatus)
+    {
+      ++yynerrs;
+#if ! YYERROR_VERBOSE
+      yyerror (YY_("syntax error"));
+#else
+      {
+       YYSIZE_T yysize = yysyntax_error (0, yystate, yychar);
+       if (yymsg_alloc < yysize && yymsg_alloc < YYSTACK_ALLOC_MAXIMUM)
+         {
+           YYSIZE_T yyalloc = 2 * yysize;
+           if (! (yysize <= yyalloc && yyalloc <= YYSTACK_ALLOC_MAXIMUM))
+             yyalloc = YYSTACK_ALLOC_MAXIMUM;
+           if (yymsg != yymsgbuf)
+             YYSTACK_FREE (yymsg);
+           yymsg = (char *) YYSTACK_ALLOC (yyalloc);
+           if (yymsg)
+             yymsg_alloc = yyalloc;
+           else
+             {
+               yymsg = yymsgbuf;
+               yymsg_alloc = sizeof yymsgbuf;
+             }
+         }
+
+       if (0 < yysize && yysize <= yymsg_alloc)
+         {
+           (void) yysyntax_error (yymsg, yystate, yychar);
+           yyerror (yymsg);
+         }
+       else
+         {
+           yyerror (YY_("syntax error"));
+           if (yysize != 0)
+             goto yyexhaustedlab;
+         }
+      }
+#endif
+    }
+
+
+
+  if (yyerrstatus == 3)
+    {
+      /* If just tried and failed to reuse look-ahead token after an
+        error, discard it.  */
+
+      if (yychar <= YYEOF)
+       {
+         /* Return failure if at end of input.  */
+         if (yychar == YYEOF)
+           YYABORT;
+       }
+      else
+       {
+         yydestruct ("Error: discarding",
+                     yytoken, &yylval);
+         yychar = YYEMPTY;
+       }
+    }
+
+  /* Else will try to reuse look-ahead token after shifting the error
+     token.  */
+  goto yyerrlab1;
+
+
+/*---------------------------------------------------.
+| yyerrorlab -- error raised explicitly by YYERROR.  |
+`---------------------------------------------------*/
+yyerrorlab:
+
+  /* Pacify compilers like GCC when the user code never invokes
+     YYERROR and the label yyerrorlab therefore never appears in user
+     code.  */
+  if (/*CONSTCOND*/ 0)
+     goto yyerrorlab;
+
+  /* Do not reclaim the symbols of the rule which action triggered
+     this YYERROR.  */
+  YYPOPSTACK (yylen);
+  yylen = 0;
+  YY_STACK_PRINT (yyss, yyssp);
+  yystate = *yyssp;
+  goto yyerrlab1;
+
+
+/*-------------------------------------------------------------.
+| yyerrlab1 -- common code for both syntax error and YYERROR.  |
+`-------------------------------------------------------------*/
+yyerrlab1:
+  yyerrstatus = 3;     /* Each real token shifted decrements this.  */
+
+  for (;;)
+    {
+      yyn = yypact[yystate];
+      if (yyn != YYPACT_NINF)
+       {
+         yyn += YYTERROR;
+         if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR)
+           {
+             yyn = yytable[yyn];
+             if (0 < yyn)
+               break;
+           }
+       }
+
+      /* Pop the current state because it cannot handle the error token.  */
+      if (yyssp == yyss)
+       YYABORT;
+
+
+      yydestruct ("Error: popping",
+                 yystos[yystate], yyvsp);
+      YYPOPSTACK (1);
+      yystate = *yyssp;
+      YY_STACK_PRINT (yyss, yyssp);
+    }
+
+  if (yyn == YYFINAL)
+    YYACCEPT;
+
+  *++yyvsp = yylval;
+
+
+  /* Shift the error token.  */
+  YY_SYMBOL_PRINT ("Shifting", yystos[yyn], yyvsp, yylsp);
+
+  yystate = yyn;
+  goto yynewstate;
+
+
+/*-------------------------------------.
+| yyacceptlab -- YYACCEPT comes here.  |
+`-------------------------------------*/
+yyacceptlab:
+  yyresult = 0;
+  goto yyreturn;
+
+/*-----------------------------------.
+| yyabortlab -- YYABORT comes here.  |
+`-----------------------------------*/
+yyabortlab:
+  yyresult = 1;
+  goto yyreturn;
+
+#ifndef yyoverflow
+/*-------------------------------------------------.
+| yyexhaustedlab -- memory exhaustion comes here.  |
+`-------------------------------------------------*/
+yyexhaustedlab:
+  yyerror (YY_("memory exhausted"));
+  yyresult = 2;
+  /* Fall through.  */
+#endif
+
+yyreturn:
+  if (yychar != YYEOF && yychar != YYEMPTY)
+     yydestruct ("Cleanup: discarding lookahead",
+                yytoken, &yylval);
+  /* Do not reclaim the symbols of the rule which action triggered
+     this YYABORT or YYACCEPT.  */
+  YYPOPSTACK (yylen);
+  YY_STACK_PRINT (yyss, yyssp);
+  while (yyssp != yyss)
+    {
+      yydestruct ("Cleanup: popping",
+                 yystos[*yyssp], yyvsp);
+      YYPOPSTACK (1);
+    }
+#ifndef yyoverflow
+  if (yyss != yyssa)
+    YYSTACK_FREE (yyss);
+#endif
+#if YYERROR_VERBOSE
+  if (yymsg != yymsgbuf)
+    YYSTACK_FREE (yymsg);
+#endif
+  /* Make sure YYID is used.  */
+  return YYID (yyresult);
+}
+
+
+
diff --git a/ircd/y.tab.h b/ircd/y.tab.h
new file mode 100644 (file)
index 0000000..ea0bc7d
--- /dev/null
@@ -0,0 +1,305 @@
+/* A Bison parser, made by GNU Bison 2.3.  */
+
+/* Skeleton interface for Bison's Yacc-like parsers in C
+
+   Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006
+   Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin Street, Fifth Floor,
+   Boston, MA 02110-1301, USA.  */
+
+/* As a special exception, you may create a larger work that contains
+   part or all of the Bison parser skeleton and distribute that work
+   under terms of your choice, so long as that work isn't itself a
+   parser generator using the skeleton or a modified version thereof
+   as a parser skeleton.  Alternatively, if you modify or redistribute
+   the parser skeleton itself, you may (at your option) remove this
+   special exception, which will cause the skeleton and the resulting
+   Bison output files to be licensed under the GNU General Public
+   License without this special exception.
+
+   This special exception was added by the Free Software Foundation in
+   version 2.2 of Bison.  */
+
+/* Tokens.  */
+#ifndef YYTOKENTYPE
+# define YYTOKENTYPE
+   /* Put the tokens into the symbol table, so that GDB and other debuggers
+      know about them.  */
+   enum yytokentype {
+     QSTRING = 258,
+     NUMBER = 259,
+     GENERAL = 260,
+     ADMIN = 261,
+     LOCATION = 262,
+     CONTACT = 263,
+     CONNECT = 264,
+     CLASS = 265,
+     CHANNEL = 266,
+     PINGFREQ = 267,
+     CONNECTFREQ = 268,
+     MAXLINKS = 269,
+     MAXHOPS = 270,
+     SENDQ = 271,
+     NAME = 272,
+     HOST = 273,
+     IP = 274,
+     USERNAME = 275,
+     PASS = 276,
+     LOCAL = 277,
+     SECONDS = 278,
+     MINUTES = 279,
+     HOURS = 280,
+     DAYS = 281,
+     WEEKS = 282,
+     MONTHS = 283,
+     YEARS = 284,
+     DECADES = 285,
+     BYTES = 286,
+     KBYTES = 287,
+     MBYTES = 288,
+     GBYTES = 289,
+     TBYTES = 290,
+     SERVER = 291,
+     PORT = 292,
+     MASK = 293,
+     HUB = 294,
+     LEAF = 295,
+     UWORLD = 296,
+     YES = 297,
+     NO = 298,
+     OPER = 299,
+     VHOST = 300,
+     HIDDEN = 301,
+     MOTD = 302,
+     JUPE = 303,
+     NICK = 304,
+     NUMERIC = 305,
+     DESCRIPTION = 306,
+     CLIENT = 307,
+     KILL = 308,
+     CRULE = 309,
+     REAL = 310,
+     REASON = 311,
+     TFILE = 312,
+     RULE = 313,
+     ALL = 314,
+     FEATURES = 315,
+     QUARANTINE = 316,
+     PSEUDO = 317,
+     PREPEND = 318,
+     USERMODE = 319,
+     IAUTH = 320,
+     TIMEOUT = 321,
+     FAST = 322,
+     AUTOCONNECT = 323,
+     PROGRAM = 324,
+     TOK_IPV4 = 325,
+     TOK_IPV6 = 326,
+     DNS = 327,
+     FORWARDS = 328,
+     SECURE = 329,
+     WEBIRC = 330,
+     SPOOF = 331,
+     MAXCHANS = 332,
+     REQUIRED = 333,
+     SSL = 334,
+     CERT = 335,
+     CACERT = 336,
+     TPRIV_CHAN_LIMIT = 337,
+     TPRIV_MODE_LCHAN = 338,
+     TPRIV_DEOP_LCHAN = 339,
+     TPRIV_WALK_LCHAN = 340,
+     TPRIV_LOCAL_KILL = 341,
+     TPRIV_REHASH = 342,
+     TPRIV_RESTART = 343,
+     TPRIV_DIE = 344,
+     TPRIV_GLINE = 345,
+     TPRIV_LOCAL_GLINE = 346,
+     TPRIV_LOCAL_JUPE = 347,
+     TPRIV_LOCAL_BADCHAN = 348,
+     TPRIV_LOCAL_OPMODE = 349,
+     TPRIV_OPMODE = 350,
+     TPRIV_SET = 351,
+     TPRIV_WHOX = 352,
+     TPRIV_BADCHAN = 353,
+     TPRIV_SEE_CHAN = 354,
+     TPRIV_SHOW_INVIS = 355,
+     TPRIV_SHOW_ALL_INVIS = 356,
+     TPRIV_PROPAGATE = 357,
+     TPRIV_UNLIMIT_QUERY = 358,
+     TPRIV_DISPLAY = 359,
+     TPRIV_SEE_OPERS = 360,
+     TPRIV_WIDE_GLINE = 361,
+     TPRIV_FORCE_OPMODE = 362,
+     TPRIV_FORCE_LOCAL_OPMODE = 363,
+     TPRIV_APASS_OPMODE = 364,
+     TPRIV_LIST_CHAN = 365,
+     TPRIV_SEE_IDLETIME = 366,
+     TPRIV_UMODE_NETSERV = 367,
+     TPRIV_UMODE_NOCHAN = 368,
+     TPRIV_UMODE_NOIDLE = 369,
+     TPRIV_UMODE_CHSERV = 370,
+     TPRIV_UMODE_XTRAOP = 371,
+     TPRIV_FLOOD = 372,
+     TPRIV_HALFFLOOD = 373,
+     TPRIV_UNLIMITED_TARGET = 374,
+     TPRIV_UMODE_OVERRIDECC = 375,
+     TPRIV_HIDE_IDLETIME = 376,
+     TPRIV_NOAMSG_OVERRIDE = 377
+   };
+#endif
+/* Tokens.  */
+#define QSTRING 258
+#define NUMBER 259
+#define GENERAL 260
+#define ADMIN 261
+#define LOCATION 262
+#define CONTACT 263
+#define CONNECT 264
+#define CLASS 265
+#define CHANNEL 266
+#define PINGFREQ 267
+#define CONNECTFREQ 268
+#define MAXLINKS 269
+#define MAXHOPS 270
+#define SENDQ 271
+#define NAME 272
+#define HOST 273
+#define IP 274
+#define USERNAME 275
+#define PASS 276
+#define LOCAL 277
+#define SECONDS 278
+#define MINUTES 279
+#define HOURS 280
+#define DAYS 281
+#define WEEKS 282
+#define MONTHS 283
+#define YEARS 284
+#define DECADES 285
+#define BYTES 286
+#define KBYTES 287
+#define MBYTES 288
+#define GBYTES 289
+#define TBYTES 290
+#define SERVER 291
+#define PORT 292
+#define MASK 293
+#define HUB 294
+#define LEAF 295
+#define UWORLD 296
+#define YES 297
+#define NO 298
+#define OPER 299
+#define VHOST 300
+#define HIDDEN 301
+#define MOTD 302
+#define JUPE 303
+#define NICK 304
+#define NUMERIC 305
+#define DESCRIPTION 306
+#define CLIENT 307
+#define KILL 308
+#define CRULE 309
+#define REAL 310
+#define REASON 311
+#define TFILE 312
+#define RULE 313
+#define ALL 314
+#define FEATURES 315
+#define QUARANTINE 316
+#define PSEUDO 317
+#define PREPEND 318
+#define USERMODE 319
+#define IAUTH 320
+#define TIMEOUT 321
+#define FAST 322
+#define AUTOCONNECT 323
+#define PROGRAM 324
+#define TOK_IPV4 325
+#define TOK_IPV6 326
+#define DNS 327
+#define FORWARDS 328
+#define SECURE 329
+#define WEBIRC 330
+#define SPOOF 331
+#define MAXCHANS 332
+#define REQUIRED 333
+#define SSL 334
+#define CERT 335
+#define CACERT 336
+#define TPRIV_CHAN_LIMIT 337
+#define TPRIV_MODE_LCHAN 338
+#define TPRIV_DEOP_LCHAN 339
+#define TPRIV_WALK_LCHAN 340
+#define TPRIV_LOCAL_KILL 341
+#define TPRIV_REHASH 342
+#define TPRIV_RESTART 343
+#define TPRIV_DIE 344
+#define TPRIV_GLINE 345
+#define TPRIV_LOCAL_GLINE 346
+#define TPRIV_LOCAL_JUPE 347
+#define TPRIV_LOCAL_BADCHAN 348
+#define TPRIV_LOCAL_OPMODE 349
+#define TPRIV_OPMODE 350
+#define TPRIV_SET 351
+#define TPRIV_WHOX 352
+#define TPRIV_BADCHAN 353
+#define TPRIV_SEE_CHAN 354
+#define TPRIV_SHOW_INVIS 355
+#define TPRIV_SHOW_ALL_INVIS 356
+#define TPRIV_PROPAGATE 357
+#define TPRIV_UNLIMIT_QUERY 358
+#define TPRIV_DISPLAY 359
+#define TPRIV_SEE_OPERS 360
+#define TPRIV_WIDE_GLINE 361
+#define TPRIV_FORCE_OPMODE 362
+#define TPRIV_FORCE_LOCAL_OPMODE 363
+#define TPRIV_APASS_OPMODE 364
+#define TPRIV_LIST_CHAN 365
+#define TPRIV_SEE_IDLETIME 366
+#define TPRIV_UMODE_NETSERV 367
+#define TPRIV_UMODE_NOCHAN 368
+#define TPRIV_UMODE_NOIDLE 369
+#define TPRIV_UMODE_CHSERV 370
+#define TPRIV_UMODE_XTRAOP 371
+#define TPRIV_FLOOD 372
+#define TPRIV_HALFFLOOD 373
+#define TPRIV_UNLIMITED_TARGET 374
+#define TPRIV_UMODE_OVERRIDECC 375
+#define TPRIV_HIDE_IDLETIME 376
+#define TPRIV_NOAMSG_OVERRIDE 377
+
+
+
+
+#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
+typedef union YYSTYPE
+#line 207 "./ircd_parser.y"
+{
+ char *text;
+ int num;
+}
+/* Line 1489 of yacc.c.  */
+#line 298 "y.tab.h"
+       YYSTYPE;
+# define yystype YYSTYPE /* obsolescent; will be withdrawn */
+# define YYSTYPE_IS_DECLARED 1
+# define YYSTYPE_IS_TRIVIAL 1
+#endif
+
+extern YYSTYPE yylval;
+
diff --git a/patches/diffs/lazy.diff b/patches/diffs/lazy.diff
new file mode 100644 (file)
index 0000000..d7ac517
--- /dev/null
@@ -0,0 +1,913 @@
+Index: include/channel.h
+===================================================================
+RCS file: /home/coder-com/cvs/ircu2.10/include/channel.h,v
+retrieving revision 1.32
+diff -u -r1.32 channel.h
+--- include/channel.h  2002/04/03 21:16:01     1.32
++++ include/channel.h  2002/04/12 13:47:52
+@@ -95,6 +95,8 @@
+ #define MODE_BURSTADDED       0x80000 /* channel was created by a BURST */
+ #define MODE_UPASS    0x100000
+ #define MODE_APASS    0x200000
++#define MODE_EMPTY    0x400000 /* LazyLeaf: no more locals, remove channel asap */
++
+ /*
+  * mode flags which take another parameter (With PARAmeterS)
+  */
+@@ -222,15 +224,20 @@
+   time_t             creationtime;
+   time_t             topic_time;
+   unsigned int       users;
++  unsigned int       locals;
+   struct Membership* members;
+   struct SLink*      invites;
+   struct SLink*      banlist;
+   struct Mode        mode;
+   char               topic[TOPICLEN + 1];
+   char               topic_nick[NICKLEN + 1];
+-  char               chname[1];
++  unsigned long      ll_bits;         /* LazyLeaf */
++  char               chname[1];               /* This *must* be last */
+ };
++#define LeafKnowsChannel(c,x) (cli_serv(c)->ll_mask & (x)->ll_bits)
++#define LL_ALL                        (~0UL)
++
+ struct ListingArgs {
+   time_t max_time;
+   time_t min_time;
+@@ -350,6 +357,7 @@
+ extern int is_zombie(struct Client *cptr, struct Channel *chptr);
+ extern int has_voice(struct Client *cptr, struct Channel *chptr);
+ extern void send_channel_modes(struct Client *cptr, struct Channel *chptr);
++extern void ll_send_channel(struct Client *cptr, struct Channel *chptr);
+ extern char *pretty_mask(char *mask);
+ extern void del_invite(struct Client *cptr, struct Channel *chptr);
+ extern void list_next_channels(struct Client *cptr, int nr);
+Index: include/client.h
+===================================================================
+RCS file: /home/coder-com/cvs/ircu2.10/include/client.h,v
+retrieving revision 1.26
+diff -u -r1.26 client.h
+--- include/client.h   2002/04/05 11:36:58     1.26
++++ include/client.h   2002/04/12 13:47:52
+@@ -369,6 +369,7 @@
+ #define FLAGS_DOID      0x00040000      /* I-lines say must use ident return */
+ #define FLAGS_NONL      0x00080000      /* No \n in buffer */
+ #define FLAGS_TS8       0x00100000      /* Why do you want to know? */
++#define FLAGS_LAZY    0x00200000      /* LazyLeaf */
+ #define FLAGS_MAP       0x00800000      /* Show server on the map */
+ #define FLAGS_JUNCTION  0x01000000      /* Junction causing the net.burst */
+ #define FLAGS_DEAF      0x02000000      /* Makes user deaf */
+@@ -413,6 +414,7 @@
+ #define IsAccount(x)            (cli_flags(x) & FLAGS_ACCOUNT)
+ #define IsHiddenHost(x)               (cli_flags(x) & FLAGS_HIDDENHOST)
+ #define HasHiddenHost(x)      (IsAccount(x) && IsHiddenHost(x))
++#define IsLazy(x)             (cli_flags(x) & FLAGS_LAZY)
+ #define IsPrivileged(x)         (IsAnOper(x) || IsServer(x))
+@@ -435,6 +437,7 @@
+ #define SetService(x)           (cli_flags(x) |= FLAGS_SERVICE)
+ #define SetAccount(x)           (cli_flags(x) |= FLAGS_ACCOUNT)
+ #define SetHiddenHost(x)      (cli_flags(x) |= FLAGS_HIDDENHOST)
++#define SetLazy(x)            (cli_flags(x) |= FLAGS_LAZY)
+ #define ClearAccess(x)          (cli_flags(x) &= ~FLAGS_CHKACCESS)
+ #define ClearBurst(x)           (cli_flags(x) &= ~FLAGS_BURST)
+@@ -450,6 +453,7 @@
+ #define ClearWallops(x)         (cli_flags(x) &= ~FLAGS_WALLOP)
+ #define ClearServNotice(x)      (cli_flags(x) &= ~FLAGS_SERVNOTICE)
+ #define ClearHiddenHost(x)    (cli_flags(x) &= ~FLAGS_HIDDENHOST)
++#define ClearLazy(x)          (cli_flags(x) &= ~FLAGS_LAZY)
+ /* free flags */
+ #define FREEFLAG_SOCKET       0x0001  /* socket needs to be freed */
+Index: include/handlers.h
+===================================================================
+RCS file: /home/coder-com/cvs/ircu2.10/include/handlers.h,v
+retrieving revision 1.16
+diff -u -r1.16 handlers.h
+--- include/handlers.h 2002/03/19 22:03:36     1.16
++++ include/handlers.h 2002/04/12 13:47:52
+@@ -183,6 +183,7 @@
+ extern int ms_gline(struct Client*, struct Client*, int, char*[]);
+ extern int ms_info(struct Client*, struct Client*, int, char*[]);
+ extern int ms_invite(struct Client*, struct Client*, int, char*[]);
++extern int ms_forget(struct Client*, struct Client*, int, char*[]);
+ extern int ms_join(struct Client*, struct Client*, int, char*[]);
+ extern int ms_jupe(struct Client*, struct Client*, int, char*[]);
+ extern int ms_kick(struct Client*, struct Client*, int, char*[]);
+Index: include/ircd_features.h
+===================================================================
+RCS file: /home/coder-com/cvs/ircu2.10/include/ircd_features.h,v
+retrieving revision 1.15
+diff -u -r1.15 ircd_features.h
+--- include/ircd_features.h    2002/04/03 15:23:47     1.15
++++ include/ircd_features.h    2002/04/12 13:47:52
+@@ -37,6 +37,7 @@
+   FEAT_KILL_IPMISMATCH,
+   FEAT_IDLE_FROM_MSG,
+   FEAT_HUB,
++  FEAT_LAZY_LEAF,
+   FEAT_WALLOPS_OPER_ONLY,
+   FEAT_NODNS,
+   FEAT_RANDOM_SEED,
+Index: include/msg.h
+===================================================================
+RCS file: /home/coder-com/cvs/ircu2.10/include/msg.h,v
+retrieving revision 1.12
+diff -u -r1.12 msg.h
+--- include/msg.h      2002/02/14 00:20:40     1.12
++++ include/msg.h      2002/04/12 13:47:52
+@@ -330,6 +330,10 @@
+ #define TOK_ACCOUNT           "AC"
+ #define CMD_ACCOUNT           MSG_ACCOUNT, TOK_ACCOUNT
++#define MSG_FORGET            "FORGET"        /* FORGET */
++#define TOK_FORGET            "FO"
++#define CMD_FORGET            MSG_FORGET, TOK_FORGET
++
+ #define MSG_POST                "POST"          /* POST */
+ #define TOK_POST                "POST"
+Index: include/s_serv.h
+===================================================================
+RCS file: /home/coder-com/cvs/ircu2.10/include/s_serv.h,v
+retrieving revision 1.6
+diff -u -r1.6 s_serv.h
+--- include/s_serv.h   2001/06/08 23:12:16     1.6
++++ include/s_serv.h   2002/04/12 13:47:52
+@@ -12,9 +12,11 @@
+ struct ConfItem;
+ struct Client;
++struct Channel;
+ extern unsigned int max_connection_count;
+ extern unsigned int max_client_count;
++extern unsigned long GlobalLeafBits;
+ /*
+  * Prototypes
+@@ -24,5 +26,8 @@
+ extern int a_kills_b_too(struct Client *a, struct Client *b);
+ extern int server_estab(struct Client *cptr, struct ConfItem *aconf);
++extern int ll_add(struct Client *cptr);
++extern void ll_remove(struct Client *cptr);
++extern void ll_check_channel(struct Client *cptr, struct Channel *chptr);
+ #endif /* INCLUDED_s_serv_h */
+Index: include/send.h
+===================================================================
+RCS file: /home/coder-com/cvs/ircu2.10/include/send.h,v
+retrieving revision 1.17
+diff -u -r1.17 send.h
+--- include/send.h     2002/02/14 00:20:41     1.17
++++ include/send.h     2002/04/12 13:47:52
+@@ -47,6 +47,12 @@
+                                 const char *tok, struct Client *one,
+                                 const char *pattern, ...);
++/* Same as above, but only when the server's ll_mask matches */
++extern void sendcmdto_mask_butone(struct Client *from, const char *cmd,
++                                const char *tok, unsigned long ll_mask,
++                                struct Client *one,
++                                const char *pattern, ...);
++
+ /* Send command to all channels user is on */
+ extern void sendcmdto_common_channels_butone(struct Client *from,
+                                            const char *cmd,
+Index: include/struct.h
+===================================================================
+RCS file: /home/coder-com/cvs/ircu2.10/include/struct.h,v
+retrieving revision 1.3
+diff -u -r1.3 struct.h
+--- include/struct.h   2002/02/14 00:20:41     1.3
++++ include/struct.h   2002/04/12 13:47:52
+@@ -52,6 +52,7 @@
+   unsigned short  nn_last;      /* Last numeric nick for p9 servers only */
+   unsigned int    nn_mask;      /* [Remote] FD_SETSIZE - 1 */
+   char          nn_capacity[4]; /* numeric representation of server capacity */
++  unsigned long   ll_mask;    /* LazyLeaf mask */
+   char *last_error_msg;         /* Allocated memory with last message receive with an ERROR */
+   char by[NICKLEN + 1];
+Index: ircd/Makefile.in
+===================================================================
+RCS file: /home/coder-com/cvs/ircu2.10/ircd/Makefile.in,v
+retrieving revision 1.43
+diff -u -r1.43 Makefile.in
+--- ircd/Makefile.in   2002/04/03 21:16:01     1.43
++++ ircd/Makefile.in   2002/04/12 13:47:52
+@@ -120,6 +120,7 @@
+       m_die.c \
+       m_endburst.c \
+       m_error.c \
++      m_forget.c \
+       m_get.c \
+       m_gline.c \
+       m_help.c \
+Index: ircd/channel.c
+===================================================================
+RCS file: /home/coder-com/cvs/ircu2.10/ircd/channel.c,v
+retrieving revision 1.81
+diff -u -r1.81 channel.c
+--- ircd/channel.c     2002/04/03 21:16:01     1.81
++++ ircd/channel.c     2002/04/12 13:47:52
+@@ -46,6 +46,7 @@
+ #include "s_conf.h"
+ #include "s_debug.h"
+ #include "s_misc.h"
++#include "s_serv.h"
+ #include "s_user.h"
+ #include "send.h"
+ #include "struct.h"
+@@ -533,6 +534,8 @@
+       remove_destruct_event(chptr);
+     ++chptr->users;
+     ++((cli_user(who))->joined);
++    if (MyUser(who))
++      ++chptr->locals;
+   }
+ }
+@@ -562,6 +565,8 @@
+     (cli_user(member->user))->channel = member->next_channel;
+   --(cli_user(member->user))->joined;
++  if (MyUser(member->user))
++    --chptr->locals;
+   member->next_member = membershipFreeList;
+   membershipFreeList = member;
+@@ -587,6 +592,17 @@
+   struct Membership* member;
+   assert(0 != chptr);
++  if (chptr->mode.mode & MODE_EMPTY) {
++    assert(feature_bool(FEAT_LAZY_LEAF));
++  
++    /* Channel has no more locals, free it */
++    do {
++      assert(!MyUser(chptr->members->user));
++    } while (remove_member_from_channel(chptr->members));
++
++    return;
++  }
++
+   if ((member = find_member_link(chptr, cptr))) {
+     if (remove_member_from_channel(member)) {
+       if (channel_all_zombies(chptr)) {
+@@ -1417,6 +1433,7 @@
+     for (; acptr != &me; acptr = (cli_serv(acptr))->up)
+       if (acptr == (cli_user(who))->server)   /* Case d) (server 5) */
+       {
++        ll_check_channel(who, chptr);
+         remove_user_from_channel(who, chptr);
+         return;
+       }
+@@ -1769,8 +1786,8 @@
+     if (mbuf->mb_dest & MODEBUF_DEST_OPMODE) {
+       /* If OPMODE was set, we're propagating the mode as an OPMODE message */
+-      sendcmdto_serv_butone(mbuf->mb_source, CMD_OPMODE, mbuf->mb_connect,
+-                          "%H %s%s%s%s%s%s", mbuf->mb_channel,
++      sendcmdto_mask_butone(mbuf->mb_source, CMD_OPMODE, mbuf->mb_channel->ll_bits,
++                          mbuf->mb_connect, "%H %s%s%s%s%s%s", mbuf->mb_channel,
+                           rembuf_i ? "-" : "", rembuf, addbuf_i ? "+" : "",
+                           addbuf, remstr, addstr);
+     } else if (mbuf->mb_dest & MODEBUF_DEST_BOUNCE) {
+@@ -1789,14 +1806,16 @@
+        * we send the actual channel TS unless this is a HACK3 or a HACK4
+        */
+       if (IsServer(mbuf->mb_source))
+-      sendcmdto_serv_butone(mbuf->mb_source, CMD_MODE, mbuf->mb_connect,
++      sendcmdto_mask_butone(mbuf->mb_source, CMD_MODE,
++                            mbuf->mb_channel->ll_bits, mbuf->mb_connect,
+                             "%H %s%s%s%s%s%s %Tu", mbuf->mb_channel,
+                             rembuf_i ? "-" : "", rembuf, addbuf_i ? "+" : "",
+                             addbuf, remstr, addstr,
+                             (mbuf->mb_dest & MODEBUF_DEST_HACK4) ? 0 :
+                             mbuf->mb_channel->creationtime);
+       else
+-      sendcmdto_serv_butone(mbuf->mb_source, CMD_MODE, mbuf->mb_connect,
++      sendcmdto_mask_butone(mbuf->mb_source, CMD_MODE, 
++                            mbuf->mb_channel->ll_bits, mbuf->mb_connect,
+                             "%H %s%s%s%s%s%s", mbuf->mb_channel,
+                             rembuf_i ? "-" : "", rembuf, addbuf_i ? "+" : "",
+                             addbuf, remstr, addstr);
+@@ -3143,7 +3162,7 @@
+     /* send notification to all servers */
+     if (jbuf->jb_type != JOINBUF_TYPE_CREATE && !IsLocalChannel(chan->chname))
+-      sendcmdto_serv_butone(jbuf->jb_source, CMD_JOIN, jbuf->jb_connect,
++      sendcmdto_mask_butone(jbuf->jb_source, CMD_JOIN, chan->ll_bits, jbuf->jb_connect,
+                           "%H %Tu", chan, chan->creationtime);
+     /* Send the notification to the channel */
+@@ -3192,9 +3211,37 @@
+     build_string(chanlist, &chanlist_i,
+                jbuf->jb_channels[i] ? jbuf->jb_channels[i]->chname : "0", 0,
+                i == 0 ? '\0' : ',');
+-    if (JOINBUF_TYPE_PART == jbuf->jb_type)
++
++    /*
++     * For lazy leafs, joins/parts have to be sent separately for 
++     * each channel. 
++     */
++    switch (jbuf->jb_type) {
++    case JOINBUF_TYPE_CREATE:
++      sendcmdto_mask_butone(jbuf->jb_source, CMD_CREATE,
++                          jbuf->jb_channels[i] ? jbuf->jb_channels[i]->ll_bits : LL_ALL,
++                          jbuf->jb_connect, "%s %Tu",
++                          jbuf->jb_channels[i] ? jbuf->jb_channels[i]->chname : "0",
++                          jbuf->jb_create);
++      break;
++
++    case JOINBUF_TYPE_PART:
++      sendcmdto_mask_butone(jbuf->jb_source, CMD_PART,
++                          jbuf->jb_channels[i]->ll_bits,
++                          jbuf->jb_connect,
++                          jbuf->jb_comment ? "%s :%s" : "%s",
++                          jbuf->jb_channels[i]->chname,
++                          jbuf->jb_comment);
++      break;
++    }
++
++    if (JOINBUF_TYPE_PART == jbuf->jb_type) {
++      /* Check now, as remove_user* may free the channel */
++      ll_check_channel(jbuf->jb_source, jbuf->jb_channels[i]);
++      
+       /* Remove user from channel */
+       remove_user_from_channel(jbuf->jb_source, jbuf->jb_channels[i]);
++    }
+     jbuf->jb_channels[i] = 0; /* mark slot empty */
+   }
+@@ -3204,6 +3251,7 @@
+                     STARTJOINLEN : STARTCREATELEN) +
+                    (jbuf->jb_comment ? strlen(jbuf->jb_comment) + 2 : 0));
++#if 0
+   /* and send the appropriate command */
+   switch (jbuf->jb_type) {
+   case JOINBUF_TYPE_CREATE:
+@@ -3217,6 +3265,7 @@
+                         jbuf->jb_comment);
+     break;
+   }
++#endif
+   return 0;
+ }
+Index: ircd/ircd_features.c
+===================================================================
+RCS file: /home/coder-com/cvs/ircu2.10/ircd/ircd_features.c,v
+retrieving revision 1.19
+diff -u -r1.19 ircd_features.c
+--- ircd/ircd_features.c       2002/04/03 15:23:48     1.19
++++ ircd/ircd_features.c       2002/04/12 13:47:52
+@@ -244,6 +244,7 @@
+   F_B(KILL_IPMISMATCH, FEAT_OPER, 0, 0),
+   F_B(IDLE_FROM_MSG, 0, 1, 0),
+   F_B(HUB, 0, 0, 0),
++  F_B(LAZY_LEAF, 0, 0, 0),
+   F_B(WALLOPS_OPER_ONLY, 0, 0, 0),
+   F_B(NODNS, 0, 0, 0),
+   F_N(RANDOM_SEED, FEAT_NODISP, random_seed_set, 0, 0, 0, 0, 0, 0),
+Index: ircd/m_burst.c
+===================================================================
+RCS file: /home/coder-com/cvs/ircu2.10/ircd/m_burst.c,v
+retrieving revision 1.16
+diff -u -r1.16 m_burst.c
+--- ircd/m_burst.c     2002/03/27 22:30:24     1.16
++++ ircd/m_burst.c     2002/04/12 13:47:52
+@@ -89,6 +89,7 @@
+ #include "ircd_policy.h"
+ #include "ircd_reply.h"
+ #include "ircd_string.h"
++#include "ircd_features.h"
+ #include "list.h"
+ #include "match.h"
+ #include "msg.h"
+@@ -463,6 +464,11 @@
+       lp->flags &= (CHFL_BAN | CHFL_BAN_IPMASK); /* reset the flag */
+       lp_p = &(*lp_p)->next;
+     }
++  }
++
++  if (IsLazy(cptr) && !LeafKnowsChannel(cptr, chptr)) {
++    chptr->ll_bits |= cli_serv(cptr)->ll_mask;
++    send_channel_modes(cptr, chptr);
+   }
+   return mbuf ? modebuf_flush(mbuf) : 0;
+Index: ircd/m_clearmode.c
+===================================================================
+RCS file: /home/coder-com/cvs/ircu2.10/ircd/m_clearmode.c,v
+retrieving revision 1.20
+diff -u -r1.20 m_clearmode.c
+--- ircd/m_clearmode.c 2002/02/14 00:20:42     1.20
++++ ircd/m_clearmode.c 2002/04/12 13:47:52
+@@ -234,8 +234,8 @@
+   /* Then send it */
+   if (!IsLocalChannel(chptr->chname))
+-    sendcmdto_serv_butone(sptr, CMD_CLEARMODE, cptr, "%H %s", chptr,
+-                        control_buf);
++    sendcmdto_mask_butone(sptr, CMD_CLEARMODE, chptr->ll_bits, cptr,
++                        "%H %s", chptr, control_buf);
+   return 0;
+ }
+Index: ircd/m_create.c
+===================================================================
+RCS file: /home/coder-com/cvs/ircu2.10/ircd/m_create.c,v
+retrieving revision 1.12
+diff -u -r1.12 m_create.c
+--- ircd/m_create.c    2002/02/14 00:20:42     1.12
++++ ircd/m_create.c    2002/04/12 13:47:52
+@@ -154,6 +154,7 @@
+       continue;
+     if ((chptr = FindChannel(name))) {
++      int hack2 = IsLazy(cptr) ? 0 : MODEBUF_DEST_HACK2;
+       name = chptr->chname;
+       /* Check if we need to bounce a mode */
+@@ -162,7 +163,7 @@
+          chptr->creationtime != MAGIC_REMOTE_JOIN_TS)) {
+       modebuf_init(&mbuf, sptr, cptr, chptr,
+                    (MODEBUF_DEST_SERVER |  /* Send mode to server */
+-                    MODEBUF_DEST_HACK2  |  /* Send a HACK(2) message */
++                    hack2               |  /* Send a HACK(2) message */
+                     MODEBUF_DEST_BOUNCE)); /* And bounce the mode */
+       modebuf_mode_client(&mbuf, MODE_ADD | MODE_CHANOP, sptr);
+@@ -180,6 +181,11 @@
+     joinbuf_join(badop ? &join : &create, chptr,
+                (badop || IsModelessChannel(name)) ?
+                CHFL_DEOPPED : CHFL_CHANOP);
++
++    if (IsLazy(cptr) && !LeafKnowsChannel(cptr, chptr)) {
++      chptr->ll_bits |= cli_serv(cptr)->ll_mask;
++      send_channel_modes(cptr, chptr);
++    }
+   }
+   joinbuf_flush(&join); /* flush out the joins and creates */
+Index: ircd/m_join.c
+===================================================================
+RCS file: /home/coder-com/cvs/ircu2.10/ircd/m_join.c,v
+retrieving revision 1.19
+diff -u -r1.19 m_join.c
+--- ircd/m_join.c      2002/03/13 09:19:21     1.19
++++ ircd/m_join.c      2002/04/12 13:47:52
+@@ -373,6 +373,11 @@
+       chptr->creationtime = creation;
+     } 
++    if (IsLazy(cptr) && !LeafKnowsChannel(cptr, chptr)) {
++      chptr->ll_bits |= cli_serv(cptr)->ll_mask;
++      send_channel_modes(cptr, chptr);
++    }
++
+     joinbuf_join(&join, chptr, flags);
+   }
+Index: ircd/m_kick.c
+===================================================================
+RCS file: /home/coder-com/cvs/ircu2.10/ircd/m_kick.c,v
+retrieving revision 1.8
+diff -u -r1.8 m_kick.c
+--- ircd/m_kick.c      2002/03/13 09:19:21     1.8
++++ ircd/m_kick.c      2002/04/12 13:47:52
+@@ -150,7 +150,7 @@
+   comment = EmptyString(parv[parc - 1]) ? parv[0] : parv[parc - 1];
+   if (!IsLocalChannel(name))
+-    sendcmdto_serv_butone(sptr, CMD_KICK, cptr, "%H %C :%s", chptr, who,
++    sendcmdto_mask_butone(sptr, CMD_KICK, chptr->ll_bits, cptr, "%H %C :%s", chptr, who,
+                         comment);
+   sendcmdto_channel_butserv_butone(sptr, CMD_KICK, chptr, NULL, "%H %C :%s", chptr, who,
+@@ -228,7 +228,7 @@
+     }
+   } else {
+     /* Propagate kick... */
+-    sendcmdto_serv_butone(sptr, CMD_KICK, cptr, "%H %C :%s", chptr, who,
++    sendcmdto_mask_butone(sptr, CMD_KICK, chptr->ll_bits, cptr, "%H %C :%s", chptr, who,
+                         comment);
+     if (member) { /* and tell the channel about it */
+Index: ircd/m_server.c
+===================================================================
+RCS file: /home/coder-com/cvs/ircu2.10/ircd/m_server.c,v
+retrieving revision 1.26
+diff -u -r1.26 m_server.c
+--- ircd/m_server.c    2002/03/19 22:03:36     1.26
++++ ircd/m_server.c    2002/04/12 13:47:52
+@@ -181,6 +181,9 @@
+       case 's':
+       SetService(cptr);
+       break;
++      case 'l':
++        SetLazy(cptr);
++      break;
+       }
+   }
+Index: ircd/m_topic.c
+===================================================================
+RCS file: /home/coder-com/cvs/ircu2.10/ircd/m_topic.c,v
+retrieving revision 1.10
+diff -u -r1.10 m_topic.c
+--- ircd/m_topic.c     2002/02/14 00:20:43     1.10
++++ ircd/m_topic.c     2002/04/12 13:47:52
+@@ -115,8 +115,8 @@
+    chptr->topic_time = CurrentTime;
+    /* Fixed in 2.10.11: Don't propergate local topics */
+    if (!IsLocalChannel(chptr->chname))
+-     sendcmdto_serv_butone(sptr, CMD_TOPIC, cptr, "%H :%s", chptr,
+-                         chptr->topic);
++     sendcmdto_mask_butone(sptr, CMD_TOPIC, chptr->ll_bits, cptr, "%H %Tu :%s", chptr,
++                         chptr->topic_time, chptr->topic);
+    if (newtopic)
+       sendcmdto_channel_butserv_butone(sptr, CMD_TOPIC, chptr, NULL,
+                                              "%H :%s", chptr, chptr->topic);
+Index: ircd/parse.c
+===================================================================
+RCS file: /home/coder-com/cvs/ircu2.10/ircd/parse.c,v
+retrieving revision 1.34
+diff -u -r1.34 parse.c
+--- ircd/parse.c       2002/03/19 22:03:36     1.34
++++ ircd/parse.c       2002/04/12 13:47:53
+@@ -577,6 +577,13 @@
+     /* UNREG, CLIENT, SERVER, OPER, SERVICE */
+     { m_ignore, m_ignore, ms_account, m_ignore, m_ignore }
+   },
++  {
++    MSG_FORGET,
++    TOK_FORGET,
++    0, MAXPARA, MFLG_SLOW, 0,
++    /* UNREG, CLIENT, SERVER, OPER, SERVICE */
++    { m_ignore, m_ignore, ms_forget, m_ignore, m_ignore }
++  },
+   /* This command is an alias for QUIT during the unregistered part of
+    * of the server.  This is because someone jumping via a broken web
+    * proxy will send a 'POST' as their first command - which we will
+Index: ircd/s_bsd.c
+===================================================================
+RCS file: /home/coder-com/cvs/ircu2.10/ircd/s_bsd.c,v
+retrieving revision 1.48
+diff -u -r1.48 s_bsd.c
+--- ircd/s_bsd.c       2002/04/03 06:45:49     1.48
++++ ircd/s_bsd.c       2002/04/12 13:47:53
+@@ -465,7 +465,8 @@
+   sendrawto_one(cptr, MSG_SERVER " %s 1 %Tu %Tu J%s %s%s +%s :%s",
+                 cli_name(&me), cli_serv(&me)->timestamp, newts,
+               MAJOR_PROTOCOL, NumServCap(&me),
+-              feature_bool(FEAT_HUB) ? "h" : "", cli_info(&me));
++              feature_bool(FEAT_HUB) ? "h" :
++              feature_bool(FEAT_LAZY_LEAF) ? "l" : "", cli_info(&me));
+   return (IsDead(cptr)) ? 0 : 1;
+ }
+Index: ircd/s_misc.c
+===================================================================
+RCS file: /home/coder-com/cvs/ircu2.10/ircd/s_misc.c,v
+retrieving revision 1.31
+diff -u -r1.31 s_misc.c
+--- ircd/s_misc.c      2002/04/02 00:26:47     1.31
++++ ircd/s_misc.c      2002/04/12 13:47:53
+@@ -48,6 +48,7 @@
+ #include "s_conf.h"
+ #include "s_debug.h"
+ #include "s_user.h"
++#include "s_serv.h"
+ #include "send.h"
+ #include "struct.h"
+ #include "support.h"
+@@ -477,6 +478,8 @@
+     sendto_opmask_butone(0, SNO_NETWORK, "Net break: %C %C (%s)",
+                        cli_serv(victim)->up, victim, comment);
++    if (IsLazy(victim))
++      ll_remove(victim);
+ #if defined(HEAD_IN_SAND_MAP) || defined(HEAD_IN_SAND_LINKS)    
+     map_update(victim);
+ #endif
+Index: ircd/s_serv.c
+===================================================================
+RCS file: /home/coder-com/cvs/ircu2.10/ircd/s_serv.c,v
+retrieving revision 1.28
+diff -u -r1.28 s_serv.c
+--- ircd/s_serv.c      2002/02/14 00:20:44     1.28
++++ ircd/s_serv.c      2002/04/12 13:47:53
+@@ -36,6 +36,7 @@
+ #include "ircd_string.h"
+ #include "ircd_snprintf.h"
+ #include "ircd_xopen.h"
++#include "ircd_log.h"
+ #include "jupe.h"
+ #include "list.h"
+ #include "match.h"
+@@ -61,6 +62,7 @@
+ unsigned int max_connection_count = 0;
+ unsigned int max_client_count = 0;
++unsigned long GlobalLeafBits = 0;
+ int exit_new_server(struct Client *cptr, struct Client *sptr, const char *host,
+                     time_t timestamp, const char *pattern, ...)
+@@ -113,7 +115,8 @@
+     sendrawto_one(cptr, MSG_SERVER " %s 1 %Tu %Tu J%s %s%s +%s :%s",
+                 cli_name(&me), cli_serv(&me)->timestamp,
+                 cli_serv(cptr)->timestamp, MAJOR_PROTOCOL, NumServCap(&me),
+-                feature_bool(FEAT_HUB) ? "h" : "",
++                feature_bool(FEAT_HUB) ? "h" :
++                feature_bool(FEAT_LAZY_LEAF) ? "l" : "",
+                 *(cli_info(&me)) ? cli_info(&me) : "IRCers United");
+     /*
+      * Don't charge this IP# for connecting
+@@ -135,6 +138,9 @@
+   SetBurst(cptr);
++  if (IsLazy(cptr) && !ll_add(cptr))
++    ClearLazy(cptr);
++
+ /*    nextping = CurrentTime; */
+   /*
+@@ -241,6 +247,7 @@
+    * Last, send the BURST.
+    * (Or for 2.9 servers: pass all channels plus statuses)
+    */
++  if (!IsLazy(cptr))
+   {
+     struct Channel *chptr;
+     for (chptr = GlobalChannelList; chptr; chptr = chptr->next)
+@@ -252,3 +259,42 @@
+   return 0;
+ }
++int ll_add(struct Client *cptr)
++{
++  int i = 1;
++
++  assert(IsLazy(cptr));
++
++  while ((GlobalLeafBits & i) && i < 0x80000000)
++    i <<= 1;
++  if (GlobalLeafBits & i) {
++    sendto_opmask_butone(NULL, SNO_OLDSNO, "No more bits for LazyLeaf %s.", cli_name(cptr));
++    return 0;
++  }
++  GlobalLeafBits |= i;
++  cli_serv(cptr)->ll_mask = i;
++  log_write(LS_DEBUG, L_DEBUG, 0, "Added LazyLeaf %s with mask 0x%lx. GlobalLeafBits=0x%lx", cli_name(cptr), i, GlobalLeafBits);
++  return 1;
++}
++
++void ll_remove(struct Client *cptr)
++{
++  struct Channel *chptr;
++
++  assert(IsLazy(cptr));
++
++  for (chptr = GlobalChannelList; chptr; chptr = chptr->next)
++    chptr->ll_bits &= ~cli_serv(cptr)->ll_mask;
++
++  GlobalLeafBits &= ~cli_serv(cptr)->ll_mask;
++  log_write(LS_DEBUG, L_DEBUG, 0, "Removed LazyLeaf %s with mask 0x%lx. GlobalLeafBits=0x%lx", cli_name(cptr), cli_serv(cptr)->ll_mask, GlobalLeafBits);
++}
++
++void ll_check_channel(struct Client *cptr, struct Channel *chptr)
++{
++  if (feature_bool(FEAT_LAZY_LEAF) && MyUser(cptr) && chptr->locals <= 1) {
++    log_write(LS_DEBUG, L_DEBUG, 0, "LazyLeaf: Channel %s has no more locals", chptr->chname);
++    sendcmdto_serv_butone(&me, CMD_FORGET, NULL, "%s", chptr->chname);
++    chptr->mode.mode |= MODE_EMPTY;
++  }
++}
+Index: ircd/send.c
+===================================================================
+RCS file: /home/coder-com/cvs/ircu2.10/ircd/send.c,v
+retrieving revision 1.46
+diff -u -r1.46 send.c
+--- ircd/send.c        2002/02/14 00:20:45     1.46
++++ ircd/send.c        2002/04/12 13:47:53
+@@ -328,6 +328,35 @@
+   msgq_clean(mb);
+ }
++void sendcmdto_mask_butone(struct Client *from, const char *cmd,
++                         const char *tok, unsigned long ll_mask,
++                         struct Client *one,
++                         const char *pattern, ...)
++{
++  struct VarData vd;
++  struct MsgBuf *mb;
++  struct DLink *lp;
++
++  vd.vd_format = pattern; /* set up the struct VarData for %v */
++  va_start(vd.vd_args, pattern);
++
++  /* use token */
++  mb = msgq_make(&me, "%C %s %v", from, tok, &vd);
++  va_end(vd.vd_args);
++
++  /* send it to our downlinks */
++  for (lp = cli_serv(&me)->down; lp; lp = lp->next) {
++    if (one && lp->value.cptr == cli_from(one))
++      continue;
++    if (IsLazy(lp->value.cptr) && !(cli_serv(lp->value.cptr)->ll_mask & ll_mask))
++      continue;
++    send_buffer(lp->value.cptr, mb, 0);
++  }
++
++  msgq_clean(mb);
++}
++
++
+ /*
+  * Send a (prefix) command originating from <from> to all channels
+  * <from> is locally on.  <from> must be a user. <tok> is ignored in
+--- /dev/null  Thu Aug 24 12:00:32 2000
++++ doc/readme.lazylinks       Fri Apr 12 16:47:36 2002
+@@ -0,0 +1,46 @@
++Concept
++~~~~~~~
++The idea behind lazy links is that leafs often don't need much of the
++state information they are sent. Currently, only lazy channels are
++implemented; this means lazy leafs will only be burst channels that
++they have local users on.
++
++Protocol
++~~~~~~~~
++If a leaf has FEAT_LAZY_LEAF set, it sends a +l flag in the SERVER message
++it sends to its hub (note that if FEAT_HUB is also set, it takes precedence
++over FEAT_LAZY_LEAF). The hub will then mark this leaf as 'lazy', and will
++not burst any channels to it. The hub will also keep a bitmask of which leaves
++know which channels. Subsequently, when the leaf tries to announce a channel
++to its hub (via a BURST, JOIN or CREATE) and the leaf doesn't "know" about
++that channel from the hub's point of view, the hub will send a full BURST of
++the channel back to the leaf, and mark the channel as "known" to the leaf.
++Note that a server with FEAT_LAZY_LEAF set *will* accept BURST messages outside
++of net.burst. When a channel has no more local clients, the leaf will send a
++FORGET message to the hub and destroy the channel locally. Upon receipt of this
++meessage, the hub will remove the "known" bit for that channel/leaf pair, and
++it will burst the channel again if the leaf tries to create it later on. The
++FORGET message has the following syntax:
++      <server numeric> FO <#channel>
++
++Code
++~~~~
++struct Server has a ll_mask field which is assigned to each lazy leaf on its
++uplink hub. Every leaf gets a bit, so the maximum number of leafs is 32 on 
++32-bit machines. struct Channel now has a ll_bits bitmask field which stores
++which leaves "know" the channel. A new sendcmd_to_mask_butone function was
++used instead of sendcmdto_serv_butone which doesn't send to lazy leaves that
++don't match the specified mask (currently, chptr->ll_bits).
++
++Bugs
++~~~~
++This documentation is less than complete.
++
++Commands like LIST, TOPIC, MODE issued on a lazy leaf for channels that hasn't
++been burst to it will incorrectly report the channels doesn't exist. This should
++be handled by forwarding those messages to its uplink.
++
++joinbuf_flush now sends each join/part as a separate message, because they each
++have to be matched against the leaves' "known channel" bits.
++
++Probably more.
+--- /dev/null  Thu Aug 24 12:00:32 2000
++++ ircd/m_forget.c    Wed Apr  3 23:07:14 2002
+@@ -0,0 +1,123 @@
++/*
++ * IRC - Internet Relay Chat, ircd/m_forget.c
++ * Copyright (C) 2002 Alex Badea <vampire@p16.pub.ro>
++ *
++ * See file AUTHORS in IRC package for additional names of
++ * the programmers.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 1, or (at your option)
++ * any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ * $Id: lazy.diff,v 1.2 2002/04/12 13:50:27 vampire Exp $
++ */
++
++/*
++ * m_functions execute protocol messages on this server:
++ *
++ *    cptr    is always NON-NULL, pointing to a *LOCAL* client
++ *            structure (with an open socket connected!). This
++ *            identifies the physical socket where the message
++ *            originated (or which caused the m_function to be
++ *            executed--some m_functions may call others...).
++ *
++ *    sptr    is the source of the message, defined by the
++ *            prefix part of the message if present. If not
++ *            or prefix not found, then sptr==cptr.
++ *
++ *            (!IsServer(cptr)) => (cptr == sptr), because
++ *            prefixes are taken *only* from servers...
++ *
++ *            (IsServer(cptr))
++ *                    (sptr == cptr) => the message didn't
++ *                    have the prefix.
++ *
++ *                    (sptr != cptr && IsServer(sptr) means
++ *                    the prefix specified servername. (?)
++ *
++ *                    (sptr != cptr && !IsServer(sptr) means
++ *                    that message originated from a remote
++ *                    user (not local).
++ *
++ *            combining
++ *
++ *            (!IsServer(sptr)) means that, sptr can safely
++ *            taken as defining the target structure of the
++ *            message in this server.
++ *
++ *    *Always* true (if 'parse' and others are working correct):
++ *
++ *    1)      sptr->from == cptr  (note: cptr->from == cptr)
++ *
++ *    2)      MyConnect(sptr) <=> sptr == cptr (e.g. sptr
++ *            *cannot* be a local connection, unless it's
++ *            actually cptr!). [MyConnect(x) should probably
++ *            be defined as (x == x->from) --msa ]
++ *
++ *    parc    number of variable parameter strings (if zero,
++ *            parv is allowed to be NULL)
++ *
++ *    parv    a NULL terminated list of parameter pointers,
++ *
++ *                    parv[0], sender (prefix string), if not present
++ *                            this points to an empty string.
++ *                    parv[1]...parv[parc-1]
++ *                            pointers to additional parameters
++ *                    parv[parc] == NULL, *always*
++ *
++ *            note:   it is guaranteed that parv[0]..parv[parc-1] are all
++ *                    non-NULL pointers.
++ */
++#include "config.h"
++
++#include "client.h"
++#include "hash.h"
++#include "ircd.h"
++#include "ircd_reply.h"
++#include "ircd_string.h"
++#include "msg.h"
++#include "numeric.h"
++#include "numnicks.h"
++#include "send.h"
++#include "channel.h"
++#include "ircd_log.h"
++
++#include <assert.h>
++#include <stdlib.h>
++
++/*
++ * ms_forget - server message handler
++ */
++int ms_forget(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
++{
++  struct Channel *chptr;
++
++  assert(0 != cptr);
++  assert(0 != sptr);
++  assert(IsServer(cptr));
++
++  if (parc < 2)
++    return need_more_params(sptr, "FORGET");
++
++  /*
++   * Only lazy leafs may forget about channels.
++   * Ignore forget messages for channels that don't exist.
++   */
++  if (!IsLazy(cptr) || !(chptr = FindChannel(parv[1])))
++    return 0;
++
++  chptr->ll_bits &= ~cli_serv(cptr)->ll_mask;
++  log_write(LS_DEBUG, L_DEBUG, 0, "LazyLeaf %s forgot about %s", cli_name(cptr), chptr->chname);
++
++  return 0;
++}
diff --git a/patches/diffs/login-on-connect.diff b/patches/diffs/login-on-connect.diff
new file mode 100644 (file)
index 0000000..8fad5db
--- /dev/null
@@ -0,0 +1,576 @@
+Index: ChangeLog
+===================================================================
+RCS file: /home/coder-com/cvs/ircu2.10/ChangeLog,v
+retrieving revision 1.340
+diff -u -r1.340 ChangeLog
+--- ChangeLog  2002/04/12 00:19:52     1.340
++++ ChangeLog  2002/04/12 13:17:10
+@@ -1,5 +1,33 @@
+ 2002-04-12  Alex Badea  <vampire@p16.pub.ro>
++      * include/ircd_features.h: new feature LOGIN_ON_CONNECT
++
++      * ircd/ircd_features.c: new feature LOGIN_ON_CONNECT
++
++      * include/client.h (struct Client): new fields for storing
++      bot name, username and password for login-on-connect
++
++      * ircd/m_account.c: extensions for login-on-connect: route
++      and process auth-request and auth-reply messages
++
++      * ircd/m_pass.c: store bot name, username and password for
++      service login
++
++      * ircd/m_user.c: store username/hostname for the client
++      even if he finished registration, as register_user may not
++      do that anymore
++
++      * ircd/s_user.c (register_user): if the client specified
++      a service login in the PASS command, attempt to log him in;
++      also, don't set his hostname if it was set remotely by a
++      service bot
++
++      * doc/example.conf: default value for FEAT_LOGIN_ON_CONNECT
++
++      * doc/readme.features: documented FEAT_LOGIN_ON_CONNECT
++
++2002-04-12  Alex Badea  <vampire@p16.pub.ro>
++
+       * ircd/m_invite.c: don't propagate invites for local channels
+       * include/patchlevel.h (PATCHLEVEL): bump patchlevel
+Index: doc/example.conf
+===================================================================
+RCS file: /home/coder-com/cvs/ircu2.10/doc/example.conf,v
+retrieving revision 1.20
+diff -u -r1.20 example.conf
+--- doc/example.conf   2002/04/03 15:23:47     1.20
++++ doc/example.conf   2002/04/12 13:17:10
+@@ -702,6 +702,7 @@
+ #  "HOST_HIDING"="FALSE";
+ #  "HIDDEN_HOST"="users.undernet.org";
+ #  "HIDDEN_IP"="127.0.0.1";
++#  "LOGIN_ON_CONNECT"="FALSE";
+ #  "KILLCHASETIMELIMIT"="30";
+ #  "MAXCHANNELSPERUSER"="10";
+ #  "AVBANLEN"="40";
+Index: doc/readme.features
+===================================================================
+RCS file: /home/coder-com/cvs/ircu2.10/doc/readme.features,v
+retrieving revision 1.5
+diff -u -r1.5 readme.features
+--- doc/readme.features        2002/04/03 15:23:47     1.5
++++ doc/readme.features        2002/04/12 13:17:10
+@@ -242,6 +242,13 @@
+ This selects a fake IP to be shown on /USERIP and /WHO %i when the
+ target has a hidden host (see HOST_HIDING).
++LOGIN_ON_CONNECT
++  * Type: boolean
++  * Default: FALSE
++
++This selects whether local clients can use specify a service bot login
++in the connection phase. Read readme.login-on-connect for more details.
++
+ KILLCHASETIMELIMIT
+  * Type: integer
+  * Default: 30
+Index: include/client.h
+===================================================================
+RCS file: /home/coder-com/cvs/ircu2.10/include/client.h,v
+retrieving revision 1.26
+diff -u -r1.26 client.h
+--- include/client.h   2002/04/05 11:36:58     1.26
++++ include/client.h   2002/04/12 13:17:10
+@@ -196,6 +196,10 @@
+   char cli_name[HOSTLEN + 1];   /* Unique name of the client, nick or host */
+   char cli_username[USERLEN + 1]; /* username here now for auth stuff */
+   char cli_info[REALLEN + 1];   /* Free form additional client information */
++  
++  char *cli_cs_user;          /* channel service authentication (user)... */
++  char *cli_cs_pass;          /* ...and password... */
++  char *cli_cs_service;               /* ...and the service bot's nick */
+ };
+ #define CLIENT_MAGIC 0x4ca08286
+Index: include/ircd_features.h
+===================================================================
+RCS file: /home/coder-com/cvs/ircu2.10/include/ircd_features.h,v
+retrieving revision 1.15
+diff -u -r1.15 ircd_features.h
+--- include/ircd_features.h    2002/04/03 15:23:47     1.15
++++ include/ircd_features.h    2002/04/12 13:17:10
+@@ -45,6 +45,7 @@
+   FEAT_HOST_HIDING,
+   FEAT_HIDDEN_HOST,
+   FEAT_HIDDEN_IP,
++  FEAT_LOGIN_ON_CONNECT,
+   /* features that probably should not be touched */
+   FEAT_KILLCHASETIMELIMIT,
+Index: ircd/ircd_features.c
+===================================================================
+RCS file: /home/coder-com/cvs/ircu2.10/ircd/ircd_features.c,v
+retrieving revision 1.19
+diff -u -r1.19 ircd_features.c
+--- ircd/ircd_features.c       2002/04/03 15:23:48     1.19
++++ ircd/ircd_features.c       2002/04/12 13:17:10
+@@ -252,6 +252,7 @@
+   F_B(HOST_HIDING, 0, 0, 0),
+   F_S(HIDDEN_HOST, FEAT_CASE, "users.undernet.org", 0),
+   F_S(HIDDEN_IP, 0, "127.0.0.1", 0),
++  F_B(LOGIN_ON_CONNECT, 0, 0, 0),
+   /* features that probably should not be touched */
+   F_I(KILLCHASETIMELIMIT, 0, 30, 0),
+Index: ircd/m_account.c
+===================================================================
+RCS file: /home/coder-com/cvs/ircu2.10/ircd/m_account.c,v
+retrieving revision 1.2
+diff -u -r1.2 m_account.c
+--- ircd/m_account.c   2002/02/14 00:20:42     1.2
++++ ircd/m_account.c   2002/04/12 13:17:10
+@@ -84,9 +84,11 @@
+ #include "ircd.h"
+ #include "ircd_reply.h"
+ #include "ircd_string.h"
++#include "ircd_alloc.h"
+ #include "msg.h"
+ #include "numnicks.h"
+ #include "s_user.h"
++#include "s_debug.h"
+ #include "send.h"
+ #include <assert.h>
+@@ -96,35 +98,108 @@
+  *
+  * parv[0] = sender prefix
+  * parv[1] = numeric of client to act on
+- * parv[2] = account name (12 characters or less)
++ * parv[2] = message type
++ *
++ * for *parv[2] == 'R' (remote auth):
++ * parv[3] = account name (12 characters or less)
++ *
++ * for *parv[2] == 'C' (auth check):
++ * parv[3] = numeric of client to check
++ * parv[4] = username
++ * parv[parc-1] = password
++ *
++ * for *parv[2] == 'A' (auth ok) or
++ * for *parv[2] == 'D' (auth denied) or
++ * parv[3] = numeric of client to check 
+  */
+ int ms_account(struct Client* cptr, struct Client* sptr, int parc,
+              char* parv[])
+ {
+   struct Client *acptr;
++  char type;
+   if (parc < 3)
+     return need_more_params(sptr, "ACCOUNT");
++  
++  if (parc < 4) {
++    /* old-style message, remap it */
++    parv[4] = NULL;
++    parv[3] = parv[2];
++    parv[2] = "R";
++  }
+   if (!IsServer(sptr))
+     return protocol_violation(cptr, "ACCOUNT from non-server %s",
+                             cli_name(sptr));
+-
+-  if (!(acptr = findNUser(parv[1])))
+-    return 0; /* Ignore ACCOUNT for a user that QUIT; probably crossed */
+-
+-  if (IsAccount(acptr))
+-    return protocol_violation(cptr, "ACCOUNT for already registered user %s "
+-                            "(%s -> %s)", cli_name(acptr),
+-                            cli_user(acptr)->account, parv[2]);
+-
+-  assert(0 == cli_user(acptr)->account[0]);
+-
+-  ircd_strncpy(cli_user(acptr)->account, parv[2], ACCOUNTLEN);
+-  hide_hostmask(acptr, FLAGS_ACCOUNT);
+-  sendcmdto_serv_butone(sptr, CMD_ACCOUNT, cptr, "%C %s", acptr,
+-                      cli_user(acptr)->account);
++  type = *parv[2];
++  if (type == 'R') {
++    if (!(acptr = findNUser(parv[1])))
++      return 0; /* Ignore ACCOUNT for a user that QUIT; probably crossed */
++
++    if (IsAccount(acptr))
++      return protocol_violation(cptr, "ACCOUNT for already registered user %s "
++                              "(%s -> %s)", cli_name(acptr),
++                              cli_user(acptr)->account, parv[3]);
++
++    assert(0 == cli_user(acptr)->account[0]);
++
++    ircd_strncpy(cli_user(acptr)->account, parv[3], ACCOUNTLEN);
++    hide_hostmask(acptr, FLAGS_ACCOUNT);
++
++#if 0
++    /* XXX Enable this when all servers speak the same language */
++    sendcmdto_serv_butone(sptr, CMD_ACCOUNT, cptr, "%C R %s", acptr,
++                        cli_user(acptr)->account);
++#else
++    sendcmdto_serv_butone(sptr, CMD_ACCOUNT, cptr, "%C %s", acptr,
++                        cli_user(acptr)->account);
++#endif
++  } else {
++    if (!(acptr = findNUser(parv[1])) && !(acptr = FindNServer(parv[1])))
++      return 0;
++
++    if (type == 'C' && parc < 6)
++      return need_more_params(sptr, "ACCOUNT");
++
++    if (!IsMe(acptr)) {
++      /* in-transit message, forward it */
++      sendcmdto_one(sptr, CMD_ACCOUNT, acptr,
++                  type == 'C' ? "%C %s %s %s :%s" : "%C %s %s",
++                  acptr, parv[2], parv[3], parv[4], parv[parc-1]);
++      return 0;
++    }
++    
++    /* the message is for me, process it */
++    if (type == 'C')
++      return protocol_violation(cptr, "ACCOUNT check (%s %s %s)", parv[3], parv[4], parv[parc-1]);
++
++    if (!(acptr = findNUser(parv[3])))
++      return 0;
++    if (IsRegistered(acptr) || !acptr->cli_cs_service)
++      return protocol_violation(cptr, "Invalid ACCOUNT %s for %s", parv[2], cli_name(acptr));
++    
++    if (type == 'A') {
++      ircd_strncpy(cli_user(acptr)->account, acptr->cli_cs_user, ACCOUNTLEN);
++      hide_hostmask(acptr, FLAGS_ACCOUNT | FLAGS_HIDDENHOST);
++    }
++    
++    sendcmdto_one(&me, CMD_NOTICE, acptr, "%C :AUTHENTICATION %s as %s", acptr,
++                type == 'A' ? "SUCCESSFUL" : "FAILED",
++                acptr->cli_cs_user);
++
++    MyFree(acptr->cli_cs_service);
++    MyFree(acptr->cli_cs_user);
++    MyFree(acptr->cli_cs_pass);
++    acptr->cli_cs_service = acptr->cli_cs_user = acptr->cli_cs_pass = NULL;
++
++    if (type != 'A') {
++      sendcmdto_one(&me, CMD_NOTICE, acptr, "%C :Type /QUOTE PASS to connect anyway", acptr);
++      return 0;
++    }
++    
++    return register_user(acptr, acptr, cli_name(acptr), cli_user(acptr)->username);
++  }
+   return 0;
+ }
+Index: ircd/m_pass.c
+===================================================================
+RCS file: /home/coder-com/cvs/ircu2.10/ircd/m_pass.c,v
+retrieving revision 1.7
+diff -u -r1.7 m_pass.c
+--- ircd/m_pass.c      2001/06/29 15:51:02     1.7
++++ ircd/m_pass.c      2002/04/12 13:17:10
+@@ -84,7 +84,11 @@
+ #include "client.h"
+ #include "ircd_reply.h"
+ #include "ircd_string.h"
++#include "ircd_alloc.h"
++#include "ircd_features.h"
++#include "s_user.h"
+ #include "send.h"
++#include "struct.h"
+ #include <assert.h>
+@@ -99,15 +103,28 @@
+   assert(cptr == sptr);
+   assert(!IsRegistered(sptr));
+-  if (EmptyString(password))
+-    return need_more_params(cptr, "PASS");
+-
+   /* TODO: For protocol negotiation */
+ #if 0
+   if (ircd_strcmp(password,"PROT")==0) {
+       /* Do something here */
+   }
+ #endif
+-  ircd_strncpy(cli_passwd(cptr), password, PASSWDLEN);
++
++  if (!EmptyString(password))
++    ircd_strncpy(cli_passwd(cptr), password, PASSWDLEN);
++
++  if (!feature_bool(FEAT_LOGIN_ON_CONNECT) || cptr->cli_cs_service)
++    return 0;
++
++  if (parc > 3) {
++    DupString(cptr->cli_cs_service, parv[parc-3]);
++    DupString(cptr->cli_cs_user, parv[parc-2]);
++    DupString(cptr->cli_cs_pass, parv[parc-1]);
++  }
++
++  /* Deal with password retries */
++  if ((cli_name(cptr))[0] && cli_cookie(cptr) == COOKIE_VERIFIED)
++    return register_user(cptr, cptr, cli_name(cptr), cli_user(cptr)->username);
++
+   return 0;
+ }
+Index: ircd/m_user.c
+===================================================================
+RCS file: /home/coder-com/cvs/ircu2.10/ircd/m_user.c,v
+retrieving revision 1.7
+diff -u -r1.7 m_user.c
+--- ircd/m_user.c      2001/06/08 23:12:17     1.7
++++ ircd/m_user.c      2002/04/12 13:17:10
+@@ -142,16 +142,14 @@
+   user->server = &me;
+   ircd_strncpy(cli_info(cptr), info, REALLEN);
++  ircd_strncpy(user->username, username, USERLEN);
++  ircd_strncpy(user->host, cli_sockhost(cptr), HOSTLEN);
+   if ((cli_name(cptr))[0] && cli_cookie(cptr) == COOKIE_VERIFIED) {
+     /*
+      * NICK and PONG already received, now we have USER...
+      */
+     return register_user(cptr, sptr, cli_name(sptr), username);
+-  }
+-  else {
+-    ircd_strncpy(user->username, username, USERLEN);
+-    ircd_strncpy(user->host, cli_sockhost(cptr), HOSTLEN);
+   }
+   return 0;
+ }
+Index: ircd/s_user.c
+===================================================================
+RCS file: /home/coder-com/cvs/ircu2.10/ircd/s_user.c,v
+retrieving revision 1.58
+diff -u -r1.58 s_user.c
+--- ircd/s_user.c      2002/04/05 11:36:59     1.58
++++ ircd/s_user.c      2002/04/12 13:17:10
+@@ -394,6 +394,25 @@
+   parv[0] = cli_name(sptr);
+   parv[1] = parv[2] = NULL;
++  if (MyConnect(sptr) && sptr->cli_cs_service && sptr->cli_cs_user && sptr->cli_cs_pass) {
++    struct Client *acptr;
++    
++    if (!(acptr = FindUser(sptr->cli_cs_service)) || !IsChannelService(acptr)) {
++      sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :Service '%s' is not available", sptr, sptr->cli_cs_service);
++      sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :Type /QUOTE PASS to connect anyway", sptr);
++      MyFree(sptr->cli_cs_service);
++      MyFree(sptr->cli_cs_user);
++      MyFree(sptr->cli_cs_pass);
++      sptr->cli_cs_service = sptr->cli_cs_user = sptr->cli_cs_pass = NULL;
++    } else {
++      sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :Attempting service login to %s",
++                          sptr, cli_name(acptr));
++      sendcmdto_one(&me, CMD_ACCOUNT, acptr, "%C C %s%s %s :%s", acptr,
++                  NumNick(sptr), sptr->cli_cs_user, sptr->cli_cs_pass);
++    }
++    return 0;
++  }
++
+   if (MyConnect(sptr))
+   {
+     static time_t last_too_many1;
+@@ -441,7 +460,9 @@
+         IPcheck_connect_fail(cli_ip(sptr));
+         return exit_client(cptr, sptr, &me, "Unknown error -- Try again");
+     }
+-    ircd_strncpy(user->host, cli_sockhost(sptr), HOSTLEN);
++    /* The host might be already set from login-on-connect */
++    if (!HasHiddenHost(sptr))
++          ircd_strncpy(user->host, cli_sockhost(sptr), HOSTLEN);
+     ircd_strncpy(user->realhost, cli_sockhost(sptr), HOSTLEN);
+     aconf = cli_confs(sptr)->value.aconf;
+--- /dev/null  Thu Aug 24 12:00:32 2000
++++ doc/readme.login-on-connect        Fri Apr 12 16:16:56 2002
+@@ -0,0 +1,182 @@
++1. This feature is experimental.
++
++2. The main point is to allow clients to log in to a service bot (i.e., X)
++*before* being announced to the network. Otherwise, a combination of a
++malicious user, /ISON, /USERIP and low latency can reveal it's real host/IP
++before he gets a chance to log in and set himself +x
++
++3. Client<->Server changes:
++~~~~~~~~~~~~~~~~~~~~~~~~~~~
++The PASS command now has the following syntax:
++
++PASS [optional Client block password] <bot nick> <username> :<passphrase>
++
++If the client specifies sends such a password message, after sending NICK,
++USER and PONG, it's username/passphrase are sent to the specified bot
++for validation, while holding the client in the 'registration' state.
++If the authentication succeeds, the client's account and umode +x are set,
++after which he is introduced to the network, continuing the regular connect
++phase. If authentication fails (or the bot is not on the network), the user
++is given a chance to retry (he can do this by sending another PASS command),
++or to disconnect from the server. If he wishes to connect without a hidden
++hostmask, he can send a PASS command with no parameters.
++
++4. Server<->Server changes:
++~~~~~~~~~~~~~~~~~~~~~~~~~~~
++The ACCOUNT message now has the following syntax:
++
++Auth check: 
++<client's server numeric> AC <bot's numeric> C <client's numeric> <username> :<passphrase>
++Servers send this message to request a service bot to authenticate the client.
++Note that <client's numeric> will only be used by the originating server for
++matching auth replies, as the user has not yet been announced to the network.
++Hubs will have to propagate this message as-is towards the service bot,
++much like they do for PRIVMSGs.
++
++Auth reply:
++<bot's server numeric> AC <client's server numeric> A|D <client's numeric>
++Service bots send this in reply to an 'auth check' message from a server.
++"A" stands for "accepted", "D" for "denied". Again, hubs will have
++to proagate this message back to the client's server.
++
++Remote auth:
++<bot's server numeric> AC <client numeric> R <account>
++This is the current message used by service bots to announce the network
++that a user has logged in. The old format is still supported:
++<bot's server numeric> AC <client numeric> <account>
++
++5. ircu code changes
++~~~~~~~~~~~~~~~~~~~~
++A new feature, FEAT_LOGIN_ON_CONNECT (default FALSE) will specify whether
++ircu will honour the login scheme as specified above for the PASS command.
++ircu will route ACCOUNT messages anyway, regardless of this feature's value.
++
++6. GNUWorld patches
++~~~~~~~~~~~~~~~~~~~
++A patch follows that will implement auth checks and replies.
++
++Index: mod.cservice/cservice.cc
++===================================================================
++RCS file: /cvsroot/gnuworld/gnuworld/mod.cservice/cservice.cc,v
++retrieving revision 1.213
++diff -u -r1.213 cservice.cc
++--- mod.cservice/cservice.cc  10 Apr 2002 19:00:10 -0000      1.213
+++++ mod.cservice/cservice.cc  12 Apr 2002 12:33:45 -0000
++@@ -2491,15 +2491,45 @@
++      {
++      case EVT_ACCOUNT:
++              {
++-             iClient* tmpUser = static_cast< iClient* >( data1 ) ;
++-             networkData* tmpData = static_cast< networkData* >(tmpUser->getCustomData(this) ) ;
++-             /* Lookup this user account, if its not there.. trouble */
++-             sqlUser* theUser = getUserRecord(tmpUser->getAccount());
++-             if (theUser)
++-                     {
++-                     tmpData->currentUser = theUser;
++-                     theUser->addAuthedClient(tmpUser);
+++             char *ac_type = static_cast <char *> (data1);
+++             if (*ac_type == 'R') {
+++                     iClient* tmpUser = static_cast< iClient* >( data2 ) ;
+++                     networkData* tmpData = static_cast< networkData* >(tmpUser->getCustomData(this) ) ;
+++                     /* Lookup this user account, if its not there.. trouble */
+++                     sqlUser* theUser = getUserRecord(tmpUser->getAccount());
+++                     if (theUser)
+++                             {
+++                             tmpData->currentUser = theUser;
+++                             theUser->addAuthedClient(tmpUser);
+++                             }
+++             } else if (*ac_type == 'C') {
+++                     // server prefix, client prefix, username, password
+++                     char **param_list = static_cast <char **> (data2);
+++                     sqlUser* theUser = getUserRecord(param_list[2]);
+++                     strstream ac;
+++
+++                     LogDebugMessage("Checking account: user=%s pass=%s ok=%d susp=%d maxlog=%d/%d",
+++                             param_list[2],
+++                             param_list[3],
+++                             isPasswordRight(theUser, param_list[3]),
+++                             theUser->getFlag(sqlUser::F_GLOBAL_SUSPEND),
+++                             theUser->networkClientList.size() + 1,
+++                             theUser->getMaxLogins());
+++
+++                     ac << getCharYY() << " AC " << param_list[0];
+++                     
+++                     if (theUser && !theUser->getFlag(sqlUser::F_GLOBAL_SUSPEND) &&
+++                             isPasswordRight(theUser, param_list[3]) &&
+++                             theUser->networkClientList.size() + 1 <= theUser->getMaxLogins()) {
+++                             ac << " A ";
+++                     } else {
+++                             ac << " D ";
++                      }
+++
+++                     ac << param_list[1] << ends;
+++                     Write(ac);
+++                     delete[] ac.str();
+++             }
++              break;
++              }
++      case EVT_BURST_ACK:
++Index: src/msg_AC.cc
++===================================================================
++RCS file: /cvsroot/gnuworld/gnuworld/src/msg_AC.cc,v
++retrieving revision 1.1
++diff -u -r1.1 msg_AC.cc
++--- src/msg_AC.cc     12 Jan 2002 21:42:17 -0000      1.1
+++++ src/msg_AC.cc     12 Apr 2002 12:33:46 -0000
++@@ -14,23 +14,48 @@
++  * SOURCE AC TARGET ACCOUNT
++  * Eg:
++  * AXAAA AC BQrTd Gte
+++ *
+++ * AX AC BQrTd R Gte
+++ * BQ AC AX C BqrTd Gte :Gte's Pass
++  */
++-int xServer::MSG_AC( xParameters& Param )
+++int xServer::MSG_AC(xParameters &Param)
++ {
++ /*
++  * First, update this users information.
++  */
++ 
++-iClient* theClient = Network->findClient(Param[1]);
++-if(!theClient)
++-     {
++-             return 0;
++-     }
+++const char *numeric = NULL, *account = NULL;
+++static char *ac_type_C = "C";
+++static char *ac_type_R = "R";
++ 
++-theClient->setAccount(Param[2]);
+++if (Param.size() < 4) {
+++     numeric = Param[1];
+++     account = Param[2];
+++} else if (Param[2][0] == 'R') {
+++     numeric = Param[1];
+++     account = Param[3];
+++} else if (Param[2][0] == 'C') {
+++     const char *param_list[4];
+++     param_list[0] = Param[0];
+++     param_list[1] = Param[3];
+++     param_list[2] = Param[4];
+++     param_list[3] = Param[5];
+++     PostEvent(EVT_ACCOUNT, static_cast <void *> (ac_type_C), static_cast <void *> (param_list));
+++     return 0;
+++}
+++
+++if (!numeric || !account)
+++     return 0;
+++
+++iClient *theClient = Network->findClient(numeric);
+++if (!theClient)
+++     return 0;
+++
+++theClient->setAccount(account);
+++PostEvent(EVT_ACCOUNT, static_cast <void *> (ac_type_R), static_cast <void *> (theClient)) ;
++ 
++-PostEvent( EVT_ACCOUNT, static_cast< void* >( theClient ) ) ;
++ return 0;
+++
++ }
++ 
++ } // namespace gnuworld
diff --git a/patches/diffs/sline.diff b/patches/diffs/sline.diff
new file mode 100644 (file)
index 0000000..ade385d
--- /dev/null
@@ -0,0 +1,221 @@
+diff -urdb doc/example.conf ircu2.10.11.06/doc/example.conf
+--- doc/example.conf   Wed Jan 28 22:28:05 2004
++++ doc/example.conf   Wed Jan 28 23:20:26 2004
+@@ -365,6 +365,30 @@
+ # Y:10:90:0:100:160000
++# [S:lines]
++# Opers may wish to hide their IP mask and hostname, even if they are on
++# a bnc. This can prevent the risk of opers or their providers getting
++# dos'd or whatever the case may be.
++#
++# When a client connects, his or her IP is compared to the incoming_IP in 
++# each of the S:lines in the conf. If it finds an exact match (NOT a mask 
++# match, but a simple comparison), it will substitute the client's ip with 
++# modified_IP and the client's real hostname with modified_hostname (as 
++# shown below).
++#
++# Syntax:
++# S:<incoming_IP>:<modified_IP>:<modifed_hostname>
++#
++# Example:
++# S:193.178.138.13:192.168.128.1:undernet.org
++#
++# If a user connects to the server with the IP 193.178.138.13, it is
++# automatically changed to 192.168.128.1 and the user's host is set to
++# undernet.org.
++#
++# If no modified_IP is provided, only the host is modified.
++
++
+ # [P:lines]
+ # When your server gets more full, you will notice delays when trying to
+ # connect to your server's primary listening port. It is possible via the
+diff -urdb include/client.h ircu2.10.11.06/include/client.h
+--- include/client.h   Wed Jan 28 22:28:05 2004
++++ include/client.h   Wed Jan 28 23:20:26 2004
+@@ -127,6 +127,7 @@
+     FLAG_GOTID,                     /* successful ident lookup achieved */
+     FLAG_DOID,                      /* I-lines say must use ident return */
+     FLAG_NONL,                      /* No \n in buffer */
++    FLAG_SLINE,                     /* User is S-lined */
+     FLAG_TS8,                       /* Why do you want to know? */
+     FLAG_MAP,                       /* Show server on the map */
+     FLAG_JUNCTION,                  /* Junction causing the net.burst */
+@@ -429,6 +430,7 @@
+ #define IsAccount(x)            HasFlag(x, FLAG_ACCOUNT)
+ #define IsHiddenHost(x)               HasFlag(x, FLAG_HIDDENHOST)
+ #define HasHiddenHost(x)      (IsAccount(x) && IsHiddenHost(x))
++#define HasSLine(x)             HasFlag(x, FLAG_SLINE)
+ #define IsPrivileged(x)         (IsAnOper(x) || IsServer(x))
+@@ -451,6 +453,7 @@
+ #define SetService(x)           SetFlag(x, FLAG_SERVICE)
+ #define SetAccount(x)           SetFlag(x, FLAG_ACCOUNT)
+ #define SetHiddenHost(x)      SetFlag(x, FLAG_HIDDENHOST)
++#define SetSLined(x)            SetFlag(x, FLAG_SLINE)
+ #define ClearAccess(x)          ClrFlag(x, FLAG_CHKACCESS)
+ #define ClearBurst(x)           ClrFlag(x, FLAG_BURST)
+diff -urdb include/s_conf.h ircu2.10.11.06/include/s_conf.h
+--- include/s_conf.h   Wed Jan 28 22:28:05 2004
++++ include/s_conf.h   Wed Jan 28 23:20:26 2004
+@@ -33,6 +33,7 @@
+ #define CONF_ILLEGAL            0x80000000
+ #define CONF_MATCH              0x40000000
++#define CONF_SPOOF              0x20000000
+ #define CONF_CLIENT             0x0002
+ #define CONF_SERVER             0x0004
+ #define CONF_LOCOP              0x0010
+diff -urdb ircd/s_auth.c ircu2.10.11.06/ircd/s_auth.c
+--- ircd/s_auth.c      Wed Jan 28 22:28:05 2004
++++ ircd/s_auth.c      Wed Jan 28 23:20:26 2004
+@@ -46,6 +46,7 @@
+ #include "querycmds.h"
+ #include "res.h"
+ #include "s_bsd.h"
++#include "s_conf.h"
+ #include "s_debug.h"
+ #include "s_misc.h"
+ #include "send.h"
+@@ -82,6 +83,7 @@
+   { "NOTICE AUTH :*** No ident response\r\n",              36 },
+   { "NOTICE AUTH :*** Your forward and reverse DNS do not match, " \
+     "ignoring hostname.\r\n",                              80 },
++  { "NOTICE AUTH :*** Using S-line privilege\r\n",         41 },
+   { "NOTICE AUTH :*** Invalid hostname\r\n",               35 }
+ };
+@@ -94,6 +96,7 @@
+   REPORT_FIN_ID,
+   REPORT_FAIL_ID,
+   REPORT_IP_MISMATCH,
++  REPORT_USING_SLINE,
+   REPORT_INVAL_DNS
+ } ReportType;
+@@ -595,6 +598,13 @@
+   struct AuthRequest* auth = 0;
+   assert(0 != client);
++
++  if (conf_check_slines(client)) {
++    sendheader(client, REPORT_USING_SLINE);
++    SetSLined(client);
++    release_auth_client(client);
++    return;
++  }
+   auth = make_auth_request(client);
+   assert(0 != auth);
+diff -urdb ircd/s_conf.c ircu2.10.11.06/ircd/s_conf.c
+--- ircd/s_conf.c      Wed Jan 28 22:28:05 2004
++++ ircd/s_conf.c      Wed Jan 28 23:20:26 2004
+@@ -1170,6 +1170,10 @@
+       conf_add_quarantine(field_vector, field_count);
+       aconf->status = CONF_ILLEGAL;
+       break;
++    case 'S':
++    case 's':
++      aconf->status = CONF_SPOOF;
++      break;
+     case 'T':                /* print out different motd's */
+     case 't':                /* based on hostmask - CONF_TLINES */
+       motd_add(field_vector[1], field_vector[2]);
+@@ -1272,6 +1276,9 @@
+     if ((aconf->status == CONF_UWORLD) && (aconf->passwd) && (*aconf->passwd))
+       addNickJupes(aconf->passwd);
++    if (aconf->status & CONF_SPOOF)
++      lookup_confhost(aconf);
++
+     collapse(aconf->host);
+     collapse(aconf->name);
+     Debug((DEBUG_NOTICE,
+@@ -1647,6 +1654,70 @@
+     c_conf->ipnum.s_addr = cli_ip(cptr).s_addr;
+   Debug((DEBUG_DNS, "sv_cl: access ok: %s[%s]", cli_name(cptr), cli_sockhost(cptr)));
++  return 0;
++}
++
++/*
++ * conf_check_slines()
++ *
++ * Check S lines for the specified client, passed in cptr struct.
++ * If the client's IP is S-lined, process the substitution here.
++ * 1. cptr->cli_ip                    (cli_ip(cptr))
++ * 2. cptr->cli_connect->con_sock_ip  (cli_sock_ip(cptr))
++ * 3. cptr->cli_connect->sockhost     (cli_sockhost(cptr))
++ *
++ * If no substitued IP are specified, only change sockhost.
++ *
++ * Precondition
++ *  cptr != NULL
++ *
++ * Returns
++ *  0 = No S-line found
++ *  1 = S-line found and substitution done.
++ *
++ * -mbuna 9/2001
++ *
++ */
++
++int
++conf_check_slines(struct Client *cptr)
++{
++  struct ConfItem* aconf;
++  struct in_addr iptemp;
++  char* hostonly;
++
++  for (aconf = GlobalConfList; aconf; aconf = aconf->next) {
++    if (aconf->status != CONF_SPOOF)
++      continue;
++    if ((aconf->dns_pending)
++      || (INADDR_NONE == aconf->ipnum.s_addr)
++      || EmptyString(aconf->name))
++      continue;
++
++    if (cli_ip(cptr).s_addr == aconf->ipnum.s_addr) {
++
++                               /* Ignore user part if u@h. */
++      if ((hostonly = strchr(aconf->name, '@')))
++        hostonly++;
++      else
++        hostonly = aconf->name;
++
++      if(!*hostonly)
++        continue;
++
++      if (!EmptyString(aconf->passwd)) {
++        iptemp.s_addr = inet_addr(aconf->passwd);
++        if (INADDR_NONE == iptemp.s_addr)
++          continue;
++        cli_ip(cptr).s_addr = iptemp.s_addr;
++      }
++
++                               /* Perform a luxurious ircd_ntoa for sanity. */
++      ircd_strncpy(cli_sock_ip(cptr), ircd_ntoa((const char*) &cli_ip(cptr)), SOCKIPLEN);
++      ircd_strncpy(cli_sockhost(cptr), hostonly, HOSTLEN);
++      return 1;
++    }
++  }
+   return 0;
+ }
+diff -urdb ircd/s_user.c ircu2.10.11.06/ircd/s_user.c
+--- ircd/s_user.c      Wed Jan 28 22:28:05 2004
++++ ircd/s_user.c      Wed Jan 28 23:20:26 2004
+@@ -422,7 +422,8 @@
+     clean_user_id(user->username,
+         HasFlag(sptr, FLAG_GOTID) ? cli_username(sptr) : username,
+-        HasFlag(sptr, FLAG_DOID) && !HasFlag(sptr, FLAG_GOTID));
++        HasFlag(sptr, FLAG_DOID) && !HasFlag(sptr, FLAG_GOTID)
++        && !(HasSLine(sptr))); /* No tilde for S-lined users. */      
+     if ((user->username[0] == '\0')
+         || ((user->username[0] == '~') && (user->username[1] == '\000')))
diff --git a/stamp-h.in b/stamp-h.in
new file mode 100644 (file)
index 0000000..9788f70
--- /dev/null
@@ -0,0 +1 @@
+timestamp
diff --git a/tests/bug-1640796.cmd b/tests/bug-1640796.cmd
new file mode 100644 (file)
index 0000000..8a3c0d8
--- /dev/null
@@ -0,0 +1,35 @@
+define srv1 localhost:7601
+define srv1-name irc.example.net
+define hidden-srv *.undernet.org
+define channel #random-channel
+define cl1-nick Ch4n0pm4n
+define cl2-nick D00dm4n
+
+# Connect two clients.  Join one to the test channel.
+connect cl1 %cl1-nick% op3rm4n %srv1% :Some Chanop
+connect cl2 %cl2-nick% d00dm4n %srv1% :Someone Else
+:cl1 join %channel%
+:cl1 mode %channel% +D
+:cl1 expect %cl1-nick% mode %channel% \\+D
+
+# Now join the other client, and let the chanop remove -D.  Both
+# should see the channel become +d.
+:cl2 wait cl1
+:cl2 join %channel%
+:cl1 wait cl2
+:cl1 mode %channel% -D
+:cl1 expect %cl1-nick% mode %channel% -D\\+d
+:cl2 expect %cl1-nick% mode %channel% -D\\+d
+
+# Bug 1640796 is that if the chanop sends +D-D, the channel is
+# improperly marked -d.  (An empty mode change is also sent to other
+# servers.)
+:cl1 mode %channel% +D-D
+:cl1 mode %channel%
+:cl1 expect %srv1-name% 324 %cl1-nick% %channel% \\+.*d
+
+# Make sure that client 1 does see the -d when client 2 quits
+:cl2 wait cl1
+:cl2 part %channel% leaving
+:cl1 expect %hidden-srv% mode %channel% -d
+:cl1 quit done
diff --git a/tests/bug-1674539.cmd b/tests/bug-1674539.cmd
new file mode 100644 (file)
index 0000000..e084d1f
--- /dev/null
@@ -0,0 +1,33 @@
+define srv1 127.0.0.1:7611
+define srv1-name irc-2.example.net
+define srv2 127.0.0.2:7621
+define srv2-name irc-3.example.net
+define cl1-nick oper1
+define cl2-nick oper2
+define cl3-nick oper3
+
+# Connect two clients to server 1, one to server 2, and oper them all up.
+connect cl1 %cl1-nick% oper %srv1% :Oper 1
+connect cl2 %cl2-nick% oper %srv1% :Oper 2
+connect cl3 %cl3-nick% oper %srv2% :Oper 3
+:cl1 oper oper oper
+:cl2 oper oper oper
+:cl3 oper oper oper
+
+# Check that we get local privileges properly.
+:cl1 wait cl2,cl3
+:cl1 raw :privs %cl1-nick%
+:cl1 expect %srv1-name% 270 %cl1-nick% %cl1-nick% :CHAN_LIMIT
+:cl1 raw :privs %cl2-nick%
+:cl1 expect %srv1-name% 270 %cl1-nick% %cl2-nick% :CHAN_LIMIT
+
+# Bug 1674539 is that remote /privs do not get any response.
+# Testing shows that the problem only shows up with a hub between.
+:cl1 raw :privs %cl3-nick%
+:cl1 expect %srv2-name% 270 %cl1-nick% %cl3-nick% :CHAN_LIMIT
+
+# Synchronize everything
+sync cl1,cl2,cl3
+:cl1 quit done
+:cl2 quit done
+:cl3 quit done
diff --git a/tests/ircd-2.conf b/tests/ircd-2.conf
new file mode 100644 (file)
index 0000000..45882d6
--- /dev/null
@@ -0,0 +1,38 @@
+General {
+        name = "irc-2.example.net";
+        vhost = "127.0.0.1";
+        description = "Test IRC server";
+        numeric = 2;
+};
+
+Admin {
+        Location = "Right Here, Right Now";
+        Location = "Testbench IRC server";
+        Contact = "root@localhost";
+};
+
+Class {
+        name = "Server";
+        pingfreq = 90 seconds;
+        connectfreq = 5 minutes;
+        sendq = 9 megabytes;
+        maxlinks = 10;
+};
+
+Connect { name = "irc.example.net"; host = "127.0.0.1"; port = 7600; password = "password"; class = "Server"; hub; autoconnect = yes; };
+
+Class {
+        name = "Local";
+        pingfreq = 1 minutes 30 seconds;
+        sendq = 160000;
+        maxlinks = 100;
+};
+
+Client { ip = "127.*"; class = "Local"; };
+Operator { local = no; class = "Local"; host = "*@127.*"; password = "$PLAIN$oper"; name = "oper"; };
+Port { server = yes; port = 7610; };
+Port { port = 7611; };
+
+Features {
+        "PPATH" = "ircd-2.pid";
+};
diff --git a/tests/ircd-3.conf b/tests/ircd-3.conf
new file mode 100644 (file)
index 0000000..6273927
--- /dev/null
@@ -0,0 +1,38 @@
+General {
+        name = "irc-3.example.net";
+        vhost = "127.0.0.1";
+        description = "Test IRC server";
+        numeric = 3;
+};
+
+Admin {
+        Location = "Right Here, Right Now";
+        Location = "Testbench IRC server";
+        Contact = "root@localhost";
+};
+
+Class {
+        name = "Server";
+        pingfreq = 90 seconds;
+        connectfreq = 5 minutes;
+        sendq = 9 megabytes;
+        maxlinks = 10;
+};
+
+Connect { name = "irc.example.net"; host = "127.0.0.1"; port = 7600; password = "password"; class = "Server"; hub; autoconnect = yes; };
+
+Class {
+        name = "Local";
+        pingfreq = 1 minutes 30 seconds;
+        sendq = 160000;
+        maxlinks = 100;
+};
+
+Client { ip = "127.*"; class = "Local"; };
+Operator { local = no; class = "Local"; host = "*@127.*"; password = "$PLAIN$oper"; name = "oper"; };
+Port { server = yes; port = 7620; };
+Port { port = 7621; };
+
+Features {
+        "PPATH" = "ircd-3.pid";
+};
diff --git a/tests/ircd.conf b/tests/ircd.conf
new file mode 100644 (file)
index 0000000..5f8c5bf
--- /dev/null
@@ -0,0 +1,39 @@
+General {
+        name = "irc.example.net";
+        vhost = "127.0.0.1";
+        description = "Test IRC server";
+        numeric = 1;
+};
+
+Admin {
+        Location = "Right Here, Right Now";
+        Location = "Testbench IRC server";
+        Contact = "root@localhost";
+};
+
+Class {
+        name = "Server";
+        pingfreq = 90 seconds;
+        connectfreq = 5 minutes;
+        sendq = 9 megabytes;
+        maxlinks = 10;
+};
+
+Connect { name = "irc-2.example.net"; host = "127.0.0.1"; port = 7610; password = "password"; class = "Server"; autoconnect = no; };
+Connect { name = "irc-3.example.net"; host = "127.0.0.1"; port = 7620; password = "password"; class = "Server"; autoconnect = no; };
+
+Class {
+        name = "Local";
+        pingfreq = 1 minutes 30 seconds;
+        sendq = 160000;
+        maxlinks = 100;
+};
+
+Client { ip = "127.*"; class = "Local"; };
+Operator { local = no; class = "Local"; host = "*@127.*"; password = "$PLAIN$oper"; name = "oper"; };
+Port { server = yes; port = 7600; };
+Port { port = 7601; };
+
+Features {
+        "HUB" = "TRUE";
+};
diff --git a/tests/readme.txt b/tests/readme.txt
new file mode 100644 (file)
index 0000000..c3f6180
--- /dev/null
@@ -0,0 +1,21 @@
+ircu Test Framework
+===================
+
+This directory contains a simple test driver for ircu, supporting
+files, and test scripts.  test-driver.pl requires the POE and
+POE::Component::IRC modules for Perl; they are available from CPAN.
+
+The test scripts assume that an instance of ircu has been started
+using the ircd.conf file in this directory (e.g. by running
+"../ircd/ircd -f `pwd`/ircd.conf"), and that IPv4 support is enabled
+on the system.
+
+The test-driver.pl script accepts several command-line options:
+
+ -D enables POE::Component::IRC debugging output
+ -V enables test-driver.pl debugging output
+ -Hipaddr sets the IPv4 address to use for connections to the server
+ one or more script names to interpret and execute
+
+The normal output is one dot for each line that is executed.  Using
+the -D and -V options generates much more output.
diff --git a/tests/test-driver.pl b/tests/test-driver.pl
new file mode 100644 (file)
index 0000000..8fd0102
--- /dev/null
@@ -0,0 +1,527 @@
+#! /usr/bin/perl -wT
+
+# If you edit this file, please check carefully that the garbage
+# collection isn't broken.  POE is sometimes too clever for our good
+# in finding references to sessions, and keeps running even after we
+# want to stop.
+
+require 5.006;
+
+use warnings;
+use strict;
+use vars;
+use constant DELAY => 2;
+use constant EXPECT_TIMEOUT => 15;
+use constant RECONNECT_TIMEOUT => 5;
+use constant THROTTLED_TIMEOUT => 90;
+
+use FileHandle;
+# sub POE::Kernel::ASSERT_DEFAULT () { 1 }
+# sub POE::Kernel::TRACE_DEFAULT () { 1 }
+use POE v0.35;
+use POE::Component::IRC v5.00;
+
+# this defines commands that take "zero time" to execute
+# (specifically, those which do not send commands from the issuing
+# client to the server)
+our $zero_time = {
+                  expect => 1,
+                  sleep => 1,
+                  wait => 1,
+                 };
+
+# Create the main session and start POE.
+# All the empty anonymous subs are just to make POE:Session::ASSERT_STATES happy.
+POE::Session->create(inline_states =>
+                     {
+                      # POE kernel interaction
+                      _start => \&drv_start,
+                      _child => sub {},
+                      _stop => sub {
+                        my $heap = $_[HEAP];
+                        print "\nThat's all, folks!";
+                        print "(exiting at line $heap->{lineno}: $heap->{line})"
+                          if $heap->{line};
+                        print "\n";
+                      },
+                      _default => \&drv_default,
+                      # generic utilities or miscellaneous functions
+                      heartbeat => \&drv_heartbeat,
+                      timeout_expect => \&drv_timeout_expect,
+                      reconnect => \&drv_reconnect,
+                      enable_client => sub { $_[ARG0]->{ready} = 1; },
+                      disable_client => sub { $_[ARG0]->{ready} = 0; },
+                      die => sub { $_[KERNEL]->signal($_[SESSION], 'TERM'); },
+                      # client-based command issuers
+                      cmd_expect => \&cmd_expect,
+                      cmd_join => \&cmd_generic,
+                      cmd_mode => \&cmd_generic,
+                      cmd_nick => \&cmd_generic,
+                      cmd_notice => \&cmd_message,
+                      cmd_oper => \&cmd_generic,
+                      cmd_part => \&cmd_generic,
+                      cmd_privmsg => \&cmd_message,
+                      cmd_quit => \&cmd_generic,
+                      cmd_raw => \&cmd_raw,
+                      cmd_sleep => \&cmd_sleep,
+                      cmd_wait => \&cmd_wait,
+                      # handlers for messages from IRC
+                      irc_001 => \&irc_connected, # Welcome to ...
+                      irc_snotice => sub {}, # notice from a server (anonymous/our uplink)
+                      irc_notice => \&irc_notice, # NOTICE to self or channel
+                      irc_msg => \&irc_msg, # PRIVMSG to self
+                      irc_public => \&irc_public, # PRIVMSG to channel
+                      irc_connected => sub {},
+                      irc_ctcp_action => sub {},
+                      irc_ctcp_ping => sub {},
+                      irc_ctcp_time => sub {},
+                      irc_ctcpreply_ping => sub {},
+                      irc_ctcpreply_time => sub {},
+                      irc_invite => sub {},
+                      irc_isupport => sub {},
+                      irc_join => sub {},
+                      irc_kick => sub {},
+                      irc_kill => sub {},
+                      irc_mode => \&irc_mode, # MODE change on client or channel
+                      irc_nick => sub {},
+                      irc_part => sub {},
+                      irc_ping => sub {},
+                      irc_quit => sub {},
+                      irc_registered => sub {},
+                      irc_topic => sub {},
+                      irc_plugin_add => sub {},
+                      irc_error => \&irc_error,
+                      irc_disconnected => \&irc_disconnected,
+                      irc_socketerr => \&irc_socketerr,
+                     },
+                     args => [@ARGV]);
+
+$| = 1;
+$poe_kernel->run();
+exit;
+
+# Core/bookkeeping test driver functions
+
+sub drv_start {
+  my ($kernel, $session, $heap) = @_[KERNEL, SESSION, HEAP];
+
+  # initialize heap
+  $heap->{clients} = {}; # session details, indexed by (short) session name
+  $heap->{sessions} = {}; # session details, indexed by session ref
+  $heap->{servers} = {}; # server addresses, indexed by short names
+  $heap->{macros} = {}; # macros
+
+  # Parse arguments
+  foreach my $arg (@_[ARG0..$#_]) {
+    if ($arg =~ /^-D$/) {
+      $heap->{irc_debug} = 1;
+    } elsif ($arg =~ /^-V$/) {
+      $heap->{verbose} = 1;
+    } elsif ($arg =~ /^-H(.+)$/) {
+      $heap->{local_address} = $1;
+    } else {
+      die "Extra command-line argument $arg\n" if $heap->{script};
+      $heap->{script} = new FileHandle($arg, 'r')
+        or die "Unable to open $arg for reading: $!\n";
+    }
+  }
+  die "No test name specified\n" unless $heap->{script};
+
+  # hook in to POE
+  $kernel->alias_set('control');
+  $kernel->yield('heartbeat');
+}
+
+sub drv_heartbeat {
+  my ($kernel, $sender, $heap) = @_[KERNEL, SENDER, HEAP];
+  my $script = $heap->{script};
+  my $used = {};
+  my $delay = DELAY;
+
+  while (1) {
+    my ($line, $lineno);
+    if ($heap->{line}) {
+      $line = delete $heap->{line};
+    } elsif (defined($line = <$script>)) {
+      $heap->{lineno} = $.;
+      print "." unless $heap->{irc_debug};
+    } else {
+      # close all connections
+      foreach my $client (values %{$heap->{clients}}) {
+        $kernel->call($client->{irc}, 'quit', "I fell off the end of my script");
+        $client->{quitting} = 1;
+      }
+      # unalias the control session
+      $kernel->alias_remove('control');
+      # die in a few seconds
+      $kernel->delay_set('die', 5);
+      return;
+    }
+
+    chomp $line;
+    # ignore comments and blank lines
+    next if $line =~ /^\#/ or $line !~ /\S/;
+
+    # expand any macros in the line
+    $line =~ s/(?<=[^\\])%(\S+?)%/$heap->{macros}->{$1}
+      or die "Use of undefined macro $1 at $heap->{lineno}\n"/eg;
+    # remove any \-escapes
+    $line =~ s/\\(.)/$1/g;
+    # figure out the type of line
+    if ($line =~ /^define (\S+) (.+)$/i) {
+      # define a new macro
+      $heap->{macros}->{$1} = $2;
+    } elsif ($line =~ /^undef (\S+)$/i) {
+      # remove the macro
+      delete $heap->{macros}->{$1};
+    } elsif ($line =~ /^connect (\S+) (\S+) (\S+) (\S+) :(.+)$/i) {
+      # connect a new session (named $1) to server $4
+      my ($name, $nick, $ident, $server, $userinfo, $port) = ($1, $2, $3, $4, $5, 6667);
+      $server = $heap->{servers}->{$server} || $server;
+      if ($server =~ /(.+):(\d+)/) {
+        $server = $1;
+        $port = $2;
+      }
+      die "Client with nick $nick already exists (line $heap->{lineno})" if $heap->{clients}->{$nick};
+      my $alias = "client_$name";
+      my $client = {
+                    name => $name,
+                    nick => $nick,
+                    ready => 0,
+                    expect => [],
+                    expect_alarms => [],
+                    params => { Nick     => $nick,
+                                Server   => $server,
+                                Port     => $port,
+                                Username => $ident,
+                                Ircname  => $userinfo,
+                                Debug    => $heap->{irc_debug},
+                              }
+                   };
+      $client->{params}->{LocalAddr} = $heap->{local_address}
+        if $heap->{local_address};
+      my $irc = POE::Component::IRC->spawn
+        (
+         alias => $alias,
+         nick => $nick,
+        ) or die "Unable to create new user $nick (line $heap->{lineno}): $!";
+      $client->{irc} = $irc->session_id();
+      $heap->{clients}->{$client->{name}} = $client;
+      $heap->{sessions}->{$irc} = $client;
+      $kernel->call($client->{irc}, 'register', 'all');
+      $kernel->call($client->{irc}, 'connect', $client->{params});
+      $used->{$name} = 1;
+    } elsif ($line =~ /^sync (.+)$/i) {
+      # do multi-way synchronization between every session named in $1
+      my @synced = split(/,|\s/, $1);
+      # first, check that they exist and are ready
+      foreach my $clnt (@synced) {
+        die "Unknown session name $clnt (line $heap->{lineno})" unless $heap->{clients}->{$clnt};
+        goto REDO unless $heap->{clients}->{$clnt}->{ready};
+      }
+      # next we actually send the synchronization signals
+      foreach my $clnt (@synced) {
+        my $client = $heap->{clients}->{$clnt};
+        $client->{sync_wait} = [map { $_ eq $clnt ? () : $heap->{clients}->{$_}->{nick} } @synced];
+        $kernel->call($client->{irc}, 'notice', $client->{sync_wait}, 'SYNC');
+        $kernel->call($sender, 'disable_client', $client);
+      }
+    } elsif ($line =~ /^:(\S+) (\S+)(.*)$/i) {
+      # generic command handler
+      my ($names, $cmd, $args) = ($1, lc($2), $3);
+      my (@avail, @unavail);
+      # figure out whether each listed client is available or not
+      foreach my $c (split ',', $names) {
+        my $client = $heap->{clients}->{$c};
+        if (not $client) {
+          print "ERROR: Unknown session name $c (line $heap->{lineno}; ignoring)\n";
+        } elsif (($used->{$c} and not $zero_time->{$cmd}) or not $client->{ready}) {
+          push @unavail, $c;
+        } else {
+          push @avail, $c;
+        }
+      }
+      # redo command with unavailable clients
+      if (@unavail) {
+        # This will break if the command can cause a redo for
+        # available clients.. this should be fixed sometime
+        $line = ':'.join(',', @unavail).' '.$cmd.$args;
+        $heap->{redo} = 1;
+      }
+      # do command with available clients
+      if (@avail) {
+        # split up the argument part of the line
+        $args =~ /^((?:(?: [^:])|[^ ])+)?(?: :(.+))?$/;
+        $args = [($1 ? split(' ', $1) : ()), ($2 ? $2 : ())];
+        # find the client and figure out if we need to wait
+        foreach my $c (@avail) {
+          my $client = $heap->{clients}->{$c};
+          die "Client $c used twice as source (line $heap->{lineno})" if $used->{c} and not $zero_time->{$cmd};
+          $kernel->call($sender, 'cmd_' . $cmd, $client, $args);
+          $used->{$c} = 1 unless $zero_time->{$cmd};
+        }
+      }
+    } else {
+      die "Unrecognized input line $heap->{lineno}: $line";
+    }
+    if ($heap->{redo}) {
+    REDO:
+      delete $heap->{redo};
+      $heap->{line} = $line;
+      last;
+    }
+  }
+  # issue new heartbeat with appropriate delay
+  $kernel->delay_set('heartbeat', $delay);
+}
+
+sub drv_timeout_expect {
+  my ($kernel, $session, $client) = @_[KERNEL, SESSION, ARG0];
+  print "ERROR: Dropping timed-out expectation by $client->{name}: ".join(',', @{$client->{expect}->[0]})."\n";
+  $client->{expect_alarms}->[0] = undef;
+  unexpect($kernel, $session, $client);
+}
+
+sub drv_reconnect {
+  my ($kernel, $session, $client) = @_[KERNEL, SESSION, ARG0];
+  $kernel->call($client->{irc}, 'connect', $client->{params});
+}
+
+sub drv_default {
+  my ($kernel, $heap, $sender, $session, $state, $args) = @_[KERNEL, HEAP, SENDER, SESSION, ARG0, ARG1];
+  if ($state =~ /^irc_(\d\d\d)$/) {
+    my $client = $heap->{sessions}->{$sender->get_heap()};
+    if (@{$client->{expect}}
+        and $args->[0] eq $client->{expect}->[0]->[0]
+        and $client->{expect}->[0]->[1] eq "$1") {
+      my $expect = $client->{expect}->[0];
+      my $mismatch;
+      $args = $args->[2]; # ->[1] is the entire string, ->[2] is split
+      for (my $x=2; ($x<=$#$expect) and ($x<=$#$args) and not $mismatch; $x++) {
+        if ($args->[$x] !~ /$expect->[$x]/i) {
+          $mismatch = 1;
+          print "Mismatch in arg $x: $args->[$x] !~ $expect->[$x]\n";
+        }
+        # $mismatch = 1 unless $args->[$x] =~ /$expect->[$x]/i;
+      }
+      unexpect($kernel, $session, $client) unless $mismatch;
+    }
+    return undef;
+  }
+  print "ERROR: Unexpected event $state to test driver (from ".$sender->ID.")\n";
+  return undef;
+}
+
+# client-based command issuers
+
+sub cmd_message {
+  my ($kernel, $heap, $event, $client, $args) = @_[KERNEL, HEAP, STATE, ARG0, ARG1];
+  die "Missing arguments" unless $#$args >= 1;
+  # translate each target as appropriate (e.g. *sessionname)
+  my @targets = split(/,/, $args->[0]);
+  foreach my $target (@targets) {
+    if ($target =~ /^\*(.+)$/) {
+      my $other = $heap->{clients}->{$1} or die "Unknown session name $1 (line $heap->{lineno})\n";
+      $target = $other->{nick};
+    }
+  }
+  $kernel->call($client->{irc}, substr($event, 4), \@targets, $args->[1]);
+}
+
+sub cmd_generic {
+  my ($kernel, $event, $client, $args) = @_[KERNEL, STATE, ARG0, ARG1];
+  $kernel->call($client->{irc}, substr($event, 4), @$args);
+}
+
+sub cmd_raw {
+  my ($kernel, $heap, $client, $args) = @_[KERNEL, HEAP, ARG0, ARG1];
+  die "Missing argument" unless $#$args >= 0;
+  $kernel->call($client->{irc}, 'sl', $args->[0]);
+}
+
+sub cmd_sleep {
+  my ($kernel, $session, $heap, $client, $args) = @_[KERNEL, SESSION, HEAP, ARG0, ARG1];
+  die "Missing argument" unless $#$args >= 0;
+  $kernel->call($session, 'disable_client', $client);
+  $kernel->delay_set('enable_client', $args->[0], $client);
+}
+
+sub cmd_wait {
+  my ($kernel, $session, $heap, $client, $args) = @_[KERNEL, SESSION, HEAP, ARG0, ARG1];
+  die "Missing argument" unless $#$args >= 0;
+  # if argument was comma-delimited, split it up (space-delimited is split by generic parser)
+  $args = [split(/,/, $args->[0])] if $args->[0] =~ /,/;
+  # make sure we only wait if all the other clients are ready
+  foreach my $other (@$args) {
+    if (not $heap->{clients}->{$other}->{ready}) {
+      $heap->{redo} = 1;
+      return;
+    }
+  }
+  # disable this client, make the others send SYNC to it
+  $kernel->call($session, 'disable_client', $client);
+  $client->{sync_wait} = [map { $heap->{clients}->{$_}->{nick} } @$args];
+  foreach my $other (@$args) {
+    die "Cannot wait on self" if $other eq $client->{name};
+    $kernel->call($heap->{clients}->{$other}->{irc}, 'notice', $client->{nick}, 'SYNC');
+  }
+}
+
+sub cmd_expect {
+  my ($kernel, $session, $heap, $client, $args) = @_[KERNEL, SESSION, HEAP, ARG0, ARG1];
+  die "Missing argument" unless $#$args >= 0;
+  push @{$client->{expect}}, $args;
+  push @{$client->{expect_alarms}}, $kernel->delay_set('timeout_expect', EXPECT_TIMEOUT, $client);
+  $kernel->call($session, 'disable_client', $client);
+}
+
+# handlers for messages from IRC
+
+sub unexpect {
+  my ($kernel, $session, $client) = @_;
+  shift @{$client->{expect}};
+  my $alarm_id = shift @{$client->{expect_alarms}};
+  $kernel->alarm_remove($alarm_id) if $alarm_id;
+  $kernel->call($session, 'enable_client', $client) unless @{$client->{expect}};
+}
+
+sub check_expect {
+  my ($kernel, $session, $heap, $poe_sender, $sender, $text) = @_[KERNEL, SESSION, HEAP, SENDER, ARG0, ARG1];
+  my $client = $heap->{sessions}->{$poe_sender->get_heap()};
+  my $expected = $client->{expect}->[0];
+
+  # check sender
+  if ($expected->[0] =~ /\*(.+)/) {
+    # we expect *sessionname, so look up session's current nick
+    my $exp = $1;
+    $sender =~ /^(.+)!/;
+    return 0 if lc($heap->{clients}->{$exp}->{nick}) ne lc($1);
+  } elsif ($expected->[0] =~ /^:?(.+!.+)/) {
+    # expect :nick!user@host, so compare whole thing
+    return 0 if lc($1) ne lc($sender);
+  } else {
+    # we only expect :nick, so compare that part
+    $sender =~ /^:?(.+)!/;
+    return 0 if lc($expected->[0]) ne lc($1);
+  }
+
+  # compare text
+  return 0 if lc($text) !~ /$expected->[2]/i;
+
+  # drop expectation of event
+  unexpect($kernel, $session, $client);
+}
+
+sub irc_connected {
+  my ($kernel, $session, $heap, $sender) = @_[KERNEL, SESSION, HEAP, SENDER];
+  my $client = $heap->{sessions}->{$sender->get_heap()};
+  print "Client $client->{name} connected to server $_[ARG0]\n"
+    if $heap->{verbose};
+  $kernel->call($session, 'enable_client', $client);
+}
+
+sub handle_irc_disconnect ($$$$$) {
+  my ($kernel, $session, $heap, $sender, $client) = @_;
+  if ($client->{quitting}) {
+    $kernel->call($sender, 'unregister', 'all');
+    delete $heap->{sessions}->{$sender->get_heap()};
+    delete $heap->{clients}->{$client->{name}};
+  } else {
+    if ($client->{disconnect_expected}) {
+      delete $client->{disconnect_expected};
+    } else {
+      print "Got unexpected disconnect for $client->{name} (nick $client->{nick})\n";
+    }
+    $kernel->call($session, 'disable_client', $client);
+    $kernel->delay_set('reconnect', $client->{throttled} ? THROTTLED_TIMEOUT : RECONNECT_TIMEOUT, $client);
+    delete $client->{throttled};
+  }
+}
+
+sub irc_disconnected {
+  my ($kernel, $session, $heap, $sender, $server) = @_[KERNEL, SESSION, HEAP, SENDER, ARG0];
+  my $client = $heap->{sessions}->{$sender->get_heap()};
+  print "Client $client->{name} disconnected from server $_[ARG0]\n" if $heap->{verbose};
+  handle_irc_disconnect($kernel, $session, $heap, $sender, $client);
+}
+
+sub irc_socketerr {
+  my ($kernel, $session, $heap, $sender, $msg) = @_[KERNEL, SESSION, HEAP, SENDER, ARG0];
+  my $client = $heap->{sessions}->{$sender->get_heap()};
+  print "Client $client->{name} (re-)connect error: $_[ARG0]\n";
+  handle_irc_disconnect($kernel, $session, $heap, $sender, $client);
+}
+
+sub irc_notice {
+  my ($kernel, $session, $heap, $sender, $from, $to, $text) = @_[KERNEL, SESSION, HEAP, SENDER, ARG0, ARG1, ARG2];
+  my $client = $heap->{sessions}->{$sender->get_heap()};
+  if ($client->{sync_wait} and $text eq 'SYNC') {
+    $from =~ s/!.+$//;
+    my $x;
+    # find who sent it..
+    for ($x=0; $x<=$#{$client->{sync_wait}}; $x++) {
+      last if $from eq $client->{sync_wait}->[$x];
+    }
+    # exit if we don't expect them
+    if ($x>$#{$client->{sync_wait}}) {
+      print "Got unexpected SYNC from $from to $client->{name} ($client->{nick})\n";
+      return;
+    }
+    # remove from the list of people we're waiting for
+    splice @{$client->{sync_wait}}, $x, 1;
+    # re-enable client if we're done waiting
+    if ($#{$client->{sync_wait}} == -1) {
+      delete $client->{sync_wait};
+      $kernel->call($session, 'enable_client', $client);
+    }
+  } elsif (@{$client->{expect}}
+           and $client->{expect}->[0]->[1] =~ /notice/i) {
+    check_expect(@_[0..ARG0], $text);
+  }
+}
+
+sub irc_msg {
+  my ($kernel, $session, $heap, $sender, $from, $to, $text) = @_[KERNEL, SESSION, HEAP, SENDER, ARG0, ARG1, ARG2];
+  my $client = $heap->{sessions}->{$sender->get_heap()};
+  if (@{$client->{expect}}
+      and $client->{expect}->[0]->[1] =~ /msg/i) {
+    check_expect(@_[0..ARG0], $text);
+  }
+}
+
+sub irc_public {
+  my ($kernel, $session, $heap, $sender, $from, $to, $text) = @_[KERNEL, SESSION, HEAP, SENDER, ARG0, ARG1, ARG2];
+  my $client = $heap->{sessions}->{$sender->get_heap()};
+  if (@{$client->{expect}}
+      and $client->{expect}->[0]->[1] =~ /public/i
+      and grep($client->{expect}->[0]->[2], @$to)) {
+    splice @{$client->{expect}->[0]}, 2, 1;
+    check_expect(@_[0..ARG0], $text);
+  }
+}
+
+sub irc_mode {
+  my ($kernel, $session, $heap, $sender, $from, $to) = @_[KERNEL, SESSION, HEAP, SENDER, ARG0, ARG1];
+  my $client = $heap->{sessions}->{$sender->get_heap()};
+  if (@{$client->{expect}}
+      and $client->{expect}->[0]->[1] =~ /mode/i
+      and grep($client->{expect}->[0]->[2], $to)) {
+    splice @{$client->{expect}->[0]}, 2, 1;
+    splice(@_, ARG1, 1);
+    check_expect(@_);
+  }
+}
+
+sub irc_error {
+  my ($kernel, $session, $heap, $sender, $what) = @_[KERNEL, SESSION, HEAP, SENDER, ARG0];
+  my $client = $heap->{sessions}->{$sender->get_heap()};
+  if (@{$client->{expect}}
+      and $client->{expect}->[0]->[1] =~ /error/i) {
+    splice @{$client->{expect}->[0]}, 2, 1;
+    unexpect($kernel, $session, $client);
+    $client->{disconnect_expected} = 1;
+  } else {
+    print "ERROR: From server to $client->{name}: $what\n";
+  }
+  $client->{throttled} = 1 if $what =~ /throttled/i;
+}
diff --git a/tools/Bounce/Bounce.cpp b/tools/Bounce/Bounce.cpp
new file mode 100644 (file)
index 0000000..bc0e48e
--- /dev/null
@@ -0,0 +1,504 @@
+/*
+ * IRC - Internet Relay Chat, tools/Bounce/Bounce.cpp
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ *                    University of Oulu, Computing Center
+ *
+ * See file AUTHORS in IRC package for additional names of
+ * the programmers.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Port Bouncer.
+ *
+ * This tool is designed to set up a number of local listening ports, and
+ * then forward any data recived on those ports, to another host/port combo.
+ * Each listening port can bounce to a different host/port defined in the
+ * config file. --Gte 
+ *
+ * $Id: Bounce.cpp,v 1.3 2002/03/07 22:52:57 ghostwolf Exp $ 
+ *
+ */
+
+#include "Bounce.h"
+int main() {
+  Bounce* application = new Bounce();
+
+  /*
+   *  Ignore SIGPIPE.
+   */
+
+  struct sigaction act; 
+  act.sa_handler = SIG_IGN;
+  act.sa_flags = 0;
+  sigemptyset(&act.sa_mask);
+  sigaction(SIGPIPE, &act, 0);
+#ifndef DEBUG
+  /*
+   *  If we aren't debugging, we might as well
+   *  detach from the console.
+   */
+
+  pid_t forkResult = fork() ;
+  if(forkResult < 0)
+  { 
+    printf("Unable to fork new process.\n");
+    return -1 ;
+  } 
+  else if(forkResult != 0)
+  {
+    printf("Successfully Forked, New process ID is %i.\n", forkResult);
+    return 0;
+  } 
+#endif
+
+  /*
+   *  Create new application object, bind listeners and begin
+   *  polling them.
+   */
+  application->bindListeners();
+
+  while (1) {
+    application->checkSockets();
+  } 
+}
+
+/*
+ ****************************************
+ *                                      *
+ *     Bounce class implementation.     *
+ *                                      *
+ ****************************************
+ */
+void Bounce::bindListeners() { 
+/*
+ *  bindListeners.
+ *  Inputs: Nothing.
+ *  Outputs: Nothing.
+ *  Process: 1. Reads the config file, and..
+ *           2. Creates a new listener for each 'P' line found.
+ *
+ */
+
+  FILE* configFd;
+  char tempBuf[256];
+  int localPort = 0;
+  int remotePort = 0;
+  char* remoteServer;
+  char* vHost; 
+  /*
+   *  Open config File.
+   */
+  
+  if(!(configFd = fopen("bounce.conf", "r")))
+  {
+    printf("Error, unable to open config file!\n");
+    exit(0);
+  } 
+
+  while (fgets(tempBuf, 256, configFd) != NULL) { 
+    if((tempBuf[0] != '#') && (tempBuf[0] != '\r')) {
+    switch(tempBuf[0])
+    {
+      case 'P': { /* Add new port listener */ 
+        strtok(tempBuf, ":");
+        vHost = strtok(NULL, ":");
+        localPort = atoi(strtok(NULL, ":"));
+        remoteServer = strtok(NULL, ":");
+        remotePort = atoi(strtok(NULL, ":")); 
+
+        Listener* newListener = new Listener();
+        strcpy(newListener->myVhost, vHost); 
+        strcpy(newListener->remoteServer, remoteServer);
+        newListener->remotePort = remotePort;
+        newListener->localPort = localPort;
+#ifdef DEBUG
+        printf("Adding new Listener: Local: %s:%i, Remote: %s:%i\n", vHost, localPort, remoteServer, remotePort);
+#endif
+
+        newListener->beginListening();
+        listenerList.insert(listenerList.begin(), newListener); 
+        break;
+      }
+    }
+    } 
+  } 
+}
+
+void Bounce::checkSockets() { 
+/*
+ *  checkSockets.
+ *  Inputs: Nothing.
+ *  Outputs: Nothing.
+ *  Process: 1. Builds up a FD_SET of all sockets we wish to check.
+ *              (Including all listeners & all open connections).
+ *           2. SELECT(2) the set, and forward/accept as needed.
+ *
+ */ 
+  typedef std::list<Listener*> listenerContainer;
+  typedef listenerContainer::iterator listIter;
+
+  typedef std::list<Connection*> connectionContainer;
+  typedef connectionContainer::iterator connIter; 
+
+  struct timeval tv;
+  fd_set readfds; 
+  tv.tv_sec = 0;
+  tv.tv_usec = 1000;
+  int tempFd = 0;
+  int tempFd2 = 0;
+  int highestFd = 0;
+  int delCheck = 0;
+  char* tempBuf;
+
+  FD_ZERO(&readfds);
+  /*
+   *  Add all Listeners to the set.
+   */
+
+  listIter a = listenerList.begin();
+  while(a != listenerList.end())
+  { 
+    tempFd = (*a)->fd; 
+    FD_SET(tempFd, &readfds);
+    if (highestFd < tempFd) highestFd = tempFd;
+    a++;
+  }
+
+  /*
+   *  Add Local & Remote connections from each
+   *  connection object to the set.
+   */
+
+  connIter b = connectionsList.begin();
+  while(b != connectionsList.end())
+  { 
+    tempFd = (*b)->localSocket->fd;
+    tempFd2 = (*b)->remoteSocket->fd;
+    FD_SET(tempFd, &readfds);
+    if (highestFd < tempFd) highestFd = tempFd;
+    FD_SET(tempFd2, &readfds);
+    if (highestFd < tempFd2) highestFd = tempFd2;
+    b++;
+  }
+
+  select(highestFd+1, &readfds, NULL, NULL, &tv); 
+
+  /*
+   *  Check all connections for readability.
+   *  First check Local FD's.
+   *  If the connection is closed on either side,
+   *  shutdown both sockets, and clean up.
+   *  Otherwise, send the data from local->remote, or
+   *  remote->local.
+   */
+
+  b = connectionsList.begin();
+  while(b != connectionsList.end())
+  { 
+    tempFd = (*b)->localSocket->fd;
+    if (FD_ISSET(tempFd, &readfds))
+    { 
+      tempBuf = (*b)->localSocket->read();
+      if ((tempBuf[0] == 0)) // Connection closed.
+      {
+        close((*b)->localSocket->fd);
+        close((*b)->remoteSocket->fd); 
+#ifdef DEBUG
+        printf("Closing FD: %i\n", (*b)->localSocket->fd);
+        printf("Closing FD: %i\n", (*b)->remoteSocket->fd); 
+#endif
+        delete(*b);
+        delCheck = 1;
+        b = connectionsList.erase(b); 
+      } else {
+        (*b)->remoteSocket->write(tempBuf, (*b)->localSocket->lastReadSize); 
+      }
+    } 
+  if (!delCheck) b++;
+  delCheck = 0;
+  } 
+
+  /*
+   *  Now check Remote FD's..
+   */
+  b = connectionsList.begin();
+  while(b != connectionsList.end())
+  { 
+    tempFd = (*b)->remoteSocket->fd;
+    if (FD_ISSET(tempFd, &readfds))
+    {
+      tempBuf = (*b)->remoteSocket->read();
+      if ((tempBuf[0] == 0)) // Connection closed.
+      {
+        close((*b)->localSocket->fd);
+        close((*b)->remoteSocket->fd); 
+#ifdef DEBUG
+        printf("Closing FD: %i\n", (*b)->localSocket->fd);
+        printf("Closing FD: %i\n", (*b)->remoteSocket->fd);
+#endif
+        delete(*b);
+        delCheck = 1;
+        b = connectionsList.erase(b); 
+      } else {
+        (*b)->localSocket->write(tempBuf, (*b)->remoteSocket->lastReadSize);
+      }
+    }
+  if (!delCheck) b++;
+  delCheck = 0;
+  } 
+  /*
+   *  Check all listeners for new connections.
+   */
+
+  a = listenerList.begin();
+  while(a != listenerList.end())
+  { 
+    tempFd = (*a)->fd; 
+    if (FD_ISSET(tempFd, &readfds))
+    { 
+      recieveNewConnection(*a);
+    }
+    a++;
+  } 
+
+}
+
+void Bounce::recieveNewConnection(Listener* listener) {
+/*
+ *  recieveNewConnection.
+ *  Inputs: A Listener Object.
+ *  Outputs: Nothing.
+ *  Process: 1. Recieves a new connection on a local port,
+ *              and creates a connection object for it.
+ *           2. Accepts the incomming connection.
+ *           3. Creates a new Socket object for the remote
+ *              end of the connection.
+ *           4. Connects up the remote Socket.
+ *           5. Adds the new Connection object to the
+ *              connections list.
+ *
+ */
+
+  Connection* newConnection = new Connection(); 
+  newConnection->localSocket = listener->handleAccept();
+
+  Socket* remoteSocket = new Socket();
+  newConnection->remoteSocket = remoteSocket; 
+  if(remoteSocket->connectTo(listener->remoteServer, listener->remotePort)) { 
+    connectionsList.insert(connectionsList.begin(), newConnection);
+  } else {
+#ifdef DEBUG
+    newConnection->localSocket->write("Unable to connect to remote host.\n");
+#endif
+    close(newConnection->localSocket->fd);
+    delete(newConnection);
+    delete(remoteSocket);
+  } 
+}
+
+/*
+ ****************************************
+ *                                      *
+ *    Listener class implementation.    *
+ *                                      *
+ ****************************************
+ */
+
+Socket* Listener::handleAccept() {
+/*
+ *  handleAccept.
+ *  Inputs: Nothing.
+ *  Outputs: A Socket Object.
+ *  Process: 1. Accept's an incomming connection,
+ *              and returns a new socket object. 
+ */
+
+  int new_fd = 0;
+  int sin_size = sizeof(struct sockaddr_in);
+
+  Socket* newSocket = new Socket();
+  new_fd = accept(fd, (struct sockaddr*)&newSocket->address, (socklen_t*)&sin_size);
+  newSocket->fd = new_fd; 
+  return newSocket;
+}
+void Listener::beginListening() {
+/*
+ *  beginListening.
+ *  Inputs: Nothing.
+ *  Outputs: Nothing.
+ *  Process: 1. Binds the local ports for all the
+ *              Listener objects.
+ *
+ */
+
+  struct sockaddr_in my_addr;
+  int bindRes;
+  int optval;
+  optval = 1;
+
+  fd = socket(AF_INET, SOCK_STREAM, 0); /* Check for no FD's left?! */
+
+  my_addr.sin_family = AF_INET;
+  my_addr.sin_port = htons(localPort);
+  my_addr.sin_addr.s_addr = inet_addr(myVhost);
+  bzero(&(my_addr.sin_zero), 8);
+
+  setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval));
+
+  bindRes = bind(fd, (struct sockaddr *)&my_addr, sizeof(struct sockaddr));
+  if(bindRes == 0)
+  {
+    listen(fd, 10);
+  } else { 
+     /*
+      *  If we can't bind a listening port, we might aswell drop out.
+      */
+     printf("Unable to bind to %s:%i!\n", myVhost, localPort);
+     exit(0);
+   } 
+}
+
+/*
+ ****************************************
+ *                                      *
+ *     Socket class implementation.     *
+ *                                      *
+ ****************************************
+ */
+
+
+Socket::Socket() {
+/*
+ *  Socket Constructor.
+ *  Inputs: Nothing.
+ *  Outputs: Nothing.
+ *  Process: Initialises member variables.
+ *
+ */
+
+  fd = -1;
+  lastReadSize = 0;
+}
+
+int Socket::write(char *message, int len) { 
+/*
+ *  write.
+ *  Inputs: Message string, and lenght.
+ *  Outputs: Amount written, or 0 on error.
+ *  Process: 1. Writes out 'len' amount of 'message'.
+ *              to this socket.
+ *
+ */
+
+   if (fd == -1) return 0; 
+   int amount = ::write(fd, message, len); 
+#ifdef DEBUG
+   printf("Wrote %i Bytes.\n", amount);
+#endif
+   return amount; 
+}
+
+int Socket::write(char *message) { 
+/*
+ *  write(2).
+ *  Inputs: Message string.
+ *  Outputs: Amount writte, or 0 on error.
+ *  Process: Writes out the whole of 'message'.
+ *
+ */
+
+   if (fd == -1) return 0; 
+   int amount = ::write(fd, message, strlen(message)); 
+#ifdef DEBUG
+   printf("Wrote %i Bytes.\n", amount);
+#endif
+   return amount; 
+}
+
+
+int Socket::connectTo(char *hostname, unsigned short portnum) { 
+/*
+ *  connectTo.
+ *  Inputs: Hostname and port.
+ *  Outputs: +ve on success, 0 on failure.
+ *  Process: 1. Connects this socket to remote 'hostname' on
+ *              port 'port'.
+ *
+ */
+
+  struct hostent     *hp;
+  if ((hp = gethostbyname(hostname)) == NULL) { 
+     return 0; 
+  }          
+
+  memset(&address,0,sizeof(address));
+  memcpy((char *)&address.sin_addr,hp->h_addr,hp->h_length);
+  address.sin_family= hp->h_addrtype;
+  address.sin_port= htons((u_short)portnum);
+
+  if ((fd = socket(hp->h_addrtype,SOCK_STREAM,0)) < 0)
+    return 0; 
+  if (connect(fd, (struct sockaddr*)&address, sizeof(address)) < 0) {
+    close(fd);
+    fd = -1; 
+    return 0;
+  } 
+  return(1);
+}
+
+char* Socket::read() { 
+/*
+ *  read.
+ *  Inputs: Nothing.
+ *  Outputs: char* to static buffer containing data.
+ *  Process: 1. Reads as much as possible from this socket, up to
+ *              4k.
+ *
+ */
+
+  int amountRead = 0;
+  static char buffer[4096];
+
+  amountRead = ::read(fd, &buffer, 4096);
+
+  if ((amountRead == -1)) buffer[0] = '\0';
+  buffer[amountRead] = '\0';
+
+#ifdef DEBUG
+  printf("Read %i Bytes.\n", amountRead);
+#endif
+  /* 
+   * Record this just incase we're dealing with binary data with 0's in it.
+   */
+  lastReadSize = amountRead;
+  return (char *)&buffer;
+}
+
diff --git a/tools/Bounce/Bounce.h b/tools/Bounce/Bounce.h
new file mode 100644 (file)
index 0000000..6062bbd
--- /dev/null
@@ -0,0 +1,117 @@
+/*
+ * IRC - Internet Relay Chat, tools/Bounce/Bounce.h
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ *                    University of Oulu, Computing Center
+ *
+ * See file AUTHORS in IRC package for additional names of
+ * the programmers.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id: Bounce.h,v 1.3 2002/03/07 22:52:57 ghostwolf Exp $
+ *
+ */
+
+#include <sys/types.h> 
+#include <sys/time.h>
+#include <sys/wait.h> 
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <arpa/inet.h>
+#include <netinet/in.h>
+#include <netdb.h> 
+#include <ctype.h>
+#include <time.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <stdarg.h>
+#include <signal.h>
+#include <fcntl.h>
+#include <stdio.h> 
+#include <stdlib.h> 
+#include <errno.h> 
+#include <string.h> 
+#include <netdb.h> 
+#include <ctype.h>
+#include <time.h>
+#include <list>
+using std::list; 
+
+#define DEBUG
+/*
+ *  "Bounce" Class.
+ */
+
+class Listener;
+class Connection;
+class Bounce
+{
+public:
+  list<Listener*> listenerList;      // List of 'Listeners'.
+  list<Connection*> connectionsList; // List of 'Connections'. 
+
+  void bindListeners(); // Binds Listening Ports.
+  void checkSockets();  // Polls all sockets.
+  void recieveNewConnection(Listener*); // Accepts connections.
+};
+
+/*
+ *  "Socket" Class.
+ */
+
+class Socket 
+{
+public:
+  int fd;                               // File descriptor.
+  int lastReadSize;                     // Size of last read buffer.
+  struct sockaddr_in address;           // Socket addr_in struct.
+  int connectTo(char*, unsigned short); // Connects the socket.
+  int write(char*, int);                // Writes 'int' bytes from message.
+  int write(char*);                     // Writes strlen(message).
+  char* read();                         // Reads as much as possible into a 4k buffer.
+  Socket();                             // Constructor.
+};
+
+/*
+ *  "Listener" Class.
+ */
+
+class Bounce;
+class Listener
+{
+public:
+  int fd;                 // File descriptor.
+  int remotePort;         // Remote port from config.
+  int localPort;          // Local port for binding.
+  char myVhost[15];       // Vhost to bind locally.
+  char remoteServer[15];  // Remote server to connect to.
+
+  void beginListening();  // Bind listening ports.
+  Socket* handleAccept(); // Accept a new connection.
+};
+
+/*
+ *  "Connection" Class.
+ *  Simply a container for a local/remote Socket pair.
+ */
+
+class Connection 
+{ 
+public:
+  Socket* localSocket;
+  Socket* remoteSocket;
+};
+
diff --git a/tools/Bounce/bounce.conf b/tools/Bounce/bounce.conf
new file mode 100644 (file)
index 0000000..55afb20
--- /dev/null
@@ -0,0 +1,7 @@
+# Format: P:<Local vhost>:<Local Port>:<Remote Address>:<Remote Port>
+# IP's only for now :)
+# $Id: bounce.conf,v 1.2 2002/03/07 22:52:57 ghostwolf Exp $
+
+P:192.168.10.5:2000:192.168.10.1:80
+P:192.168.10.5:3000:4.33.94.3:80
+P:192.168.10.5:4000:209.207.224.42:80
diff --git a/tools/Bounce/build b/tools/Bounce/build
new file mode 100644 (file)
index 0000000..49f6b05
--- /dev/null
@@ -0,0 +1 @@
+g++ -O3 -ggdb -Wall -Wmissing-declarations -o Bounce Bounce.cpp
diff --git a/tools/autodoc.py b/tools/autodoc.py
new file mode 100644 (file)
index 0000000..60d1813
--- /dev/null
@@ -0,0 +1,70 @@
+#
+# Structure AutoDocumentator for ircu.
+# 26/02/2000 --Gte
+#
+# Creates a 'structs.html', containing HTML Table definitions
+# for all structures encountered in *.h in the current directory.
+#
+# $Id: autodoc.py,v 1.1 2000/03/18 05:20:30 bleep Exp $
+
+import string, fnmatch, os
+
+def parse(filename):
+       OutFile = open('structs.html', 'a')
+       OutFile.write("<B><H2>"+filename+"</H2>")
+       stage = 1
+       try:
+               IncFile = open(filename, 'r')
+               line = IncFile.readline()
+       
+               while line != "": 
+                       line = string.replace(line,"\n","") # Stript out LF's.
+                       splitline = string.split(line, " ")
+                       try:
+                               if ((stage == 2) & (splitline[0] == "};")):
+                                       OutFile.write("</TABLE><P>"+"\n")
+                                       stage = 1
+                               if (stage == 2):
+                                       # Begin reading member information.
+                                       declr = string.split(string.strip(line), ";", 1)
+                                       comment = string.replace(declr[1], "*", "")
+                                       comment = string.replace(comment, "/", "")
+       
+                                       OutFile.write("<tr>\n")
+                                       OutFile.write("<td WIDTH=\"22%\">"+string.strip(declr[0])+"</td>\n")
+                                       if (declr[1][-1] == "/"):
+                                               OutFile.write("<td WIDTH=\"78%\">"+string.strip(comment)+"</td>\n")
+                                       else:
+                                               # Loop until end of comment string.
+                                               while (declr[-1] != "/"):
+                                                       line = IncFile.readline()
+                                                       line = string.replace(line,"\n","") # Stript out LF's.
+                                                       declr = string.strip(line)
+                                                       comment = comment + line
+                                               comment = string.replace(comment, "*", "")
+                                               comment = string.replace(comment, "/", "")
+                                               OutFile.write("<td WIDTH=\"78%\">"+string.strip(comment)+"</td>\n")
+                                       OutFile.write("</tr>\n")                                                
+       
+                               if ((splitline[0] == "struct") & (splitline[2] == "{") & (stage == 1)):
+                                       # We've found a "Standard" structure definition.
+                                       OutFile.write("Structure table for: \"<B>"+splitline[1]+"</B>\"<P>\n")
+                                       OutFile.write("<table BORDER CELLSPACING=0 CELLPADDING=2 WIDTH=\"100%\" ><tr><td VALIGN=TOP WIDTH=\"22%\"><b>Variable</b></td><td VALIGN=TOP WIDTH=\"78%\"><b>Description</b></td></tr>")
+                                       # Now, carry on until we encounter a "};".
+                                       stage = 2
+                       except IndexError:
+                               pass
+                       line = IncFile.readline()
+       
+               IncFile.close
+               OutFile.write("<HR>")
+       
+       except IOError:
+               print("** Error, File does not exist.") 
+       OutFile.close
+
+files = os.listdir(".")
+files.sort()
+for file in files:
+       if (fnmatch.fnmatch(file, "*.h")):
+               parse(file)
diff --git a/tools/hashtoy b/tools/hashtoy
new file mode 100644 (file)
index 0000000..13b5d56
--- /dev/null
@@ -0,0 +1,92 @@
+#!/usr/bin/perl
+#
+# hashtoy: a little script to read an ircu burst IP dump and try
+#          different hash formulae
+# usage:   hashtoy <filename> <tablesize> '<expression>'
+#          use x for the key and n for the table size
+# example: hashtoy undernet-burst.txt 8192 '((x >> 14) + (x >> 7) + x) & 8191'
+# notes:   the input file is expected to contain one encoded IP address per
+#          line. see base64toint() and inttobase64() in ircd/s_user.c for
+#          details of the encoding.
+#
+# --Liandrin
+#
+# $Id: hashtoy,v 1.2 2002/03/07 22:52:57 ghostwolf Exp $
+
+@convert2n = (
+        0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+        0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+        0,  0,  0,  0,  0,  0,  0,  0, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61,  0,  0,
+        0,  0,  0,  0,  0,  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14,
+       15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 62,  0, 63,  0,  0,  0, 26, 27, 28,
+       29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48,
+       49, 50, 51
+);
+
+sub base64toint {
+       my $i    = 0;
+       my $str  = shift;
+       my @strc = ($str =~ /(.)/g);
+
+       $i  = $convert2n[ord($strc[5])];
+       $i += $convert2n[ord($strc[4])] << 6;
+       $i += $convert2n[ord($strc[3])] << 12;
+       $i += $convert2n[ord($strc[2])] << 18;
+       $i += $convert2n[ord($strc[1])] << 24;
+       $i += $convert2n[ord($strc[0])] << 30;
+}
+
+sub ntohl {
+       my $i = shift;
+       my $j;
+
+       return (($i & 0xFF000000) >> 24) |
+           (($i & 0x00FF0000) >> 8)  |
+           (($i & 0x0000FF00) << 8)  |
+           (($i & 0x000000FF) << 24);
+}
+
+($file, $tablesize, $expression) = @ARGV;
+while ($#ARGV > -1) { shift @ARGV; }
+
+if (!defined($file) || !defined($tablesize) || !defined($expression)) {
+       print STDERR "usage: $0 filename tablesize expression\n";
+       print STDERR "sample expression: x % n\n";
+       exit 1;
+}
+
+$expression =~ s/\bx\b/\$ip/gi;
+$expression =~ s/\bn\b/\$tablesize/gi;
+$expression =~ s/^(.*)$/sub dohash { return ($1); }/;
+
+$minkey = 2**32;
+$maxkey = 0;
+
+eval $expression;
+
+open IPS, $file || die "Can't open $file at";
+
+while (<IPS>) {
+       chomp;
+       $ip = base64toint($_);
+       $key = dohash($ip);
+       $minkey = $key if ($key < $minkey);
+       $maxkey = $key if ($key > $maxkey);
+       $testing{$key}++;
+}
+
+$max      = 0;
+$min      = $tablesize + 1;
+$nEntries = 0;
+$total    = 0;
+for (values %testing) {
+       $max = $_ if ($_ > $max);
+       $min = $_ if ($_ < $min);
+       $nEntries++;
+       $total += $_;
+}
+
+print "Table size: $tablesize\n";
+printf "Min/average/max chain length: $min/%.2f/$max\n", ($total / $nEntries);
+print "Minimum key: $minkey\n";
+print "Maximum key: $maxkey\n";
diff --git a/tools/iauth-test b/tools/iauth-test
new file mode 100644 (file)
index 0000000..0e8d104
--- /dev/null
@@ -0,0 +1,237 @@
+#! /usr/bin/perl
+# iauth-test: test script for IRC authorization (iauth) protocol
+# Copyright 2006 Michael Poole
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License version 2 as
+# published by the Free Software Foundation.
+
+require 5.008; # We assume deferred signal handlers, new in 5.008.
+use strict;
+use warnings;
+use vars qw(%pending);
+
+use Config;     # for $Config{sig_name} and $Config{sig_num}
+use FileHandle; # for autoflush method on file handles
+
+# This script is intended to help test an implementation of the iauth
+# protocol by exercising every command in the protocol and by
+# exercising most distinct combinations of commands.  It assumes IPv4
+# support in the server and POSIX real-time signal support in the OS
+# (recognized and supported by Perl).
+
+# Certain behavior is triggered by receipt of real-time signals.
+# SIGRTMIN + 0 -> Send server notice ('>').
+# SIGRTMIN + 1 -> Toggle debug level ('G').
+# SIGRTMIN + 2 -> Set policy options ('O').
+# SIGRTMIN + 3 -> Simulate config change ('a', 'A').
+# SIGRTMIN + 4 -> Simulate statistics change ('s', 'S').
+
+# In the following discussion, sX means message X from the server, and
+# iX means message X from iauth.  The hard part is the ordering of
+# various events during client registration.  This includes sC, sP,
+# sU, su, sn, sN/d, sH and sT; and o/U/u, iN, iI, iC and iD/R/k/K.
+
+# sC is first, sD/sT/iD/R/k/K is last.  If sH is sent, no more sU, su,
+# sn, sN, sd or sH messages may be sent.  If iI is sent, iN should
+# also be sent (either before or after iI).  Multiple sP, sU and iC
+# messages may be sent. Otherwse, the ordering of unrelated messages
+# from either source are not constrained, but only one message from
+# each set of alternatives may be sent.
+
+# This means the sets of commands with interesting orderings are:
+# sU, su, io/U/u
+# sN/d, iN, iI
+# sH, sT or iD/R/k/K
+
+# 127.x.y.z IP addresses are used to exercise these orderings; see the
+# %handlers variable below.
+
+sub dolog ($) {
+    print LOG "$_[0]\n";
+}
+
+sub reply ($;$$) {
+    my ($msg, $client, $extra) = @_;
+
+    if (not defined $msg) {
+        # Accept this for easier handling of client reply messages.
+        return;
+    } elsif (ref $msg eq '') {
+        $msg =~ s/^(.) ?/$1 $client->{id} $client->{ip} $client->{port} / if $client;
+        dolog "< $msg";
+        print "$msg\n";
+    } elsif (ref $msg eq 'ARRAY') {
+        grep { reply($_, $client, $extra); } @$msg;
+    } elsif (ref $msg eq 'CODE') {
+        &$msg($client, $extra);
+    } else {
+        die "Unknown reply message type.";
+    }
+}
+
+# Find the names of signals with values SIGRTMIN+1, +2, etc.
+BEGIN {
+    my @sig_name;
+    my %sig_num;
+
+    sub populate_signals () {
+        die "No sigs?"
+            unless $Config{sig_name} and $Config{sig_num};
+        my @names = split ' ', $Config{sig_name};
+        @sig_num{@names} = split ' ', $Config{sig_num};
+        foreach (@names) { $sig_name[$sig_num{$_}] ||= $_; }
+    }
+
+    sub assign_signal_handlers() {
+        my $sigrtmin = $sig_num{RTMIN};
+        die "No realtime signals?"
+            unless $sigrtmin;
+        $SIG{$sig_name[$sigrtmin+0]} = \&send_server_notice;
+        $SIG{$sig_name[$sigrtmin+1]} = \&toggle_debug_level;
+        $SIG{$sig_name[$sigrtmin+2]} = \&set_policy_options;
+        $SIG{$sig_name[$sigrtmin+3]} = \&sim_config_changed;
+        $SIG{$sig_name[$sigrtmin+4]} = \&sim_stats_change;
+    }
+}
+
+BEGIN {
+    my $debug_level = 0;
+    my $max_debug_level = 2;
+
+    sub toggle_debug_level () {
+        if (++$debug_level > $max_debug_level) {
+            $debug_level = 0;
+        }
+        reply "G $debug_level";
+    }
+}
+
+BEGIN {
+    my %rotation = (
+        '' => 'AU',
+        'AU' => 'AURTW',
+        'AURTW' => '',
+    );
+    my $policy = '';
+
+    sub set_policy_options () {
+        $policy = $rotation{$policy};
+        reply "O $policy";
+    }
+}
+
+BEGIN {
+    my $generation = 0;
+
+    sub sim_config_changed () {
+        reply "a";
+        reply "A config $generation";
+        $generation++;
+    }
+}
+
+BEGIN {
+    my $generation = 0;
+
+    sub sim_stats_change () {
+        reply "s";
+        reply "S stats $generation";
+        $generation++;
+    }
+}
+
+sub send_server_notice () {
+    reply "> :Hello the server!";
+}
+
+my %handlers = (
+                # Default handliner: immediately report done.
+                'default'    => { C_reply => 'D' },
+                # 127.0.0.x: various timings for iD/iR/ik/iK.
+                '127.0.0.1'  => { C_reply => 'D' },
+                '127.0.0.2'  => { C_reply => 'R account-1' },
+                '127.0.0.3'  => { C_reply => 'k' },
+                '127.0.0.4'  => { C_reply => 'K' },
+                '127.0.0.15' => { },
+                '127.0.0.16' => { H_reply => 'D' },
+                '127.0.0.17' => { H_reply => 'R account-2' },
+                '127.0.0.18' => { H_reply => 'k' },
+                '127.0.0.19' => { H_reply => 'K' },
+                '127.0.0.32' => { T_reply => 'D' },
+                '127.0.0.33' => { T_reply => 'R account-3' },
+                '127.0.0.34' => { T_reply => 'k' },
+                '127.0.0.35' => { T_reply => 'K' },
+                # 127.0.1.x: io/iU/iu functionality.
+                '127.0.1.0'  => { C_reply => 'o forced',
+                                  H_reply => 'D' },
+                '127.0.1.1'  => { C_reply => 'U trusted',
+                                  H_reply => 'D' },
+                '127.0.1.2'  => { C_reply => 'u untrusted',
+                                  H_reply => 'D' },
+                # 127.0.2.x: iI/iN functionality.
+                '127.0.2.0'  => { C_reply => 'N iauth.assigned.host',
+                                  H_reply => 'D' },
+                '127.0.2.1'  => { C_reply => \&ip_change },
+                # 127.0.3.x: iC/sP functionality.
+                '127.0.3.0'  => { C_reply => 'C :Please enter the password.',
+                                  P_reply => \&passwd_check },
+);
+
+sub handle_new_client ($$$$) {
+    my ($id, $ip, $port, $extra) = @_;
+    my $handler = $handlers{$ip} || $handlers{default};
+    my $client = { id => $id, ip => $ip, port => $port, handler => $handler };
+
+    # If we have any deferred reply handlers, we must save the client.
+    $pending{$id} = $client if grep /^[^C]_reply$/, keys %$handler;
+    reply $client->{handler}->{C_reply}, $client, $extra;
+}
+
+sub ip_change ($$) {
+    my ($client, $extra) = @_;
+    reply 'I 127.255.255.254', $client;
+    $client->{ip} = '127.255.255.254';
+    reply 'N other.assigned.host', $client;
+    reply 'D', $client;
+}
+
+sub passwd_check ($$) {
+    my ($client, $extra) = @_;
+    if ($extra eq 'secret') {
+        reply 'D', $client;
+    } else {
+        reply 'C :Bad password', $client;
+    }
+}
+
+open LOG, ">> iauth.log";
+populate_signals();
+assign_signal_handlers();
+autoflush LOG 1;
+autoflush STDOUT 1;
+autoflush STDERR 1;
+dolog "IAuth starting " . scalar(localtime(time));
+
+while (<>) {
+    my ($id, $client);
+
+    # Chomp newline and log incoming message.
+    s/\r?\n?\r?$//;
+    dolog "> $_";
+
+    # If there's an ID at the start of the line, parse it out.
+    if (s/^(\d+) //) { $id = $1; $client = $pending{$id}; }
+
+    # Figure out how to handle the command.
+    if (/^C (\S+) (\S+) (.+)$/) {
+        handle_new_client($id, $1, $2, $3);
+    } elsif (/^([DT])/ and $client) {
+        reply $client->{handler}->{"${1}_reply"}, $client;
+        delete $pending{$id};
+    } elsif (/^([d])/ and $client) {
+        reply $client->{handler}->{"${1}_reply"}, $client;
+    } elsif (/^([HNPUu]) (.+)/ and $client) {
+        reply $client->{handler}->{"${1}_reply"}, $client, $2;
+    }
+}
diff --git a/tools/linesync/linesync.conf b/tools/linesync/linesync.conf
new file mode 100644 (file)
index 0000000..b63faca
--- /dev/null
@@ -0,0 +1,17 @@
+
+# Configuration for linesync.sh
+#
+# - This file must be placed in the same directory as ircd.conf
+# - Note that all URL's *MUST* have a trailing /
+# - Since we are using wget, you could use ftp:// URL's as well if you want to
+
+# Where do we get our ircd.conf update?
+LINE_SERVER="http://some.domain/"
+
+# Check servers, as many as you like, seperated by spaces 
+LINE_CHECK="http://host1.other.domain/lsync/ http://host-19.domain-x.net/ http://www.domain.what"
+
+# What .conf lines are allowed in the downloaded updates?
+# Pipe seperated - for Undernet use "Uworld|Jupe|Quarantine|Kill" (kKQU in .11 terms)
+ALLOWED_LINES="Uworld|Jupe|Quarantine|Kill"
+
diff --git a/tools/linesync/linesync.sh b/tools/linesync/linesync.sh
new file mode 100644 (file)
index 0000000..2358cda
--- /dev/null
@@ -0,0 +1,241 @@
+#!/bin/sh
+# linesync.sh, Copyright (c) 2002 Arjen Wolfs
+# 20020604, sengaia@undernet.org
+# 20050417, daniel@undernet.org  - modified for u2.10.12
+# $Id: linesync.sh,v 1.5 2005/04/17 16:59:49 entrope Exp $
+#
+# The code contained is in this file is licenced under the terms
+# and conditions as specified in the GNU General Public License.
+#
+# linesync.sh - centralized ircd.conf updates.
+# The purpose of this little shell script is to allow a section of an ircd.conf to be 
+# updated from a central location. Hence it is intended to facilitate the automated 
+# distribution of Kill, Jupe, Quarantine and Uworld lines; or any other .conf lines you 
+# may wish to keep synchronized accross all servers on a network.
+#
+# This script will download a file called linesync from a specified web server (see 
+# below for configuration), and calculate an md5sum from it. It will then download
+# a file called linesync.sum from a configurable number of other web servers and
+# compare the contents of these files against the checksum calculated. If any of the
+# downloaded checksums mismatch, the program will abort. This provides security to
+# the centralized update mechanism - in order for it to be compromised, multiple
+# web servers would have to compromised.
+#
+# If all checksums match, the script inspects the .conf lines contained within the 
+# downloaded file. If any .conf lines are found that are not specifically allowed,
+# the program will abort. This will prevent malicious/dangerous .conf lines (such as
+# Operator or Connect lines) from being inserted into ircd.conf.
+#
+# If all the checks mentioned above are passed, the script checks ircd.conf for a section
+# that begins with "# BEGIN LINESYNC", and ends with "# END LINESYNC". The section contained
+# between these two comments is the section maintained by this program. If these lines are not
+# found in the ircd.conf, they will be appended to it.
+# Next, the script will build a new ircd.conf by removing all lines present between the two
+# commented lines mentioned above, and replace them with the contents of the file downloaded.
+# 
+# Once this has been completed, ircd.conf is backed up and replaced with the newly built version,
+# and ircd will be rehashed. 
+#
+# Configuration: This script requires two parameters - the full path to your ircd.conf, and the
+# full path to your ircd.pid. It will look for a configuration file called linesync.conf in the
+# same directory as ircd.conf. See the included sample linesync.conf for information on how to
+# set it up. Obviously, you will need to have web server(s) to use for the distribution of your
+# .conf update and checksums. This script requires the presence of wget and md5sum, and various
+# other programs that should be present by default on any Unix system. 
+#
+# This program should be run from crontab, i.e something like:
+# 0 0 * * * /home/irc/bin/linesync.sh /home/irc/lib/ircd.conf /home/irc/lib/ircd.pid
+#
+# This program has been tested on and works on FreeBSD, Solaris, and Linux.
+# md5sum is included in GNU textutils.
+#
+#      Good Luck!
+#      Arjen Wolfs (sengaia@undernet.org), June 9 2002.
+#
+
+# This checks for the presence of an executable file in $PATH
+locate_program() {
+        if [ ! -x "`which $1 2>&1`" ]; then
+                echo "You don't seem to have $1. Sorry."
+                exit 1
+        fi
+}
+
+# This checks for the presence of any file
+check_file() {
+        if [ ! -f "$1" ]; then
+                echo "There doesn't appear to be a $1. Sorry."
+                exit 1
+        fi
+}
+
+# Try to find programs we will need
+locate_program wget && locate_program egrep && locate_program diff
+
+# try to find GNU awk
+awk_cmd=`which gawk`
+if [ $? -ne 0 ]; then
+        awk_cmd=""
+fi
+
+# try to find an appropriate md5 program
+# BSD md5 capability courtesy of spale
+md5_cmd=`which md5sum`
+if [ -z "$md5_cmd" ]; then
+       md5_cmd=`which md5`
+       if [ -z "$md5_cmd" ]; then
+               echo "No MD5 capable programs found (I looked for md5sum and md5)."
+               exit
+       else
+               md5_cmd="$md5_cmd -q"
+       fi
+fi
+
+if [ -z "$awk_cmd" ]; then
+       locate_program awk
+       is_gawk=`echo | awk --version | head -1 | egrep '^GNU.+$'`
+       if [ -z "$is_gawk" ]; then
+               echo "Your version of awk is not GNU awk. Sorry."
+               exit 1
+       fi
+       awk_cmd="awk"   
+fi
+
+# Check for required command line parameters
+if [ -z "$1" -o -z "$2" ]; then
+        echo "Usage: $0 <conf_path> <pid_path>"
+        echo "      <conf_path>     Full path to ircd.conf (/home/irc/lib/ircd.conf)"
+        echo "      <pid_path>      Full path to ircd.pid (/home/irc/lib/ircd.pid)"
+        exit 1
+fi
+
+# check and set up stuff
+diff_cmd="diff"
+cpath=$1
+ppath=$2
+check_file $cpath
+dpath=`dirname $cpath`
+lpath="$dpath/linesync.conf"
+check_file $lpath
+save_dir=$PWD; cd $dpath
+tpath=$PWD; cd $save_dir
+tmp_path="$dpath/tmp"
+mkdir $tmp_path > /dev/null 2>&1
+
+# load and check configuration
+. $lpath
+if [ -z "$LINE_SERVER" -o -z "$LINE_CHECK" -o -z "$ALLOWED_LINES" ]; then
+       echo "Please setup $lpath correctly."
+       exit 1
+fi
+
+# Not all versions of date support %s, work around it
+TS=`date +%Y%m%d%H%M%S`
+TMPFILE="$tmp_path/linesync.$TS"
+LSFILE="$LINE_SERVER""linesync"
+# Attempt to download our .conf update
+wget --cache=off --quiet --output-document=$TMPFILE $LSFILE > /dev/null 2>&1
+if [ ! -s "$TMPFILE" ]; then
+        echo "Unable to retrieve $LSFILE. Sorry."
+       rm $TMPFILE > /dev/null 2>&1
+        exit 1
+fi
+
+# Check whether the file contains any disallowed .conf lines
+bad_lines=`egrep '^[^'$ALLOWED_LINES'|#]+' $TMPFILE`
+if [ ! -z "$bad_lines" ]; then
+        echo "The file downloaded in $TMPFILE contains the following disallowed line(s):"
+        echo $bad_lines
+        exit 1
+fi
+
+# Check whether somebody tried to sneak a second block onto some line
+bad_lines=`egrep -i '}[        ]*;[    ]*[a-z]+[       ]*{' $TMPFILE`
+if [ ! -z "$bad_lines" ] ; then
+       echo "The file downloaded in $TMPFILE contains the following multi-block line(s):"
+        echo $bad_lines
+        exit 1
+fi
+
+# check our ircd.conf
+ircd_setup=`egrep '^# (BEGIN|END) LINESYNC$' $cpath|wc -l`
+if [ $ircd_setup != 2 ]; then
+       cp $cpath $cpath.orig
+       echo "Performing initial merge on $cpath, original file saved as $cpath.orig."
+       
+        echo "# Do NOT remove the following line, linesync.sh depends on it!" >> $cpath
+        echo "# BEGIN LINESYNC" >> $cpath
+        echo "# END LINESYNC" >> $cpath
+        echo "# Do not remove the previous line, linesync.sh depends on it!" >> $cpath
+
+       # Do an initial merge to remove duplicates
+       inpath="$tmp_path/linesync.tmp.$TS"
+       $awk_cmd '
+       {
+                if (!loaded_template) {
+                        command="cat " tempfile; tlines=0;
+                        while ((command | getline avar) > 0) { template[tlines]=avar; tlines++ }
+                        close(command)
+                        loaded_template++
+                }
+               dup_line=0
+                for (i=0; i<tlines; i++) {
+                        if (tolower($0)==tolower(template[i])) { dup_line++; break }
+                }
+               if (!dup_line) print $0
+        } ' tempfile=$TMPFILE < $cpath > $inpath
+else
+       inpath=$cpath
+fi
+
+# Get the checksum
+CKSUM=`$md5_cmd $TMPFILE|cut -d' ' -f1`
+
+check_file="$tmp_path/linesync.sum.$TS"
+for ck_server in $LINE_CHECK; do
+       sumfile="$ck_server""linesync.sum"
+       wget --cache=off --quiet --output-document=$check_file $sumfile > /dev/null 2>&1
+       if [ ! -s "$check_file" ]; then
+               echo "Unable to retrieve checksum from $sumfile"
+               exit 1  
+       fi
+       if [ "$CKSUM" != "`cat $check_file`" ]; then
+               echo "Checksum retrieved from $sumfile does not match!"
+               exit 1
+       fi
+       rm -f $check_file
+done
+# It all checks out, proceed...
+
+# Replace the marked block in ircd.conf with the new version
+
+$awk_cmd ' 
+$0=="# BEGIN LINESYNC" { chop++; print; next }
+$0=="# END LINESYNC" {
+        command="cat " syncfile
+        while ((command | getline avar) > 0) { print avar }
+        close(command)
+        chop--
+}
+{ if (!chop) print $0 }
+' syncfile=$TMPFILE < $inpath > $tmp_path/linesync.new.$TS
+
+# run a diff between current and new confs to see if we updated anything
+# no point sending the ircd a -HUP if this is not needed, especially on a
+# busy network, such as Undernet.
+diff=`$diff_cmd $cpath $tmp_path/linesync.new.$TS`
+if [ ! -z "$diff" ]; then
+       # Changes were detected
+
+       # Back up the current ircd.conf and replace it with the new one
+       cp $cpath  $dpath/ircd.conf.bk
+       cp $tmp_path/linesync.new.$TS $cpath
+
+       # Rehash ircd (without caring wether or not it succeeds)
+       kill -HUP `cat $ppath 2>/dev/null` > /dev/null 2>&1
+fi
+
+# (Try to) clean up
+rm -rf $tmp_path > /dev/null 2>&1
+
+# That's it...
diff --git a/tools/mkchroot b/tools/mkchroot
new file mode 100644 (file)
index 0000000..bae523d
--- /dev/null
@@ -0,0 +1,99 @@
+#!/bin/sh
+#
+# IRC - Internet Relay Chat, tools/mkchroot
+# Copyright (C) 2001 Kevin L. Mitchell <klmitch@mit.edu>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 1, or (at your option)
+# any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+# $Id: mkchroot,v 1.1 2001/06/21 15:48:16 kev Exp $
+
+if test $# -lt 2; then
+    echo "Usage: $0 <destdir> <executable> [<executable> [...]]" >&2
+    exit 2
+fi
+
+destdir=$1
+shift
+
+# Use ldd to formulate a newline-separated list of libraries
+liblist=
+for arg
+do
+    # Interpret ldd output
+    libs=`ldd $arg | sed -e 's/        / /g' -e 's/  */ /g' -e 's/^ //g' | \
+       awk 'BEGIN { RS = " "; } { print; }' | grep '^/'`
+
+    # add it to the list so far
+    if test x"$liblist" = x; then
+       liblist=$libs
+    else
+       liblist="$liblist
+$libs"
+    fi
+done
+# Sort the list and remove duplicates
+liblist=`echo "$liblist" | sort -u`
+
+# Now figure out all the subdirectories we're interested in
+# Must create the top level, if need be
+dirlist=/
+# Break down the library list into directories and remove duplicates
+dirs=`echo "$liblist" | sed -e 's@/[^/]*$@@' | sort -u`
+# Go through each directory to break it down into its components
+for headdir in $dirs; do
+    tIFS=$IFS
+    IFS=/$IFS
+    # Start at the top level
+    dir=
+    for subdir in $headdir; do
+       # update dir so we know where we are
+       if test x"$dir" = x; then
+           dir=$subdir
+       else
+           dir=$dir/$subdir
+       fi
+
+       # add (absolute) entry to directory list
+       dirlist="$dirlist
+/$dir"
+    done
+    IFS=$tIFS
+done
+# Sort for ordering and remove duplicates
+dirlist=`echo "$dirlist" | sort -u`
+
+# Create the directories
+echo "Creating directories:"
+for dir in $dirlist; do
+    # add destination directory name, remove trailing /, if any, for test
+    dir=`echo "$destdir$dir" | sed -e 's@//*$@@'`
+    echo "  $dir"
+    # sanity-check directory...
+    if test -f "$dir" -o -h "$dir"; then
+       echo "ERROR: A non-directory \"$dir\" already exists; bailing out" >&2
+       exit 2
+    elif test ! -d "$dir"; then
+       # Create the directory world-readable
+       mkdir -m 755 $dir
+    fi
+done
+
+# Now copy over the libraries
+echo "Copying libraries:"
+for lib in $liblist; do
+    echo "  $lib -> $destdir$lib"
+    # Preserve permissions
+    cp -p $lib $destdir$lib
+done
diff --git a/tools/ringlog.c b/tools/ringlog.c
new file mode 100644 (file)
index 0000000..ab80101
--- /dev/null
@@ -0,0 +1,341 @@
+/*
+** Copyright (C) 2002 by Kevin L. Mitchell <klmitch@mit.edu>
+**
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program; if not, write to the Free Software
+** Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+**
+** @(#)$Id: ringlog.c,v 1.4 2004/07/01 12:38:28 entrope Exp $
+*/
+/*
+ * This file contains two separate pieces, along with some common
+ * gunk.  If RINGLOG_INSTRUMENT is defined, the two special functions
+ * __cyg_profile_func_enter() and __cyg_profile_func_exit() are
+ * defined; otherwise a main function is defined.  The common gunk is
+ * init_log(), which opens and, if necessary, initializes a special
+ * binary log file that is treated as a ring buffer (to prevent the
+ * file from growing unboundedly).
+ *
+ * The object produced when compiled with RINGLOG_INSTRUMENT is
+ * designed to work with the special gcc option
+ * -finstrument-functions; this option causes the
+ * __cyg_profile_func_*() functions mentioned above to be called when
+ * a function is entered or exited.  (Of course, ringlog.o should
+ * *not* be compiled with this option.)  These functions will in turn
+ * call store_entry(), which will call init_log() as needed to open
+ * the log file, ensure that a start record is output, and then will
+ * store records for the function calls.  The log file used is
+ * "call.ringlog" in the directory from which the program was
+ * started.
+ *
+ * When RINGLOG_INSTRUMENT is *not* defined while building, a main
+ * function is defined, and the result is an executable for
+ * interpretation of a ringlog.  Usage is very simple:  All arguments
+ * not beginning with '-' are treated as files to open, and all
+ * arguments beginning with '-' are treated as a specification for the
+ * number of entries new files should be created with.  If this
+ * specification is 0 (which it is by default), files will not be
+ * created if they do not already exist.
+ *
+ * For every filename argument, at least one line will be printed
+ * out.  If the file is not empty, the entries in the file will be
+ * printed out, one to a line.  Each entry is numbered with a logical
+ * number.  The entry numbers are followed by a two word description
+ * of the entry type ("Log start," "Function entry," "Function exit,"
+ * and "Invalid entry"), followed by a colon (":"), followed by the
+ * word "addr" and the address of the function, followed by the word
+ * "call" and the address from which the function was called.  The
+ * ringlog program is not able to convert these addresses to symbols
+ * or file and line numbers--that can be done with a program like
+ * addr2line (part of the binutils package).  The output has been
+ * carefully contrived to be parsable by a script.
+ *
+ * The file format is documented below.  Note that data is stored in
+ * host byte order.
+ *
+ *                      1                   2                   3
+ *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |                         Magic number                          |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |          First entry          |          Last entry           |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |                            Records                            |
+ * \                                                               \
+ * \                                                               \
+ * |                            Records                            |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *
+ * Record format:
+ *                      1                   2                   3
+ *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |                           Type code                           |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |                       Function address                        |
+ * /                                                               /
+ * /                                                               /
+ * |                       Function address                        |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |                       Calling location                        |
+ * /                                                               /
+ * /                                                               /
+ * |                       Calling location                        |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *
+ * Some systems may have pointers larger than 32 bits, which is why these
+ * fields are allowed to be variable width.
+ */
+#include <assert.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+/* /etc/magic rules:
+ *
+ * 0   belong  0x52e45fd4      RingLog call trace file, big endian
+ * >4  beshort x               (First entry %u,
+ * >>6 beshort x               last entry %u)
+ * 0   lelong  0x52e45fd4      RingLog call trace file, little endian
+ * >4  leshort x               (First entry %u,
+ * >>6 leshort x               last entry %u)
+ */
+#define RINGLOG_MAGIC 0x52e45fd4       /* verify file format */
+
+#define RINGLOG_INIT  0x00000000       /* mark when a session was initiated */
+#define RINGLOG_ENTER 0x01010101       /* record function entry */
+#define RINGLOG_EXIT  0x02020202       /* record function exit */
+
+#define RINGLOG_FNAME "call.ringlog"   /* default file name */
+#define RINGLOG_ILEN  2000             /* default number of entries */
+
+/* length of the header and of individual entries */
+#define HEAD_LEN      (sizeof(u_int32_t) + 2 * sizeof(u_int16_t))
+#define ENTRY_LEN     (sizeof(u_int32_t) + 2 * sizeof(void *))
+
+/* return an lvalue to the specified type stored at the specified location */
+#define rl_ref(log, loc, type) (*((type *)((log) + (loc))))
+
+/* access particular header fields */
+#define rl_magic(log) rl_ref((log), 0, u_int32_t)
+#define rl_first(log) rl_ref((log), 4, u_int16_t)
+#define rl_last(log)  rl_ref((log), 6, u_int16_t)
+
+/* translate physical entry number to a file location */
+#define rl_addr(loc)  ((loc) * ENTRY_LEN + HEAD_LEN)
+
+/* extract the type, function, and call fields of an entry */
+#define rl_type(log, loc) rl_ref((log), rl_addr(loc), u_int32_t)
+#define rl_func(log, loc) rl_ref((log), rl_addr(loc) + sizeof(u_int32_t), \
+                                void *)
+#define rl_call(log, loc) rl_ref((log), rl_addr(loc) + sizeof(u_int32_t) + \
+                                sizeof(void *), void *)
+
+static char *log = 0; /* the log has to be global data */
+static size_t log_size = 0; /* remember the size of the log */
+static int log_length = 0; /* remember how many entries it'll hold */
+
+/* Open and initialize the log file */
+static int
+init_log(char *fname, size_t init_len)
+{
+  char c = 0;
+  int fd, err = 0, size = -1;
+  struct stat buf;
+
+  /* open file */
+  if ((fd = open(fname, O_RDWR | (init_len > 0 ? O_CREAT : 0),
+                S_IRUSR | S_IWUSR)) < 0)
+    return errno; /* return error */
+
+  if (fstat(fd, &buf)) { /* get size */
+    err = errno; /* save errno... */
+    close(fd); /* close file descriptor */
+    return err; /* return error */
+  }
+
+  if (buf.st_size <= 8) /* too small */
+    size = HEAD_LEN + ENTRY_LEN * init_len;
+  else if ((buf.st_size - 8) % ENTRY_LEN) /* not a multiple of entry length */
+    size = ((buf.st_size - 8) / ENTRY_LEN + 1) * ENTRY_LEN + 8; /* round up */
+
+  if (size >= 0) { /* need to set the size */
+    if (lseek(fd, size - 1, SEEK_SET) < 0) { /* seek to the end of our file */
+      err = errno; /* save errno... */
+      close(fd); /* close file descriptor */
+      return err; /* return error */
+    }
+
+    if (write(fd, &c, 1) < 0) { /* write a zero to set the new size */
+      err = errno; /* save errno... */
+      close(fd); /* close file descriptor */
+      return err; /* return error */
+    }
+
+    log_size = size; /* record log size */
+  } else
+    log_size = buf.st_size; /* record log size */
+
+  /* map the file to memory */
+  if ((log = (char *)mmap(0, log_size, PROT_READ | PROT_WRITE,
+                         MAP_SHARED, fd, 0)) == MAP_FAILED)
+    err = errno; /* save errno... */
+
+  close(fd); /* don't need the file descriptor anymore */
+
+  if (err) /* an error occurred while mapping the file; return it */
+    return err;
+
+  log_length = (log_size - HEAD_LEN) / ENTRY_LEN; /* store number of entries */
+
+  if (rl_magic(log) == 0) { /* initialize if necessary */
+    rl_magic(log) = RINGLOG_MAGIC;
+    rl_first(log) = -1;
+    rl_last(log) = -1;
+  }
+
+  if (rl_magic(log) != RINGLOG_MAGIC) { /* verify file format */
+    munmap(log, log_size); /* unmap file */
+    return -1; /* -1 indicates file format error */
+  }
+
+  return 0; /* return success */
+}
+
+#ifdef RINGLOG_INSTRUMENT
+
+/* store an entry in the log file */
+static void
+store_entry(u_int32_t type, void *this_fn, void *call_site)
+{
+  if (!log) { /* open the log file if necessary; die if unable */
+    assert(init_log(RINGLOG_FNAME, RINGLOG_ILEN) == 0);
+    store_entry(RINGLOG_INIT, 0, 0); /* mark start of logging */
+  }
+
+  if (++(rl_last(log)) >= log_length) /* select next entry to fill */
+    rl_last(log) = 0; /* wrap if needed */
+
+  if (rl_first(log) == rl_last(log)) { /* advance start pointer if collision */
+    if (++(rl_first(log)) >= log_length) /* wrap if necessary */
+      rl_first(log) = 0;
+  } else if (rl_first(log) == (u_int16_t)-1) /* no entries yet; enter one */
+    rl_first(log) = 0;
+
+  rl_type(log, rl_last(log)) = type; /* record the entry */
+  rl_func(log, rl_last(log)) = this_fn;
+  rl_call(log, rl_last(log)) = call_site;
+}
+
+/* called upon function entry */
+void
+__cyg_profile_func_enter(void *this_fn, void *call_site)
+{
+  store_entry(RINGLOG_ENTER, this_fn, call_site);
+}
+
+/* called upon function exit */
+void
+__cyg_profile_func_exit(void *this_fn, void *call_site)
+{
+  store_entry(RINGLOG_EXIT, this_fn, call_site);
+}
+
+#else /* !defined(RINGLOG_INSTRUMENT) */
+
+/* converts a type to a printable string */
+static char *
+get_type(u_int32_t type)
+{
+  switch (type) {
+  case RINGLOG_INIT:
+    return " Logging start";
+    break;
+  case RINGLOG_ENTER:
+    return "Function entry";
+    break;
+  case RINGLOG_EXIT:
+    return " Function exit";
+    break;
+  }
+
+  return " Invalid entry";
+}
+
+/* Print out entries from a starting point to an end point */
+static void
+extract(int *count, u_int16_t start, u_int16_t end)
+{
+  for (; start <= end; start++)
+    printf("% 4d %s: addr %p call %p\n", (*count)++,
+          get_type(rl_type(log, start)), rl_func(log, start),
+          rl_call(log, start));
+}
+
+int
+main(int argc, char **argv)
+{
+  char *arg;
+  int i, err, size = 0;
+
+  while ((arg = *++argv)) {
+    if (arg[0] == '-') { /* -<number> turns into log file size */
+      size = atoi(arg + 1);
+      continue;
+    }
+
+    log = 0; /* initialize our data */
+    log_size = 0;
+    log_length = 0;
+
+    switch ((err = init_log(arg, size))) { /* initialize the log */
+    case -1: /* file is in an invalid format */
+      printf("File %s not a valid ringlog file\n", arg);
+      continue;
+      break;
+
+    case 0: /* file has opened and is ready to be read */
+      break;
+
+    default: /* some error occurred */
+      printf("Error %d opening file %s: %s\n", err, arg, strerror(err));
+      continue;
+      break;
+    }
+
+    if (rl_first(log) == (u_int16_t)-1) /* it's an empty file */
+      printf("File %s is empty\n", arg);
+    else { /* print out file contents */
+      printf("File %s contents:\n", arg);
+
+      i = 0; /* initialize counter */
+      if (rl_last(log) <= rl_first(log)) { /* print out log file */
+       extract(&i, rl_first(log), log_length - 1); /* end of buffer... */
+       extract(&i, 0, rl_last(log)); /* then beginning of buffer */
+      } else
+       extract(&i, rl_first(log), rl_last(log));
+    }
+
+    munmap(log, log_size); /* unmap the file */
+  }
+
+  return 0;
+}
+
+#endif /* !RINGLOG_INSTRUMENT */
diff --git a/tools/ringlog.pl b/tools/ringlog.pl
new file mode 100644 (file)
index 0000000..1164e64
--- /dev/null
@@ -0,0 +1,187 @@
+#! /usr/bin/perl -w
+#
+# Copyright (C) 2002 by Kevin L. Mitchell <klmitch@mit.edu>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+#
+# @(#)$Id: ringlog.pl,v 1.4 2004/07/01 12:38:28 entrope Exp $
+#
+# This program is intended to be used in conjunction with ringlog and
+# the binutils program addr2line.  The -r option specifies the path to
+# the ringlog program; the -a option specifies the path to addr2line.
+# (Both of these default to assuming that the programs are in your
+# PATH.)  All other options are passed to addr2line, and any other
+# arguments are treated as filenames to pass to ringlog.  If no
+# filenames are given, the program operates in filter mode, expecting
+# to get output from ringlog on its standard input.  In this case,
+# ringlog will not be directly executed, but addr2line still will.
+
+use strict;
+
+use Socket;
+use IO::Handle;
+
+sub start_addr2line {
+    my ($location, @args) = @_;
+
+    unshift(@args, '-f'); # always get functions
+
+    # Get a socket pair
+    socketpair(CHILD, PARENT, AF_UNIX, SOCK_STREAM, PF_UNSPEC)
+       or die "socketpair: $!";
+
+    CHILD->autoflush(1); # Make sure autoflush is turned on
+    PARENT->autoflush(1);
+
+    my $pid;
+
+    # Fork...
+    die "cannot fork: $!"
+       unless (defined($pid = fork));
+
+    if (!$pid) { # in child
+       close(CHILD);
+       open(STDIN, "<&PARENT");
+       open(STDOUT, ">&PARENT");
+       exec($location, @args); # exec!
+    }
+
+    # in parent
+    close(PARENT);
+
+    return \*CHILD; # Return a filehandle for it
+}
+
+sub xlate_addr {
+    my ($fh, $addr) = @_;
+
+    # Feed address into addr2line
+    print $fh "$addr\n";
+
+    # Get function name, file name, and line number
+    my $function = <$fh> || die "Couldn't get function name";
+    my $fileline = <$fh> || die "Couldn't get file name or line number";
+
+    # Remove newlines...
+    chomp($function, $fileline);
+
+    # If addr2line couldn't translate the address, just return it
+    return "[$addr]"
+       if ($function eq "??");
+
+    # return function(file:line)[address]
+    return "$function($fileline)[$addr]";
+}
+
+sub start_ringlog {
+    my ($location, @args) = @_;
+
+    # Build a pipe and fork, through the magic of open()
+    my $pid = open(RINGLOG, "-|");
+
+    # Make sure we forked!
+    die "couldn't fork: $!"
+       unless (defined($pid));
+
+    # Execute ringlog...
+    exec($location, @args)
+       unless ($pid);
+
+    return \*RINGLOG;
+}
+
+sub parse_ringlog {
+    my ($ringlog, $addr) = @_;
+    my $state = "reading";
+
+    while (<$ringlog>) {
+       chomp;
+
+       # Beginning of parsable data
+       if (/^File.*contents:$/) {
+           $state = "parsing";
+
+           # Here's actual parsable data, so parse it
+       } elsif ($state eq "parsing" && /^\s*\d+/) {
+           s/(0x[a-fA-F0-9]+)/&xlate_addr($addr, $1)/eg;
+
+           # Switch out of parsing mode
+       } else {
+           $state = "reading";
+       }
+
+       # Print the final result
+       print "$_\n";
+    }
+}
+
+# get an argument for an option that requires one
+sub getarg (\$) {
+    my ($iref) = @_;
+
+    $ARGV[$$iref] =~ /^(-.)(.*)/;
+
+    die "Argument for $1 missing"
+       unless ((defined($2) && $2 ne "") || @ARGV > $$iref + 1);
+
+    return defined($2) && $2 ne "" ? $2 : $ARGV[++$$iref];
+}
+
+my ($ringlog_exe, $addr2line_exe) = ("ringlog", "addr2line");
+my (@addr2line_args, @files);
+
+# Deal with arguments; note that we have to deal with -b and -e for
+# addr2line.
+for (my $i = 0; $i < @ARGV; $i++) {
+    if ($ARGV[$i] =~ /^-r/) {
+       $ringlog_exe = getarg($i);
+    } elsif ($ARGV[$i] =~ /^-a/) {
+       $addr2line_exe = getarg($i);
+    } elsif ($ARGV[$i] =~ /^-([be])/) {
+       push(@addr2line_args, "-$1", getarg($i));
+    } elsif ($ARGV[$i] =~ /^-/) {
+       push(@addr2line_args, $ARGV[$i]);
+    } else {
+       push(@files, [ $ARGV[$i], @addr2line_args ]);
+       @addr2line_args = ();
+    }
+}
+
+# Verify that that left us with executable names, at least
+die "No ringlog executable"
+    unless (defined($ringlog_exe) && $ringlog_exe ne "");
+die "No addr2line executable"
+    unless (defined($addr2line_exe) && $addr2line_exe ne "");
+
+# Ok, process each file we've been asked to process
+foreach my $file (@files) {
+    my ($addr2line, $ringlog) =
+       (start_addr2line($addr2line_exe, @{$file}[1..$#{$file}]),
+        start_ringlog($ringlog_exe, $file->[0]));
+
+    parse_ringlog($ringlog, $addr2line);
+
+    close($addr2line);
+    close($ringlog);
+}
+
+# Now if there are still more unprocessed arguments, expect ringlog
+# input on stdin...
+if (@addr2line_args) {
+    my $addr2line = start_addr2line($addr2line_exe, @addr2line_args);
+
+    parse_ringlog(\*STDIN, $addr2line);
+    close($addr2line);
+}
diff --git a/tools/untabify b/tools/untabify
new file mode 100644 (file)
index 0000000..5af6668
--- /dev/null
@@ -0,0 +1,10 @@
+#!/usr/bin/perl
+#
+# untabify - convert tabs to spaces
+#
+# $Id: untabify,v 1.2 2002/03/07 22:52:57 ghostwolf Exp $
+
+use Text::Tabs;
+$tabstop = 8;
+while (<>) { print expand($_) }
+
diff --git a/tools/wrapper.c b/tools/wrapper.c
new file mode 100644 (file)
index 0000000..94d52ae
--- /dev/null
@@ -0,0 +1,220 @@
+/*
+** Copyright (C) 2000 by Kevin L. Mitchell <klmitch@mit.edu>
+**
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program; if not, write to the Free Software
+** Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+**
+** @(#)$Id: wrapper.c,v 1.3 2004/05/15 14:50:09 entrope Exp $
+*/
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <pwd.h>
+#include <grp.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/resource.h>
+#include <unistd.h>
+
+/*
+ * Try and find the correct name to use with getrlimit() for setting the max.
+ * number of files allowed to be open by this process.
+ *
+ * Shamelessly stolen from ircu...
+ */
+#ifdef RLIMIT_FDMAX
+#define RLIMIT_FD_MAX RLIMIT_FDMAX
+#else
+#ifdef RLIMIT_NOFILE
+#define RLIMIT_FD_MAX RLIMIT_NOFILE
+#else
+#ifdef RLIMIT_OPEN_MAX
+#define RLIMIT_FD_MAX RLIMIT_OPEN_MAX
+#else
+#error Unable to find a valid RLIMIT_FD_MAX
+#endif
+#endif
+#endif
+
+/*fix for change uid/gid with chroot #ubra 08/02/03*/
+int uid, gid;
+
+/*
+ * Set the hard and soft limits for maximum file descriptors.
+ */
+int
+set_fdlimit(unsigned int max_descriptors)
+{
+  struct rlimit limit;
+
+  limit.rlim_max = limit.rlim_cur = max_descriptors;
+
+  return setrlimit(RLIMIT_FD_MAX, &limit);
+}
+
+/*
+ * Change directories to the indicated root directory, then make it the
+ * root directory.
+ */
+int
+change_root(char *root)
+{
+  if (chdir(root))
+    return -1;
+  if (chroot(root))
+    return -1;
+
+  return 0;
+}
+
+/*
+ * Change the user and group ids--including supplementary groups!--as
+ * appropriate.
+ *
+ * fix for change uid/gid with chroot #ubra 08/02/03
+ * old change_user() got splited into get_user() and set_user()
+ */
+int
+get_user(char *user, char *group)
+{
+  struct passwd *pwd;
+  struct group *grp;
+  char *tmp;
+
+  /* Track down a struct passwd describing the desired user */
+  uid = strtol(user, &tmp, 10); /* was the user given as a number? */
+  if (*tmp) { /* strtol() failed to parse; look up as a user name */
+    if (!(pwd = getpwnam(user)))
+      return -1;
+  } else if (!(pwd = getpwuid(uid))) /* look up uid */
+      return -1;
+
+  uid = pwd->pw_uid; /* uid to change to */
+  gid = pwd->pw_gid; /* default gid for user */
+
+  if (group) { /* a group was specified; track down struct group */
+    gid = strtol(group, &tmp, 10); /* was the group given as a number? */
+    if (*tmp) { /* strtol() failed to parse; look up as a group name */
+      if (!(grp = getgrnam(group)))
+       return -1;
+    } else if (!(grp = getgrgid(gid))) /* look up gid */
+      return -1;
+
+    gid = grp->gr_gid; /* set the gid */
+  }
+
+  if (initgroups(pwd->pw_name, gid)) /* initialize supplementary groups */
+    return -1;
+  return 0; /* success! */
+}
+
+int
+set_user(void) {
+  if (setgid(gid)) /* change our current group */
+    return -1;
+  if (setuid(uid)) /* change our current user */
+    return -1;
+
+  return 0; /* success! */
+}
+
+/*
+ * Explain how to use this program.
+ */
+void
+usage(char *prog, int retval)
+{
+  fprintf(stderr, "Usage: %s [-u <user>] [-g <group>] [-l <limit>] [-c <root>]"
+         " -- \\\n\t\t<cmd> [<cmdargs>]\n", prog);
+  fprintf(stderr, "       %s -h\n", prog);
+
+  exit(retval);
+}
+
+int
+main(int argc, char **argv)
+{
+  int c, limit = -1;
+  char *prog, *user = 0, *group = 0, *root = 0;
+
+  /* determine program name for error reporting */
+  if ((prog = strrchr(argv[0], '/')))
+    prog++;
+  else
+    prog = argv[0];
+
+  /* process command line arguments */
+  while ((c = getopt(argc, argv, "hu:g:l:c:")) > 0)
+    switch (c) {
+    case 'h': /* requested help */
+      usage(prog, 0);
+      break;
+
+    case 'u': /* suggested a user */
+      user = optarg;
+      break;
+
+    case 'g': /* suggested a group */
+      group = optarg;
+      break;
+
+    case 'l': /* file descriptor limit */
+      limit = strtol(optarg, 0, 10);
+      break;
+
+    case 'c': /* select a root directory */
+      root = optarg;
+      break;
+
+    default: /* unknown command line argument */
+      usage(prog, 1);
+      break;
+    }
+
+  /* Not enough arguments; we must have a command to execute! */
+  if (optind >= argc)
+    usage(prog, 1);
+
+  if (limit > 0) /* set the requested fd limit */
+    if (set_fdlimit(limit) < 0) {
+      perror(prog);
+      return 1;
+    }
+
+  if(user) /* get the selected user account uid/gid*/
+   if (get_user(user, group)) {
+     perror(prog);
+     return 1;
+   }
+
+
+  if (root) /* change root directories */
+    if (change_root(root)) {
+      perror(prog);
+      return 1;
+    }
+
+  if (user) /* change to selected user account */
+    if (set_user()) {
+      perror(prog);
+      return 1;
+    }
+
+  /* execute the requested command */
+  execvp(argv[optind], argv + optind);
+
+  /* If we got here, execvp() failed; report the error */
+  perror(prog);
+  return 1;
+}